AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
FastConfigurableGUI.cs
Go to the documentation of this file.
1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT License. See LICENSE in the project root for license information.
3 
4 using System;
5 using UnityEditor;
6 using UnityEngine;
7 
8 namespace HoloToolkit.Unity
9 {
13  public class FastConfigurableGUI : ShaderGUI
14  {
15  protected bool firstTimeApply = true;
16 
17  //cached material properties
18  protected MaterialProperty blendMode;
19 
20  protected MaterialProperty vertexColorEnabled;
21  protected MaterialProperty mainColorEnabled;
22  protected MaterialProperty mainColor;
23  protected MaterialProperty mainTexture;
24  protected MaterialProperty alphaCutoff;
25  protected MaterialProperty occlusionMap;
26 
27  protected MaterialProperty ambientLightingEnabled;
28  protected MaterialProperty diffuseLightingEnabled;
29  protected MaterialProperty useAdditionalLightingData;
30  protected MaterialProperty perPixelLighting;
31 
32  protected MaterialProperty specularLightingEnabled;
33  protected MaterialProperty specularColor;
34  protected MaterialProperty specular;
35  protected MaterialProperty specularMap;
36  protected MaterialProperty gloss;
37  protected MaterialProperty glossMap;
38 
39  protected MaterialProperty normalMap;
40 
41  protected MaterialProperty reflectionsEnabled;
42  protected MaterialProperty cubeMap;
43  protected MaterialProperty reflectionScale;
44  protected MaterialProperty calibrationSpaceReflections;
45 
46  protected MaterialProperty rimLightingEnabled;
47  protected MaterialProperty rimPower;
48  protected MaterialProperty rimColor;
49 
50  protected MaterialProperty emissionColorEnabled;
51  protected MaterialProperty emissionColor;
52  protected MaterialProperty emissionMap;
53 
54  protected MaterialProperty useTextureScale;
55  protected MaterialProperty useTextureOffset;
56  protected MaterialProperty textureScaleAndOffset;
57 
58  protected MaterialProperty srcBlend;
59  protected MaterialProperty dstBlend;
60  protected MaterialProperty blendOp;
61 
62  protected MaterialProperty cullMode;
63  protected MaterialProperty zTest;
64  protected MaterialProperty zWrite;
65  protected MaterialProperty colorWriteMask;
66 
67  public override void OnGUI(MaterialEditor matEditor, MaterialProperty[] props)
68  {
69  // MaterialProperties can be animated so we do not cache them but fetch them every event to ensure animated values are updated correctly
70  CacheMainProperties(props);
71  CacheOutputConfigurationProperties(props);
72 
73  // Make sure that needed setup (ie keywords/renderqueue) are set up if we're switching from an existing material.
74  // Do this before any GUI code has been issued to prevent layout issues in subsequent GUILayout statements (case 780071)
75  if (firstTimeApply)
76  {
77  firstTimeApply = false;
78  }
79 
80  EditorGUIUtility.labelWidth = 0f;
81 
82  EditorGUI.BeginChangeCheck();
83  {
84  ShowMainGUI(matEditor);
85  ShowOutputConfigurationGUI(matEditor);
86 
87  var mode = (BlendMode)blendMode.floatValue;
88  if (mode == BlendMode.Advanced)
89  {
90  matEditor.RenderQueueField();
91  }
92  }
93  if (EditorGUI.EndChangeCheck())
94  {
95  foreach (var obj in blendMode.targets)
96  {
97  var mat = obj as Material;
98  SetMaterialBlendMode(mat, (BlendMode)blendMode.floatValue);
99  SetMaterialAutoPropertiesAndKeywords(mat);
100  }
101  }
102  }
103 
104  protected virtual void ShowMainGUI(MaterialEditor matEditor)
105  {
106  ShowBlendModeGUI(matEditor);
107 
108  var mode = (BlendMode)blendMode.floatValue;
109  var mat = matEditor.target as Material;
110 
111  ShaderGUIUtils.BeginHeader("Base Texture and Color");
112  {
113  matEditor.ShaderProperty(vertexColorEnabled, Styles.vertexColorEnabled);
114 
116  Styles.main,
117  mainTexture,
118  mainColorEnabled, mainColor,
119  textureScaleAndOffset);
120 
121  matEditor.TexturePropertySingleLine(Styles.occlusionMap, occlusionMap);
122 
123  if (mode == BlendMode.Cutout)
124  {
125  matEditor.ShaderProperty(alphaCutoff, Styles.alphaCutoffText.text);
126  }
127  }
130 
131  ShaderGUIUtils.BeginHeader("Lighting");
132  {
133  matEditor.ShaderProperty(ambientLightingEnabled, Styles.ambientLightingEnabled);
134  matEditor.ShaderProperty(diffuseLightingEnabled, Styles.diffuseLightingEnabled);
135  matEditor.ShaderProperty(useAdditionalLightingData, Styles.useAdditionalLighingData);
136  EditorGUI.BeginDisabledGroup(MaterialNeedsPerPixel(mat));
137  matEditor.ShaderProperty(perPixelLighting, Styles.perPixelLighting);
138  EditorGUI.EndDisabledGroup();
139 
140  ShaderGUIUtils.BeginHeaderProperty(matEditor, Styles.specularLightingEnabled.text, specularLightingEnabled);
141  {
142  if (specularLightingEnabled.floatValue != 0.0f)
143  {
144  matEditor.ShaderProperty(specularColor, Styles.specularColor);
145 
146  //consider a special slider + tex control
147  matEditor.TexturePropertySingleLine(Styles.specular, specularMap, specular);
148  matEditor.TexturePropertySingleLine(Styles.gloss, glossMap, gloss);
149  }
150  }
152 
153  matEditor.TexturePropertySingleLine(Styles.normalMap, normalMap);
154 
155  ShaderGUIUtils.BeginHeaderProperty(matEditor, Styles.rimLightingEnabled.text, rimLightingEnabled);
156  {
157  if (rimLightingEnabled.floatValue != 0.0f)
158  {
159  matEditor.ShaderProperty(rimPower, Styles.rimPower);
160  matEditor.ShaderProperty(rimColor, Styles.rimColor);
161  }
162  }
164 
165  ShaderGUIUtils.BeginHeaderProperty(matEditor, Styles.reflectionsEnabled.text, reflectionsEnabled);
166  {
167  if (reflectionsEnabled.floatValue != 0.0f)
168  {
169  matEditor.TexturePropertySingleLine(Styles.cubeMap, cubeMap);
170  matEditor.ShaderProperty(reflectionScale, Styles.reflectionScale);
171  matEditor.ShaderProperty(calibrationSpaceReflections, Styles.calibrationSpaceReflections);
172  }
173  }
175 
176  CustomMaterialEditor.TextureWithToggleableColorSingleLine(matEditor, Styles.emission, emissionMap, emissionColorEnabled, emissionColor);
177  }
180 
181  ShaderGUIUtils.BeginHeader("Global");
182  {
183  CustomMaterialEditor.TextureScaleOffsetVector4Property(matEditor, textureScaleAndOffset);
184  }
187 
188  if (mode == BlendMode.Advanced)
189  {
190  ShaderGUIUtils.BeginHeader("Alpha Blending");
191  {
192  matEditor.ShaderProperty(srcBlend, Styles.srcBlend);
193  matEditor.ShaderProperty(dstBlend, Styles.dstBlend);
194  matEditor.ShaderProperty(blendOp, Styles.blendOp);
195  }
198  }
199  }
200 
201  protected virtual void ShowBlendModeGUI(MaterialEditor matEditor)
202  {
203  EditorGUI.showMixedValue = blendMode.hasMixedValue;
204  var mode = (BlendMode)blendMode.floatValue;
205 
206  EditorGUI.BeginChangeCheck();
207  mode = (BlendMode)EditorGUILayout.Popup(Styles.renderingMode, (int)mode, Styles.blendNames);
208  if (EditorGUI.EndChangeCheck())
209  {
210  matEditor.RegisterPropertyChangeUndo("Rendering Mode");
211  blendMode.floatValue = (float)mode;
212  }
213 
214  EditorGUI.showMixedValue = false;
215  }
216 
217  protected virtual void ShowOutputConfigurationGUI(MaterialEditor matEditor)
218  {
219  var mode = (BlendMode)blendMode.floatValue;
220  if (mode == BlendMode.Advanced)
221  {
222  ShaderGUIUtils.BeginHeader("Output Configuration");
223  {
224  matEditor.ShaderProperty(cullMode, Styles.cullMode);
225  matEditor.ShaderProperty(zTest, Styles.zTest);
226  matEditor.ShaderProperty(zWrite, Styles.zWrite);
227  matEditor.ShaderProperty(colorWriteMask, Styles.colorWriteMask);
228  }
230  }
231  }
232 
233  public override void AssignNewShaderToMaterial(Material mat, Shader oldShader, Shader newShader)
234  {
235  // _Emission property is lost after assigning, transfer it before assigning the new shader
236  if (mat.HasProperty("_Emission"))
237  {
238  mat.SetColor("_EmissionColor", mat.GetColor("_Emission"));
239  }
240 
241  base.AssignNewShaderToMaterial(mat, oldShader, newShader);
242 
243  if (oldShader == null)
244  {
245  return;
246  }
247 
248  BlendMode blendMode = BlendMode.Opaque;
249 
250  bool standard = oldShader.name.Contains("Standard");
251  bool legacy = oldShader.name.Contains("Legacy Shaders/");
252  bool mobile = oldShader.name.Contains("Mobile/");
253 
254  bool transparent = oldShader.name.Contains("Transparent/");
255  bool cutout = oldShader.name.Contains("Transparent/Cutout/");
256  bool unlit = oldShader.name.Contains("Unlit");
257  bool directionalLightOnly = oldShader.name.Contains("DirectionalLight");
258  bool vertexLit = oldShader.name.Contains("VertexLit");
259  bool spec = !oldShader.name.Contains("Diffuse");
260 
261  if (standard)
262  {
263  SetMaterialLighting(mat, true, true, ShaderGUIUtils.TryGetToggle(mat, "_SpecularHighlights", true), true, true);
264  }
265  else if (mobile || legacy)
266  {
267  if (cutout)
268  {
269  blendMode = BlendMode.Cutout;
270  }
271  else if (transparent)
272  {
273  blendMode = BlendMode.Transparent;
274  }
275 
276  if (unlit)
277  {
278  SetMaterialLighting(mat, false, false, false, false, false);
279  }
280  else
281  {
282  //TODO: need to handle way more cases
283  SetMaterialLighting(mat, true, true, spec, !directionalLightOnly, vertexLit);
284  }
285 
286  SetMaterialBlendMode(mat, blendMode);
287  }
288  }
289 
290  protected virtual void SetMaterialLighting(Material mat, bool ambient, bool diffuse, bool specular, bool additional, bool perPixel)
291  {
292  mat.SetFloat("_UseAmbient", ambient ? 1.0f : 0.0f);
293  mat.SetFloat("_UseDiffuse", diffuse ? 1.0f : 0.0f);
294  mat.SetFloat("_SpecularHighlights", specular ? 1.0f : 0.0f);
295  mat.SetFloat("_Shade4", additional ? 1.0f : 0.0f);
296 
297  mat.SetFloat("_ForcePerPixel", perPixel ? 1.0f : 0.0f);
298  }
299 
300  protected virtual void SetMaterialBlendMode(Material mat, BlendMode blendMode)
301  {
302  switch (blendMode)
303  {
304  case BlendMode.Opaque:
305  mat.SetOverrideTag("RenderType", "");
306  mat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
307  mat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
308  mat.SetInt("_ZWrite", 1);
309  ShaderGUIUtils.SetKeyword(mat, "_ALPHATEST_ON", false);
310  mat.renderQueue = -1;
311  break;
312  case BlendMode.Cutout:
313  mat.SetOverrideTag("RenderType", "TransparentCutout");
314  mat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
315  mat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
316  mat.SetInt("_ZWrite", 1);
317  ShaderGUIUtils.SetKeyword(mat, "_ALPHATEST_ON", true);
318  mat.renderQueue = (int)UnityEngine.Rendering.RenderQueue.AlphaTest;
319  break;
320  case BlendMode.Transparent:
321  mat.SetOverrideTag("RenderType", "Transparent");
322  //non pre-multiplied alpha
323  mat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
324  mat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
325  mat.SetInt("_ZWrite", 1);
326  ShaderGUIUtils.SetKeyword(mat, "_ALPHATEST_ON", false);
327  mat.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
328  break;
329  case BlendMode.Advanced:
330  //user configured
331  break;
332  }
333  }
334 
335  protected virtual bool MaterialNeedsPerPixel(Material mat)
336  {
337  bool usesBumpMap = mat.GetTexture("_BumpMap");
338  bool usesSpecMap = mat.GetTexture("_SpecularMap");
339  bool usesGlossMap = mat.GetTexture("_GlossMap");
340  bool usesEmissionMap = mat.GetTexture("_EmissionMap");
341 
342  return (usesBumpMap || usesSpecMap || usesGlossMap || usesEmissionMap);
343  }
344 
345  protected virtual void SetMaterialAutoPropertiesAndKeywords(Material mat)
346  {
347  ShaderGUIUtils.SetKeyword(mat, "_USEMAINTEX_ON", mat.GetTexture("_MainTex"));
348  ShaderGUIUtils.SetKeyword(mat, "_USEOCCLUSIONMAP_ON", mat.GetTexture("_OcclusionMap"));
349 
350  bool usesBumpMap = mat.GetTexture("_BumpMap");
351  bool usesSpecMap = mat.GetTexture("_SpecularMap");
352  bool usesGlossMap = mat.GetTexture("_GlossMap");
353  bool usesEmissionMap = mat.GetTexture("_EmissionMap");
354 
355  ShaderGUIUtils.SetKeyword(mat, "_USEBUMPMAP_ON", usesBumpMap);
356  ShaderGUIUtils.SetKeyword(mat, "_USESPECULARMAP_ON", usesSpecMap);
357  ShaderGUIUtils.SetKeyword(mat, "_USEGLOSSMAP_ON", usesGlossMap);
358 
359  ShaderGUIUtils.SetKeyword(mat, "_USEEMISSIONMAP_ON", usesEmissionMap);
360 
361  if (usesBumpMap || usesSpecMap || usesGlossMap || usesEmissionMap)
362  {
363  mat.SetFloat("_ForcePerPixel", 1.0f);
364  }
365 
366  var texScaleOffset = mat.GetVector("_TextureScaleOffset");
367  bool usesScale = texScaleOffset.x != 1.0f || texScaleOffset.y != 1.0f;
368  bool usesOffset = texScaleOffset.z != 0.0f || texScaleOffset.w != 0.0f;
369 
370  ShaderGUIUtils.SetKeyword(mat, "_MainTex_SCALE_ON", usesScale);
371  ShaderGUIUtils.SetKeyword(mat, "_MainTex_OFFSET_ON", usesOffset);
372  }
373 
374  protected virtual void CacheMainProperties(MaterialProperty[] props)
375  {
376  blendMode = FindProperty("_Mode", props);
377 
378  vertexColorEnabled = FindProperty("_UseVertexColor", props);
379  mainColorEnabled = FindProperty("_UseMainColor", props);
380  mainColor = FindProperty("_Color", props);
381  mainTexture = FindProperty("_MainTex", props);
382  alphaCutoff = FindProperty("_Cutoff", props);
383 
384  occlusionMap = FindProperty("_OcclusionMap", props);
385 
386  ambientLightingEnabled = FindProperty("_UseAmbient", props);
387  diffuseLightingEnabled = FindProperty("_UseDiffuse", props);
388  useAdditionalLightingData = FindProperty("_Shade4", props);
389  perPixelLighting = FindProperty("_ForcePerPixel", props);
390 
391  specularLightingEnabled = FindProperty("_SpecularHighlights", props);
392  specularColor = FindProperty("_SpecColor", props);
393  specular = FindProperty("_Specular", props);
394  specularMap = FindProperty("_SpecularMap", props);
395 
396  gloss = FindProperty("_Gloss", props);
397  glossMap = FindProperty("_GlossMap", props);
398 
399  normalMap = FindProperty("_BumpMap", props);
400 
401  reflectionsEnabled = FindProperty("_UseReflections", props);
402  cubeMap = FindProperty("_CubeMap", props);
403  reflectionScale = FindProperty("_ReflectionScale", props);
404  calibrationSpaceReflections = FindProperty("_CalibrationSpaceReflections", props);
405 
406  rimLightingEnabled = FindProperty("_UseRimLighting", props);
407  rimPower = FindProperty("_RimPower", props);
408  rimColor = FindProperty("_RimColor", props);
409 
410  emissionColorEnabled = FindProperty("_UseEmissionColor", props);
411  emissionColor = FindProperty("_EmissionColor", props);
412  emissionMap = FindProperty("_EmissionMap", props);
413 
414  textureScaleAndOffset = FindProperty("_TextureScaleOffset", props);
415 
416  srcBlend = FindProperty("_SrcBlend", props);
417  dstBlend = FindProperty("_DstBlend", props);
418  blendOp = FindProperty("_BlendOp", props);
419  }
420 
421  protected virtual void CacheOutputConfigurationProperties(MaterialProperty[] props)
422  {
423  cullMode = FindProperty("_Cull", props);
424  zTest = FindProperty("_ZTest", props);
425  zWrite = FindProperty("_ZWrite", props);
426  colorWriteMask = FindProperty("_ColorWriteMask", props);
427  }
428 
429  protected static class Styles
430  {
431  public static string renderingMode = "Rendering Mode";
432  public static readonly string[] blendNames = Enum.GetNames(typeof(BlendMode));
433 
434  public static GUIContent vertexColorEnabled = new GUIContent("Vertex Color", "Utilize vertex color from the model?");
435  public static GUIContent main = new GUIContent("Albedo", "Albedo (RGB) and Transparency (A)");
436  public static GUIContent alphaCutoffText = new GUIContent("Alpha Cutoff", "Threshold for alpha cutoff");
437 
438  public static GUIContent occlusionMap = new GUIContent("Occlusion Map", "Additional texture to be overlaid on the main texture");
439 
440  public static GUIContent ambientLightingEnabled = new GUIContent("Ambient", "Scene ambient lighting");
441  public static GUIContent diffuseLightingEnabled = new GUIContent("Diffuse", "Diffuse (lambertian) lighting from directional lights");
442  public static GUIContent useAdditionalLighingData = new GUIContent("Point and Spot", "Apply lighting from point and spot lights (expensive)");
443  public static GUIContent perPixelLighting = new GUIContent("Per-Pixel lighting", "Light objects per-pixel instead of per-vertex - using any lighting affecting map will force this on");
444 
445  public static GUIContent specularLightingEnabled = new GUIContent("Specular Highlights", "Specular (blinn-phong) lighting from directional lights");
446  public static GUIContent specularColor = new GUIContent(" Color", "Tint to apply to specular highlights");
447  public static GUIContent specular = new GUIContent("Power", "Specular Power - using a map will turn on per-pixel lighting");
448  public static GUIContent gloss = new GUIContent("Gloss", "Specular Scale - using a map will turn on per-pixel lighting");
449 
450  public static GUIContent normalMap = new GUIContent("Normal Map", "Normal Map - will turn on per-pixel lighting");
451 
452  public static GUIContent reflectionsEnabled = new GUIContent("Reflections", "Cube map based reflections");
453  public static GUIContent cubeMap = new GUIContent("Cube Map", "Cube map lookup for reflections");
454  public static GUIContent reflectionScale = new GUIContent("Scale", "Reflection strength");
455  public static GUIContent calibrationSpaceReflections = new GUIContent("In calibration space", "Keeps reflections consistent across different calibrations");
456 
457  public static GUIContent rimLightingEnabled = new GUIContent("Rim Lighting", "Side lighting");
458  public static GUIContent rimPower = new GUIContent("Power", "Power of rim lighting");
459  public static GUIContent rimColor = new GUIContent("Color", "Color of rim lighting");
460 
461  public static GUIContent emission = new GUIContent("Emission", "Emission (RGB)");
462 
463  public static GUIContent textureScaleAndOffset = new GUIContent("Texture Scale and Offset", "Applies to all textures");
464 
465  public static GUIContent srcBlend = new GUIContent("Source Blend", "Blend factor for transparency, etc.");
466  public static GUIContent dstBlend = new GUIContent("Destination Blend", "Blend factor for transparency, etc.");
467  public static GUIContent blendOp = new GUIContent("Blend Operation", "Blend operation for transparency, etc.");
468 
469  public static GUIContent cullMode = new GUIContent("Culling Mode", "Type of culling to apply to polygons - typically this is set to backfacing");
470  public static GUIContent zTest = new GUIContent("Z Test", "Depth buffer check type - output is not written if this is false");
471  public static GUIContent zWrite = new GUIContent("Z Write", "When to write to the depth buffer");
472  public static GUIContent colorWriteMask = new GUIContent("Color Write Mask", "Restricts output to specified color channels only");
473  }
474 
475  public enum BlendMode
476  {
477  Opaque,
478  Cutout,
479  Transparent,
480  Advanced
481  }
482  }
483 }
virtual void CacheOutputConfigurationProperties(MaterialProperty[] props)
Editor for FastConfigurable shader
virtual void ShowBlendModeGUI(MaterialEditor matEditor)
virtual bool MaterialNeedsPerPixel(Material mat)
static bool TryGetToggle(Material material, string property, bool defaultVal)
virtual void SetMaterialBlendMode(Material mat, BlendMode blendMode)
virtual void ShowOutputConfigurationGUI(MaterialEditor matEditor)
static void BeginHeaderProperty(MaterialEditor matEditor, string headerText, MaterialProperty prop)
override void AssignNewShaderToMaterial(Material mat, Shader oldShader, Shader newShader)
virtual void CacheMainProperties(MaterialProperty[] props)
virtual void SetMaterialAutoPropertiesAndKeywords(Material mat)
override void OnGUI(MaterialEditor matEditor, MaterialProperty[] props)
static void BeginHeader(string headerText)
virtual void SetMaterialLighting(Material mat, bool ambient, bool diffuse, bool specular, bool additional, bool perPixel)
static Rect TextureWithToggleableColorSingleLine(MaterialEditor matEditor, GUIContent label, MaterialProperty textureProp, MaterialProperty colorToggleProp, MaterialProperty colorProp)
Helper class for custom material editors
static void TextureScaleOffsetVector4Property(MaterialEditor matEditor, MaterialProperty scaleOffsetProp)
static Rect TextureWithToggleableColorAutoScaleOffsetSingleLine(MaterialEditor matEditor, GUIContent label, MaterialProperty textureProp, MaterialProperty colorToggleProp, MaterialProperty colorProp, MaterialProperty scaleOffsetProp)
static void SetKeyword(Material mat, string keyword, bool state)
Helper class for custom shader editors
virtual void ShowMainGUI(MaterialEditor matEditor)