ShadowShaderGUI.cs 18 KB

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