MixedRealityShaderGUI.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. // Copyright (c) Microsoft Corporation. All rights reserved.
  2. // Licensed under the MIT License.
  3. using System;
  4. using UnityEditor;
  5. using UnityEngine;
  6. using UnityEngine.Rendering;
  7. using Object = UnityEngine.Object;
  8. namespace Microsoft.MixedReality.Toolkit.Editor
  9. {
  10. /// <summary>
  11. /// A custom base shader inspector for Mixed Reality Toolkit shaders.
  12. /// </summary>
  13. public abstract class MixedRealityShaderGUI : ShaderGUI
  14. {
  15. protected enum RenderingMode
  16. {
  17. Opaque,
  18. TransparentCutout,
  19. Transparent,
  20. PremultipliedTransparent,
  21. Additive,
  22. Custom
  23. }
  24. protected enum CustomRenderingMode
  25. {
  26. Opaque,
  27. TransparentCutout,
  28. Transparent
  29. }
  30. protected enum DepthWrite
  31. {
  32. Off,
  33. On
  34. }
  35. protected static class BaseStyles
  36. {
  37. public static string renderingOptionsTitle = "Rendering Options";
  38. public static string advancedOptionsTitle = "Advanced Options";
  39. public static string renderTypeName = "RenderType";
  40. public static string renderingModeName = "_Mode";
  41. public static string customRenderingModeName = "_CustomMode";
  42. public static string sourceBlendName = "_SrcBlend";
  43. public static string destinationBlendName = "_DstBlend";
  44. public static string blendOperationName = "_BlendOp";
  45. public static string depthTestName = "_ZTest";
  46. public static string depthWriteName = "_ZWrite";
  47. public static string depthOffsetFactorName = "_ZOffsetFactor";
  48. public static string depthOffsetUnitsName = "_ZOffsetUnits";
  49. public static string colorWriteMaskName = "_ColorWriteMask";
  50. public static string cullModeName = "_CullMode";
  51. public static string renderQueueOverrideName = "_RenderQueueOverride";
  52. public static string alphaTestOnName = "_ALPHATEST_ON";
  53. public static string alphaBlendOnName = "_ALPHABLEND_ON";
  54. public static readonly string[] renderingModeNames = Enum.GetNames(typeof(RenderingMode));
  55. public static readonly string[] customRenderingModeNames = Enum.GetNames(typeof(CustomRenderingMode));
  56. public static readonly string[] depthWriteNames = Enum.GetNames(typeof(DepthWrite));
  57. public static GUIContent sourceBlend = new GUIContent("Source Blend", "Blend Mode of Newly Calculated Color");
  58. public static GUIContent destinationBlend = new GUIContent("Destination Blend", "Blend Mode of Existing Color");
  59. public static GUIContent blendOperation = new GUIContent("Blend Operation", "Operation for Blending New Color With Existing Color");
  60. public static GUIContent depthTest = new GUIContent("Depth Test", "How Should Depth Testing Be Performed.");
  61. public static GUIContent depthWrite = new GUIContent("Depth Write", "Controls Whether Pixels From This Material Are Written to the Depth Buffer");
  62. public static GUIContent depthOffsetFactor = new GUIContent("Depth Offset Factor", "Scales the Maximum Z Slope, with Respect to X or Y of the Polygon");
  63. public static GUIContent depthOffsetUnits = new GUIContent("Depth Offset Units", "Scales the Minimum Resolvable Depth Buffer Value");
  64. public static GUIContent colorWriteMask = new GUIContent("Color Write Mask", "Color Channel Writing Mask");
  65. public static GUIContent cullMode = new GUIContent("Cull Mode", "Triangle Culling Mode");
  66. public static GUIContent renderQueueOverride = new GUIContent("Render Queue Override", "Manually Override the Render Queue");
  67. }
  68. protected bool initialized;
  69. protected MaterialProperty renderingMode;
  70. protected MaterialProperty customRenderingMode;
  71. protected MaterialProperty sourceBlend;
  72. protected MaterialProperty destinationBlend;
  73. protected MaterialProperty blendOperation;
  74. protected MaterialProperty depthTest;
  75. protected MaterialProperty depthWrite;
  76. protected MaterialProperty depthOffsetFactor;
  77. protected MaterialProperty depthOffsetUnits;
  78. protected MaterialProperty colorWriteMask;
  79. protected MaterialProperty cullMode;
  80. protected MaterialProperty renderQueueOverride;
  81. protected const string LegacyShadersPath = "Legacy Shaders/";
  82. protected const string TransparentShadersPath = "/Transparent/";
  83. protected const string TransparentCutoutShadersPath = "/Transparent/Cutout/";
  84. public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] props)
  85. {
  86. Material material = (Material)materialEditor.target;
  87. FindProperties(props);
  88. Initialize(material);
  89. RenderingModeOptions(materialEditor);
  90. }
  91. protected virtual void FindProperties(MaterialProperty[] props)
  92. {
  93. renderingMode = FindProperty(BaseStyles.renderingModeName, props);
  94. customRenderingMode = FindProperty(BaseStyles.customRenderingModeName, props);
  95. sourceBlend = FindProperty(BaseStyles.sourceBlendName, props);
  96. destinationBlend = FindProperty(BaseStyles.destinationBlendName, props);
  97. blendOperation = FindProperty(BaseStyles.blendOperationName, props);
  98. depthTest = FindProperty(BaseStyles.depthTestName, props);
  99. depthWrite = FindProperty(BaseStyles.depthWriteName, props);
  100. depthOffsetFactor = FindProperty(BaseStyles.depthOffsetFactorName, props);
  101. depthOffsetUnits = FindProperty(BaseStyles.depthOffsetUnitsName, props);
  102. colorWriteMask = FindProperty(BaseStyles.colorWriteMaskName, props);
  103. cullMode = FindProperty(BaseStyles.cullModeName, props);
  104. renderQueueOverride = FindProperty(BaseStyles.renderQueueOverrideName, props);
  105. }
  106. protected void Initialize(Material material)
  107. {
  108. if (!initialized)
  109. {
  110. MaterialChanged(material);
  111. initialized = true;
  112. }
  113. }
  114. protected virtual void MaterialChanged(Material material)
  115. {
  116. SetupMaterialWithRenderingMode(material,
  117. (RenderingMode)renderingMode.floatValue,
  118. (CustomRenderingMode)customRenderingMode.floatValue,
  119. (int)renderQueueOverride.floatValue);
  120. }
  121. protected void RenderingModeOptions(MaterialEditor materialEditor)
  122. {
  123. EditorGUI.BeginChangeCheck();
  124. EditorGUI.showMixedValue = renderingMode.hasMixedValue;
  125. RenderingMode mode = (RenderingMode)renderingMode.floatValue;
  126. EditorGUI.BeginChangeCheck();
  127. mode = (RenderingMode)EditorGUILayout.Popup(renderingMode.displayName, (int)mode, BaseStyles.renderingModeNames);
  128. if (EditorGUI.EndChangeCheck())
  129. {
  130. materialEditor.RegisterPropertyChangeUndo(renderingMode.displayName);
  131. renderingMode.floatValue = (float)mode;
  132. Object[] targets = renderingMode.targets;
  133. foreach (Object target in targets)
  134. {
  135. MaterialChanged((Material)target);
  136. }
  137. }
  138. EditorGUI.showMixedValue = false;
  139. if ((RenderingMode)renderingMode.floatValue == RenderingMode.Custom)
  140. {
  141. EditorGUI.indentLevel += 2;
  142. customRenderingMode.floatValue = EditorGUILayout.Popup(customRenderingMode.displayName, (int)customRenderingMode.floatValue, BaseStyles.customRenderingModeNames);
  143. materialEditor.ShaderProperty(sourceBlend, BaseStyles.sourceBlend);
  144. materialEditor.ShaderProperty(destinationBlend, BaseStyles.destinationBlend);
  145. materialEditor.ShaderProperty(blendOperation, BaseStyles.blendOperation);
  146. materialEditor.ShaderProperty(depthTest, BaseStyles.depthTest);
  147. depthWrite.floatValue = EditorGUILayout.Popup(depthWrite.displayName, (int)depthWrite.floatValue, BaseStyles.depthWriteNames);
  148. materialEditor.ShaderProperty(depthOffsetFactor, BaseStyles.depthOffsetFactor);
  149. materialEditor.ShaderProperty(depthOffsetUnits, BaseStyles.depthOffsetUnits);
  150. materialEditor.ShaderProperty(colorWriteMask, BaseStyles.colorWriteMask);
  151. EditorGUI.indentLevel -= 2;
  152. }
  153. if (!PropertyEnabled(depthWrite))
  154. {
  155. /*
  156. if (MixedRealityToolkitShaderGUIUtilities.DisplayDepthWriteWarning(materialEditor))
  157. {
  158. renderingMode.floatValue = (float)RenderingMode.Custom;
  159. depthWrite.floatValue = (float)DepthWrite.On;
  160. }*/
  161. }
  162. materialEditor.ShaderProperty(cullMode, BaseStyles.cullMode);
  163. }
  164. protected static void SetupMaterialWithRenderingMode(Material material, RenderingMode mode, CustomRenderingMode customMode, int renderQueueOverride)
  165. {
  166. // If we aren't switching to Custom, then set default values for all RenderingMode types. Otherwise keep whatever user had before
  167. if (mode != RenderingMode.Custom)
  168. {
  169. material.SetInt(BaseStyles.blendOperationName, (int)BlendOp.Add);
  170. material.SetInt(BaseStyles.depthTestName, (int)CompareFunction.LessEqual);
  171. material.SetFloat(BaseStyles.depthOffsetFactorName, 0.0f);
  172. material.SetFloat(BaseStyles.depthOffsetUnitsName, 0.0f);
  173. material.SetInt(BaseStyles.colorWriteMaskName, (int)ColorWriteMask.All);
  174. }
  175. switch (mode)
  176. {
  177. case RenderingMode.Opaque:
  178. {
  179. material.SetOverrideTag(BaseStyles.renderTypeName, BaseStyles.renderingModeNames[(int)RenderingMode.Opaque]);
  180. material.SetInt(BaseStyles.customRenderingModeName, (int)CustomRenderingMode.Opaque);
  181. material.SetInt(BaseStyles.sourceBlendName, (int)BlendMode.One);
  182. material.SetInt(BaseStyles.destinationBlendName, (int)BlendMode.Zero);
  183. material.SetInt(BaseStyles.depthWriteName, (int)DepthWrite.On);
  184. material.DisableKeyword(BaseStyles.alphaTestOnName);
  185. material.DisableKeyword(BaseStyles.alphaBlendOnName);
  186. material.renderQueue = (renderQueueOverride >= 0) ? renderQueueOverride : (int)RenderQueue.Geometry;
  187. }
  188. break;
  189. case RenderingMode.TransparentCutout:
  190. {
  191. material.SetOverrideTag(BaseStyles.renderTypeName, BaseStyles.renderingModeNames[(int)RenderingMode.TransparentCutout]);
  192. material.SetInt(BaseStyles.customRenderingModeName, (int)CustomRenderingMode.TransparentCutout);
  193. material.SetInt(BaseStyles.sourceBlendName, (int)BlendMode.One);
  194. material.SetInt(BaseStyles.destinationBlendName, (int)BlendMode.Zero);
  195. material.SetInt(BaseStyles.depthWriteName, (int)DepthWrite.On);
  196. material.EnableKeyword(BaseStyles.alphaTestOnName);
  197. material.DisableKeyword(BaseStyles.alphaBlendOnName);
  198. material.renderQueue = (renderQueueOverride >= 0) ? renderQueueOverride : (int)RenderQueue.AlphaTest;
  199. }
  200. break;
  201. case RenderingMode.Transparent:
  202. {
  203. material.SetOverrideTag(BaseStyles.renderTypeName, BaseStyles.renderingModeNames[(int)RenderingMode.Transparent]);
  204. material.SetInt(BaseStyles.customRenderingModeName, (int)CustomRenderingMode.Transparent);
  205. material.SetInt(BaseStyles.sourceBlendName, (int)BlendMode.SrcAlpha);
  206. material.SetInt(BaseStyles.destinationBlendName, (int)BlendMode.OneMinusSrcAlpha);
  207. material.SetInt(BaseStyles.depthWriteName, (int)DepthWrite.Off);
  208. material.DisableKeyword(BaseStyles.alphaTestOnName);
  209. material.EnableKeyword(BaseStyles.alphaBlendOnName);
  210. material.renderQueue = (renderQueueOverride >= 0) ? renderQueueOverride : (int)RenderQueue.Transparent;
  211. }
  212. break;
  213. case RenderingMode.PremultipliedTransparent:
  214. {
  215. material.SetOverrideTag(BaseStyles.renderTypeName, BaseStyles.renderingModeNames[(int)RenderingMode.Transparent]);
  216. material.SetInt(BaseStyles.customRenderingModeName, (int)CustomRenderingMode.Transparent);
  217. material.SetInt(BaseStyles.sourceBlendName, (int)BlendMode.One);
  218. material.SetInt(BaseStyles.destinationBlendName, (int)BlendMode.OneMinusSrcAlpha);
  219. material.SetInt(BaseStyles.depthWriteName, (int)DepthWrite.Off);
  220. material.DisableKeyword(BaseStyles.alphaTestOnName);
  221. material.EnableKeyword(BaseStyles.alphaBlendOnName);
  222. material.renderQueue = (renderQueueOverride >= 0) ? renderQueueOverride : (int)RenderQueue.Transparent;
  223. }
  224. break;
  225. case RenderingMode.Additive:
  226. {
  227. material.SetOverrideTag(BaseStyles.renderTypeName, BaseStyles.renderingModeNames[(int)RenderingMode.Transparent]);
  228. material.SetInt(BaseStyles.customRenderingModeName, (int)CustomRenderingMode.Transparent);
  229. material.SetInt(BaseStyles.sourceBlendName, (int)BlendMode.One);
  230. material.SetInt(BaseStyles.destinationBlendName, (int)BlendMode.One);
  231. material.SetInt(BaseStyles.depthWriteName, (int)DepthWrite.Off);
  232. material.DisableKeyword(BaseStyles.alphaTestOnName);
  233. material.EnableKeyword(BaseStyles.alphaBlendOnName);
  234. material.renderQueue = (renderQueueOverride >= 0) ? renderQueueOverride : (int)RenderQueue.Transparent;
  235. }
  236. break;
  237. case RenderingMode.Custom:
  238. {
  239. material.SetOverrideTag(BaseStyles.renderTypeName, BaseStyles.customRenderingModeNames[(int)customMode]);
  240. // _SrcBlend, _DstBlend, _BlendOp, _ZTest, _ZWrite, _ColorWriteMask are controlled by UI.
  241. switch (customMode)
  242. {
  243. case CustomRenderingMode.Opaque:
  244. {
  245. material.DisableKeyword(BaseStyles.alphaTestOnName);
  246. material.DisableKeyword(BaseStyles.alphaBlendOnName);
  247. }
  248. break;
  249. case CustomRenderingMode.TransparentCutout:
  250. {
  251. material.EnableKeyword(BaseStyles.alphaTestOnName);
  252. material.DisableKeyword(BaseStyles.alphaBlendOnName);
  253. }
  254. break;
  255. case CustomRenderingMode.Transparent:
  256. {
  257. material.DisableKeyword(BaseStyles.alphaTestOnName);
  258. material.EnableKeyword(BaseStyles.alphaBlendOnName);
  259. }
  260. break;
  261. }
  262. material.renderQueue = (renderQueueOverride >= 0) ? renderQueueOverride : material.renderQueue;
  263. }
  264. break;
  265. }
  266. }
  267. /// <summary>
  268. /// Check whether shader feature is enabled
  269. /// </summary>
  270. /// <param name="property">float property to check against</param>
  271. /// <returns>false if 0.0f, true otherwise</returns>
  272. protected static bool PropertyEnabled(MaterialProperty property)
  273. {
  274. return !property.floatValue.Equals(0.0f);
  275. }
  276. /// <summary>
  277. /// Get the value of a given float property for a material
  278. /// </summary>
  279. /// <param name="material">material to check</param>
  280. /// <param name="propertyName">name of property against material</param>
  281. /// <returns>if has property, then value of that property for current material, null otherwise</returns>
  282. protected static float? GetFloatProperty(Material material, string propertyName)
  283. {
  284. if (material.HasProperty(propertyName))
  285. {
  286. return material.GetFloat(propertyName);
  287. }
  288. return null;
  289. }
  290. /// <summary>
  291. /// Get the value of a given vector property for a material
  292. /// </summary>
  293. /// <param name="material">material to check</param>
  294. /// <param name="propertyName">name of property against material</param>
  295. /// <returns>if has property, then value of that property for current material, null otherwise</returns>
  296. protected static Vector4? GetVectorProperty(Material material, string propertyName)
  297. {
  298. if (material.HasProperty(propertyName))
  299. {
  300. return material.GetVector(propertyName);
  301. }
  302. return null;
  303. }
  304. /// <summary>
  305. /// Get the value of a given color property for a material
  306. /// </summary>
  307. /// <param name="material">material to check</param>
  308. /// <param name="propertyName">name of property against material</param>
  309. /// <returns>if has property, then value of that property for current material, null otherwise</returns>
  310. protected static Color? GetColorProperty(Material material, string propertyName)
  311. {
  312. if (material.HasProperty(propertyName))
  313. {
  314. return material.GetColor(propertyName);
  315. }
  316. return null;
  317. }
  318. /// <summary>
  319. /// Sets the shader feature controlled by keyword and property name parameters active or inactive
  320. /// </summary>
  321. /// <param name="material">Material to modify</param>
  322. /// <param name="keywordName">Keyword of shader feature</param>
  323. /// <param name="propertyName">Associated property name for shader feature</param>
  324. /// <param name="propertyValue">float to be treated as a boolean flag for setting shader feature active or inactive</param>
  325. protected static void SetShaderFeatureActive(Material material, string keywordName, string propertyName, float? propertyValue)
  326. {
  327. if (propertyValue.HasValue)
  328. {
  329. if (keywordName != null)
  330. {
  331. if (!propertyValue.Value.Equals(0.0f))
  332. {
  333. material.EnableKeyword(keywordName);
  334. }
  335. else
  336. {
  337. material.DisableKeyword(keywordName);
  338. }
  339. }
  340. material.SetFloat(propertyName, propertyValue.Value);
  341. }
  342. }
  343. /// <summary>
  344. /// Sets vector property against associated material
  345. /// </summary>
  346. /// <param name="material">material to control</param>
  347. /// <param name="propertyName">name of property to set</param>
  348. /// <param name="propertyValue">value of property to set</param>
  349. protected static void SetVectorProperty(Material material, string propertyName, Vector4? propertyValue)
  350. {
  351. if (propertyValue.HasValue)
  352. {
  353. material.SetVector(propertyName, propertyValue.Value);
  354. }
  355. }
  356. /// <summary>
  357. /// Set color property against associated material
  358. /// </summary>
  359. /// <param name="material">material to control</param>
  360. /// <param name="propertyName">name of property to set</param>
  361. /// <param name="propertyValue">value of property to set</param>
  362. protected static void SetColorProperty(Material material, string propertyName, Color? propertyValue)
  363. {
  364. if (propertyValue.HasValue)
  365. {
  366. material.SetColor(propertyName, propertyValue.Value);
  367. }
  368. }
  369. }
  370. }