BaseShaderGUI.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. using System;
  2. using UnityEngine;
  3. using UnityEngine.Rendering;
  4. using UnityEditor.Rendering.Universal;
  5. namespace UnityEditor
  6. {
  7. public abstract class BaseShaderGUI : ShaderGUI
  8. {
  9. #region EnumsAndClasses
  10. public enum SurfaceType
  11. {
  12. Opaque,
  13. Transparent
  14. }
  15. public enum BlendMode
  16. {
  17. Alpha, // Old school alpha-blending mode, fresnel does not affect amount of transparency
  18. Premultiply, // Physically plausible transparency mode, implemented as alpha pre-multiply
  19. Additive,
  20. Multiply
  21. }
  22. public enum SmoothnessSource
  23. {
  24. BaseAlpha,
  25. SpecularAlpha
  26. }
  27. public enum RenderFace
  28. {
  29. Front = 2,
  30. Back = 1,
  31. Both = 0
  32. }
  33. protected class Styles
  34. {
  35. // Catergories
  36. public static readonly GUIContent SurfaceOptions =
  37. new GUIContent("Surface Options", "Controls how Universal RP renders the Material on a screen.");
  38. public static readonly GUIContent SurfaceInputs = new GUIContent("Surface Inputs",
  39. "These settings describe the look and feel of the surface itself.");
  40. public static readonly GUIContent AdvancedLabel = new GUIContent("Advanced",
  41. "These settings affect behind-the-scenes rendering and underlying calculations.");
  42. public static readonly GUIContent surfaceType = new GUIContent("Surface Type",
  43. "Select a surface type for your texture. Choose between Opaque or Transparent.");
  44. public static readonly GUIContent blendingMode = new GUIContent("Blending Mode",
  45. "Controls how the color of the Transparent surface blends with the Material color in the background.");
  46. public static readonly GUIContent cullingText = new GUIContent("Render Face",
  47. "Specifies which faces to cull from your geometry. Front culls front faces. Back culls backfaces. None means that both sides are rendered.");
  48. public static readonly GUIContent alphaClipText = new GUIContent("Alpha Clipping",
  49. "Makes your Material act like a Cutout shader. Use this to create a transparent effect with hard edges between opaque and transparent areas.");
  50. public static readonly GUIContent alphaClipThresholdText = new GUIContent("Threshold",
  51. "Sets where the Alpha Clipping starts. The higher the value is, the brighter the effect is when clipping starts.");
  52. public static readonly GUIContent receiveShadowText = new GUIContent("Receive Shadows",
  53. "When enabled, other GameObjects can cast shadows onto this GameObject.");
  54. public static readonly GUIContent baseMap = new GUIContent("Base Map",
  55. "Specifies the base Material and/or Color of the surface. If you’ve selected Transparent or Alpha Clipping under Surface Options, your Material uses the Texture’s alpha channel or color.");
  56. public static readonly GUIContent emissionMap = new GUIContent("Emission Map",
  57. "Sets a Texture map to use for emission. You can also select a color with the color picker. Colors are multiplied over the Texture.");
  58. public static readonly GUIContent normalMapText =
  59. new GUIContent("Normal Map", "Assigns a tangent-space normal map.");
  60. public static readonly GUIContent bumpScaleNotSupported =
  61. new GUIContent("Bump scale is not supported on mobile platforms");
  62. public static readonly GUIContent fixNormalNow = new GUIContent("Fix now",
  63. "Converts the assigned texture to be a normal map format.");
  64. public static readonly GUIContent queueSlider = new GUIContent("Priority",
  65. "Determines the chronological rendering order for a Material. High values are rendered first.");
  66. }
  67. #endregion
  68. #region Variables
  69. protected MaterialEditor materialEditor { get; set; }
  70. protected MaterialProperty surfaceTypeProp { get; set; }
  71. protected MaterialProperty blendModeProp { get; set; }
  72. protected MaterialProperty cullingProp { get; set; }
  73. protected MaterialProperty alphaClipProp { get; set; }
  74. protected MaterialProperty alphaCutoffProp { get; set; }
  75. protected MaterialProperty receiveShadowsProp { get; set; }
  76. // Common Surface Input properties
  77. protected MaterialProperty baseMapProp { get; set; }
  78. protected MaterialProperty baseColorProp { get; set; }
  79. protected MaterialProperty emissionMapProp { get; set; }
  80. protected MaterialProperty emissionColorProp { get; set; }
  81. protected MaterialProperty queueOffsetProp { get; set; }
  82. public bool m_FirstTimeApply = true;
  83. private const string k_KeyPrefix = "UniversalRP:Material:UI_State:";
  84. private string m_HeaderStateKey = null;
  85. // Header foldout states
  86. SavedBool m_SurfaceOptionsFoldout;
  87. SavedBool m_SurfaceInputsFoldout;
  88. SavedBool m_AdvancedFoldout;
  89. #endregion
  90. private const int queueOffsetRange = 50;
  91. ////////////////////////////////////
  92. // General Functions //
  93. ////////////////////////////////////
  94. #region GeneralFunctions
  95. public abstract void MaterialChanged(Material material);
  96. public virtual void FindProperties(MaterialProperty[] properties)
  97. {
  98. surfaceTypeProp = FindProperty("_Surface", properties);
  99. blendModeProp = FindProperty("_Blend", properties);
  100. cullingProp = FindProperty("_Cull", properties);
  101. alphaClipProp = FindProperty("_AlphaClip", properties);
  102. alphaCutoffProp = FindProperty("_Cutoff", properties);
  103. receiveShadowsProp = FindProperty("_ReceiveShadows", properties, false);
  104. baseMapProp = FindProperty("_BaseMap", properties, false);
  105. baseColorProp = FindProperty("_BaseColor", properties, false);
  106. emissionMapProp = FindProperty("_EmissionMap", properties, false);
  107. emissionColorProp = FindProperty("_EmissionColor", properties, false);
  108. queueOffsetProp = FindProperty("_QueueOffset", properties, false);
  109. }
  110. public override void OnGUI(MaterialEditor materialEditorIn, MaterialProperty[] properties)
  111. {
  112. if (materialEditorIn == null)
  113. throw new ArgumentNullException("materialEditorIn");
  114. FindProperties(properties); // MaterialProperties can be animated so we do not cache them but fetch them every event to ensure animated values are updated correctly
  115. materialEditor = materialEditorIn;
  116. Material material = materialEditor.target as Material;
  117. // Make sure that needed setup (ie keywords/renderqueue) are set up if we're switching some existing
  118. // material to a universal shader.
  119. if (m_FirstTimeApply)
  120. {
  121. OnOpenGUI(material, materialEditorIn);
  122. m_FirstTimeApply = false;
  123. }
  124. ShaderPropertiesGUI(material);
  125. }
  126. public virtual void OnOpenGUI(Material material, MaterialEditor materialEditor)
  127. {
  128. // Foldout states
  129. m_HeaderStateKey = k_KeyPrefix + material.shader.name; // Create key string for editor prefs
  130. m_SurfaceOptionsFoldout = new SavedBool($"{m_HeaderStateKey}.SurfaceOptionsFoldout", true);
  131. m_SurfaceInputsFoldout = new SavedBool($"{m_HeaderStateKey}.SurfaceInputsFoldout", true);
  132. m_AdvancedFoldout = new SavedBool($"{m_HeaderStateKey}.AdvancedFoldout", false);
  133. foreach (var obj in materialEditor.targets)
  134. MaterialChanged((Material)obj);
  135. }
  136. public void ShaderPropertiesGUI(Material material)
  137. {
  138. if (material == null)
  139. throw new ArgumentNullException("material");
  140. EditorGUI.BeginChangeCheck();
  141. m_SurfaceOptionsFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SurfaceOptionsFoldout.value, Styles.SurfaceOptions);
  142. if(m_SurfaceOptionsFoldout.value){
  143. DrawSurfaceOptions(material);
  144. EditorGUILayout.Space();
  145. }
  146. EditorGUILayout.EndFoldoutHeaderGroup();
  147. m_SurfaceInputsFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SurfaceInputsFoldout.value, Styles.SurfaceInputs);
  148. if (m_SurfaceInputsFoldout.value)
  149. {
  150. DrawSurfaceInputs(material);
  151. EditorGUILayout.Space();
  152. }
  153. EditorGUILayout.EndFoldoutHeaderGroup();
  154. m_AdvancedFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_AdvancedFoldout.value, Styles.AdvancedLabel);
  155. if (m_AdvancedFoldout.value)
  156. {
  157. DrawAdvancedOptions(material);
  158. EditorGUILayout.Space();
  159. }
  160. EditorGUILayout.EndFoldoutHeaderGroup();
  161. DrawAdditionalFoldouts(material);
  162. if (EditorGUI.EndChangeCheck())
  163. {
  164. foreach (var obj in materialEditor.targets)
  165. MaterialChanged((Material)obj);
  166. }
  167. }
  168. #endregion
  169. ////////////////////////////////////
  170. // Drawing Functions //
  171. ////////////////////////////////////
  172. #region DrawingFunctions
  173. public virtual void DrawSurfaceOptions(Material material)
  174. {
  175. DoPopup(Styles.surfaceType, surfaceTypeProp, Enum.GetNames(typeof(SurfaceType)));
  176. if ((SurfaceType)material.GetFloat("_Surface") == SurfaceType.Transparent)
  177. DoPopup(Styles.blendingMode, blendModeProp, Enum.GetNames(typeof(BlendMode)));
  178. EditorGUI.BeginChangeCheck();
  179. EditorGUI.showMixedValue = cullingProp.hasMixedValue;
  180. var culling = (RenderFace)cullingProp.floatValue;
  181. culling = (RenderFace)EditorGUILayout.EnumPopup(Styles.cullingText, culling);
  182. if (EditorGUI.EndChangeCheck())
  183. {
  184. materialEditor.RegisterPropertyChangeUndo(Styles.cullingText.text);
  185. cullingProp.floatValue = (float)culling;
  186. material.doubleSidedGI = (RenderFace)cullingProp.floatValue != RenderFace.Front;
  187. }
  188. EditorGUI.showMixedValue = false;
  189. EditorGUI.BeginChangeCheck();
  190. EditorGUI.showMixedValue = alphaClipProp.hasMixedValue;
  191. var alphaClipEnabled = EditorGUILayout.Toggle(Styles.alphaClipText, alphaClipProp.floatValue == 1);
  192. if (EditorGUI.EndChangeCheck())
  193. alphaClipProp.floatValue = alphaClipEnabled ? 1 : 0;
  194. EditorGUI.showMixedValue = false;
  195. if (alphaClipProp.floatValue == 1)
  196. materialEditor.ShaderProperty(alphaCutoffProp, Styles.alphaClipThresholdText, 1);
  197. if (receiveShadowsProp != null)
  198. {
  199. EditorGUI.BeginChangeCheck();
  200. EditorGUI.showMixedValue = receiveShadowsProp.hasMixedValue;
  201. var receiveShadows =
  202. EditorGUILayout.Toggle(Styles.receiveShadowText, receiveShadowsProp.floatValue == 1.0f);
  203. if (EditorGUI.EndChangeCheck())
  204. receiveShadowsProp.floatValue = receiveShadows ? 1.0f : 0.0f;
  205. EditorGUI.showMixedValue = false;
  206. }
  207. }
  208. public virtual void DrawSurfaceInputs(Material material)
  209. {
  210. DrawBaseProperties(material);
  211. }
  212. public virtual void DrawAdvancedOptions(Material material)
  213. {
  214. materialEditor.EnableInstancingField();
  215. if (queueOffsetProp != null)
  216. {
  217. EditorGUI.BeginChangeCheck();
  218. EditorGUI.showMixedValue = queueOffsetProp.hasMixedValue;
  219. var queue = EditorGUILayout.IntSlider(Styles.queueSlider, (int)queueOffsetProp.floatValue, -queueOffsetRange, queueOffsetRange);
  220. if (EditorGUI.EndChangeCheck())
  221. queueOffsetProp.floatValue = queue;
  222. EditorGUI.showMixedValue = false;
  223. }
  224. }
  225. public virtual void DrawAdditionalFoldouts(Material material){}
  226. public virtual void DrawBaseProperties(Material material)
  227. {
  228. if (baseMapProp != null && baseColorProp != null) // Draw the baseMap, most shader will have at least a baseMap
  229. {
  230. materialEditor.TexturePropertySingleLine(Styles.baseMap, baseMapProp, baseColorProp);
  231. // TODO Temporary fix for lightmapping, to be replaced with attribute tag.
  232. if (material.HasProperty("_MainTex"))
  233. {
  234. material.SetTexture("_MainTex", baseMapProp.textureValue);
  235. var baseMapTiling = baseMapProp.textureScaleAndOffset;
  236. material.SetTextureScale("_MainTex", new Vector2(baseMapTiling.x, baseMapTiling.y));
  237. material.SetTextureOffset("_MainTex", new Vector2(baseMapTiling.z, baseMapTiling.w));
  238. }
  239. }
  240. }
  241. protected virtual void DrawEmissionProperties(Material material, bool keyword)
  242. {
  243. var emissive = true;
  244. var hadEmissionTexture = emissionMapProp.textureValue != null;
  245. if (!keyword)
  246. {
  247. materialEditor.TexturePropertyWithHDRColor(Styles.emissionMap, emissionMapProp, emissionColorProp,
  248. false);
  249. }
  250. else
  251. {
  252. // Emission for GI?
  253. emissive = materialEditor.EmissionEnabledProperty();
  254. EditorGUI.BeginDisabledGroup(!emissive);
  255. {
  256. // Texture and HDR color controls
  257. materialEditor.TexturePropertyWithHDRColor(Styles.emissionMap, emissionMapProp,
  258. emissionColorProp,
  259. false);
  260. }
  261. EditorGUI.EndDisabledGroup();
  262. }
  263. // If texture was assigned and color was black set color to white
  264. var brightness = emissionColorProp.colorValue.maxColorComponent;
  265. if (emissionMapProp.textureValue != null && !hadEmissionTexture && brightness <= 0f)
  266. emissionColorProp.colorValue = Color.white;
  267. // UniversalRP does not support RealtimeEmissive. We set it to bake emissive and handle the emissive is black right.
  268. if (emissive)
  269. {
  270. material.globalIlluminationFlags = MaterialGlobalIlluminationFlags.BakedEmissive;
  271. if (brightness <= 0f)
  272. material.globalIlluminationFlags |= MaterialGlobalIlluminationFlags.EmissiveIsBlack;
  273. }
  274. }
  275. public static void DrawNormalArea(MaterialEditor materialEditor, MaterialProperty bumpMap, MaterialProperty bumpMapScale = null)
  276. {
  277. if (bumpMapScale != null)
  278. {
  279. materialEditor.TexturePropertySingleLine(Styles.normalMapText, bumpMap,
  280. bumpMap.textureValue != null ? bumpMapScale : null);
  281. if (bumpMapScale.floatValue != 1 &&
  282. UnityEditorInternal.InternalEditorUtility.IsMobilePlatform(
  283. EditorUserBuildSettings.activeBuildTarget))
  284. if (materialEditor.HelpBoxWithButton(Styles.bumpScaleNotSupported, Styles.fixNormalNow))
  285. bumpMapScale.floatValue = 1;
  286. }
  287. else
  288. {
  289. materialEditor.TexturePropertySingleLine(Styles.normalMapText, bumpMap);
  290. }
  291. }
  292. protected static void DrawTileOffset(MaterialEditor materialEditor, MaterialProperty textureProp)
  293. {
  294. materialEditor.TextureScaleOffsetProperty(textureProp);
  295. }
  296. #endregion
  297. ////////////////////////////////////
  298. // Material Data Functions //
  299. ////////////////////////////////////
  300. #region MaterialDataFunctions
  301. public static void SetMaterialKeywords(Material material, Action<Material> shadingModelFunc = null, Action<Material> shaderFunc = null)
  302. {
  303. // Clear all keywords for fresh start
  304. material.shaderKeywords = null;
  305. // Setup blending - consistent across all Universal RP shaders
  306. SetupMaterialBlendMode(material);
  307. // Receive Shadows
  308. if(material.HasProperty("_ReceiveShadows"))
  309. CoreUtils.SetKeyword(material, "_RECEIVE_SHADOWS_OFF", material.GetFloat("_ReceiveShadows") == 0.0f);
  310. // Emission
  311. if (material.HasProperty("_EmissionColor"))
  312. MaterialEditor.FixupEmissiveFlag(material);
  313. bool shouldEmissionBeEnabled =
  314. (material.globalIlluminationFlags & MaterialGlobalIlluminationFlags.EmissiveIsBlack) == 0;
  315. if (material.HasProperty("_EmissionEnabled") && !shouldEmissionBeEnabled)
  316. shouldEmissionBeEnabled = material.GetFloat("_EmissionEnabled") >= 0.5f;
  317. CoreUtils.SetKeyword(material, "_EMISSION", shouldEmissionBeEnabled);
  318. // Normal Map
  319. if(material.HasProperty("_BumpMap"))
  320. CoreUtils.SetKeyword(material, "_NORMALMAP", material.GetTexture("_BumpMap"));
  321. // Shader specific keyword functions
  322. shadingModelFunc?.Invoke(material);
  323. shaderFunc?.Invoke(material);
  324. }
  325. public static void SetupMaterialBlendMode(Material material)
  326. {
  327. if (material == null)
  328. throw new ArgumentNullException("material");
  329. bool alphaClip = material.GetFloat("_AlphaClip") == 1;
  330. if (alphaClip)
  331. {
  332. material.EnableKeyword("_ALPHATEST_ON");
  333. }
  334. else
  335. {
  336. material.DisableKeyword("_ALPHATEST_ON");
  337. }
  338. var queueOffset = 0; // queueOffsetRange;
  339. if(material.HasProperty("_QueueOffset"))
  340. queueOffset = queueOffsetRange - (int) material.GetFloat("_QueueOffset");
  341. SurfaceType surfaceType = (SurfaceType)material.GetFloat("_Surface");
  342. if (surfaceType == SurfaceType.Opaque)
  343. {
  344. if (alphaClip)
  345. {
  346. material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.AlphaTest;
  347. material.SetOverrideTag("RenderType", "TransparentCutout");
  348. }
  349. else
  350. {
  351. material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Geometry;
  352. material.SetOverrideTag("RenderType", "Opaque");
  353. }
  354. material.renderQueue += queueOffset;
  355. material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
  356. material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
  357. material.SetInt("_ZWrite", 1);
  358. material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
  359. material.SetShaderPassEnabled("ShadowCaster", true);
  360. }
  361. else
  362. {
  363. BlendMode blendMode = (BlendMode)material.GetFloat("_Blend");
  364. var queue = (int) UnityEngine.Rendering.RenderQueue.Transparent;
  365. // Specific Transparent Mode Settings
  366. switch (blendMode)
  367. {
  368. case BlendMode.Alpha:
  369. material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
  370. material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
  371. material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
  372. break;
  373. case BlendMode.Premultiply:
  374. material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
  375. material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
  376. material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
  377. break;
  378. case BlendMode.Additive:
  379. material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
  380. material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.One);
  381. material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
  382. break;
  383. case BlendMode.Multiply:
  384. material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.DstColor);
  385. material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
  386. material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
  387. material.EnableKeyword("_ALPHAMODULATE_ON");
  388. break;
  389. }
  390. // General Transparent Material Settings
  391. material.SetOverrideTag("RenderType", "Transparent");
  392. material.SetInt("_ZWrite", 0);
  393. material.renderQueue = queue + queueOffset;
  394. material.SetShaderPassEnabled("ShadowCaster", false);
  395. }
  396. }
  397. #endregion
  398. ////////////////////////////////////
  399. // Helper Functions //
  400. ////////////////////////////////////
  401. #region HelperFunctions
  402. public static void TwoFloatSingleLine(GUIContent title, MaterialProperty prop1, GUIContent prop1Label,
  403. MaterialProperty prop2, GUIContent prop2Label, MaterialEditor materialEditor, float labelWidth = 30f)
  404. {
  405. EditorGUI.BeginChangeCheck();
  406. EditorGUI.showMixedValue = prop1.hasMixedValue || prop2.hasMixedValue;
  407. Rect rect = EditorGUILayout.GetControlRect();
  408. EditorGUI.PrefixLabel(rect, title);
  409. var indent = EditorGUI.indentLevel;
  410. var preLabelWidth = EditorGUIUtility.labelWidth;
  411. EditorGUI.indentLevel = 0;
  412. EditorGUIUtility.labelWidth = labelWidth;
  413. Rect propRect1 = new Rect(rect.x + preLabelWidth, rect.y,
  414. (rect.width - preLabelWidth) * 0.5f, EditorGUIUtility.singleLineHeight);
  415. var prop1val = EditorGUI.FloatField(propRect1, prop1Label, prop1.floatValue);
  416. Rect propRect2 = new Rect(propRect1.x + propRect1.width, rect.y,
  417. propRect1.width, EditorGUIUtility.singleLineHeight);
  418. var prop2val = EditorGUI.FloatField(propRect2, prop2Label, prop2.floatValue);
  419. EditorGUI.indentLevel = indent;
  420. EditorGUIUtility.labelWidth = preLabelWidth;
  421. if (EditorGUI.EndChangeCheck())
  422. {
  423. materialEditor.RegisterPropertyChangeUndo(title.text);
  424. prop1.floatValue = prop1val;
  425. prop2.floatValue = prop2val;
  426. }
  427. EditorGUI.showMixedValue = false;
  428. }
  429. public void DoPopup(GUIContent label, MaterialProperty property, string[] options)
  430. {
  431. DoPopup(label, property, options, materialEditor);
  432. }
  433. public static void DoPopup(GUIContent label, MaterialProperty property, string[] options, MaterialEditor materialEditor)
  434. {
  435. if (property == null)
  436. throw new ArgumentNullException("property");
  437. EditorGUI.showMixedValue = property.hasMixedValue;
  438. var mode = property.floatValue;
  439. EditorGUI.BeginChangeCheck();
  440. mode = EditorGUILayout.Popup(label, (int)mode, options);
  441. if (EditorGUI.EndChangeCheck())
  442. {
  443. materialEditor.RegisterPropertyChangeUndo(label.text);
  444. property.floatValue = mode;
  445. }
  446. EditorGUI.showMixedValue = false;
  447. }
  448. // Helper to show texture and color properties
  449. public static Rect TextureColorProps(MaterialEditor materialEditor, GUIContent label, MaterialProperty textureProp, MaterialProperty colorProp, bool hdr = false)
  450. {
  451. Rect rect = EditorGUILayout.GetControlRect();
  452. EditorGUI.showMixedValue = textureProp.hasMixedValue;
  453. materialEditor.TexturePropertyMiniThumbnail(rect, textureProp, label.text, label.tooltip);
  454. EditorGUI.showMixedValue = false;
  455. if (colorProp != null)
  456. {
  457. EditorGUI.BeginChangeCheck();
  458. EditorGUI.showMixedValue = colorProp.hasMixedValue;
  459. int indentLevel = EditorGUI.indentLevel;
  460. EditorGUI.indentLevel = 0;
  461. Rect rectAfterLabel = new Rect(rect.x + EditorGUIUtility.labelWidth, rect.y,
  462. EditorGUIUtility.fieldWidth, EditorGUIUtility.singleLineHeight);
  463. var col = EditorGUI.ColorField(rectAfterLabel, GUIContent.none, colorProp.colorValue, true,
  464. false, hdr);
  465. EditorGUI.indentLevel = indentLevel;
  466. if (EditorGUI.EndChangeCheck())
  467. {
  468. materialEditor.RegisterPropertyChangeUndo(colorProp.displayName);
  469. colorProp.colorValue = col;
  470. }
  471. EditorGUI.showMixedValue = false;
  472. }
  473. return rect;
  474. }
  475. // Copied from shaderGUI as it is a protected function in an abstract class, unavailable to others
  476. public new static MaterialProperty FindProperty(string propertyName, MaterialProperty[] properties)
  477. {
  478. return FindProperty(propertyName, properties, true);
  479. }
  480. // Copied from shaderGUI as it is a protected function in an abstract class, unavailable to others
  481. public new static MaterialProperty FindProperty(string propertyName, MaterialProperty[] properties, bool propertyIsMandatory)
  482. {
  483. for (int index = 0; index < properties.Length; ++index)
  484. {
  485. if (properties[index] != null && properties[index].name == propertyName)
  486. return properties[index];
  487. }
  488. if (propertyIsMandatory)
  489. throw new ArgumentException("Could not find MaterialProperty: '" + propertyName + "', Num properties: " + (object) properties.Length);
  490. return null;
  491. }
  492. #endregion
  493. }
  494. }