- Home /
Question by
$$anonymous$$ · Aug 05, 2016 at 10:50 AM ·
guishadercustom-inspectorcustom-shader
Custom Shader GUI problem
I am having getting this error when I switch on/off the toggle in the custom shader GUI.
Error Code:
InvalidOperationException: Operation is not valid due to the current state of the object
System.Collections.Generic.Stack`1[System.Boolean].Pop ()
UnityEditor.EditorGUI.EndChangeCheck () (at C:/buildslave/unity/build/Editor/Mono/EditorGUI.cs:234)
UnityEditor.MaterialEditor.PropertiesGUI () (at C:/buildslave/unity/build/Editor/Mono/Inspector/MaterialEditor.cs:1224)
UnityEditor.MaterialEditor.OnInspectorGUI () (at C:/buildslave/unity/build/Editor/Mono/Inspector/MaterialEditor.cs:235)
UnityEditor.InspectorWindow.DrawEditor (UnityEditor.Editor editor, Int32 editorIndex, Boolean rebuildOptimizedGUIBlock, System.Boolean& showImportedObjectBarNext, UnityEngine.Rect& importedObjectBarRect) (at C:/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:1231)
UnityEditor.DockArea:OnGUI()
My custom shadergui has this code:
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Linq;
using System.Text.RegularExpressions;
public abstract class EtlokShaderGUI : ShaderGUI
{
public class FeatureToggle
{
// The name the toggle will have in the inspector.
public string InspectorName;
// We will look for properties that contain this word, and hide them if we're not enabled.
public string InspectorPropertyHideTag;
// The keyword that the shader uses when this feature is enabled or disabled.
public string ShaderKeywordEnabled;
public string ShaderKeywordDisabled;
// The current state of this feature.
public bool Enabled;
public FeatureToggle(string InspectorName, string InspectorPropertyHideTag, string ShaderKeywordEnabled, string ShaderKeywordDisabled)
{
this.InspectorName = InspectorName;
this.InspectorPropertyHideTag = InspectorPropertyHideTag;
this.ShaderKeywordEnabled = ShaderKeywordEnabled;
this.ShaderKeywordDisabled = ShaderKeywordDisabled;
this.Enabled = false;
}
}
// A list of all the toggles that we have in this material editor.
protected List<FeatureToggle> Toggles = new List<FeatureToggle>();
// This function will be implemented in derived classes, and used to populate the list of toggles.
protected abstract void CreateToggleList();
public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
{
//base.OnGUI(materialEditor, properties);
Material targetMat = materialEditor.target as Material;
Shader shader = targetMat.shader;
string[] oldKeyWords = targetMat.shaderKeywords;
// Populate our list of toggles
//Toggles.Clear();
Toggles = new List<FeatureToggle>();
CreateToggleList();
// Update each toggle to enabled if it's enabled keyword is present. If it's enabled keyword is missing, we assume it's disabled.
for (int i = 0; i < Toggles.Count; i++)
{
Toggles[i].Enabled = oldKeyWords.Contains(Toggles[i].ShaderKeywordEnabled);
}
EditorGUI.BeginChangeCheck();
// Draw Non-toggleable values
for (int i = 0; i < ShaderUtil.GetPropertyCount(shader); i++)
{
ShaderPropertyImpl(materialEditor, properties, i, null);
}
// Draw toggles, then their values.
for (int s = 0; s < Toggles.Count; s++)
{
EditorGUILayout.Separator();
Toggles[s].Enabled = EditorGUILayout.BeginToggleGroup(Toggles[s].InspectorName, Toggles[s].Enabled);
if (Toggles[s].Enabled)
{
for (int i = 0; i < ShaderUtil.GetPropertyCount(shader); i++)
{
ShaderPropertyImpl(materialEditor, properties, i, Toggles[s]);
}
}
EditorGUILayout.EndToggleGroup();
}
if (EditorGUI.EndChangeCheck())
materialEditor.PropertiesChanged();
// If changes have been made, then apply them.
if (EditorGUI.EndChangeCheck())
{
// New list of key words.
List<string> newKeyWords = new List<string>();
// If true, add the enabled keyword (ending with _ON), if false, add the disabled keyword(ending with _OFF).
for (int i = 0; i < Toggles.Count; i++)
{
newKeyWords.Add(Toggles[i].Enabled ? Toggles[i].ShaderKeywordEnabled : Toggles[i].ShaderKeywordDisabled);
}
// Send the new list of keywords to the material, this will define what version of the shader to use.
targetMat.shaderKeywords = newKeyWords.ToArray();
EditorUtility.SetDirty(targetMat);
}
}
private void ShaderPropertyImpl(MaterialEditor matEditor, MaterialProperty[] matpropset, int propertyIndex, FeatureToggle currentToggle)
{
Material targetMat = matEditor.target as Material;
Shader shader = targetMat.shader;
string propertyDescription = ShaderUtil.GetPropertyDescription(shader, propertyIndex);
string propertyName = ShaderUtil.GetPropertyName(shader, propertyIndex);
// If current toggle is null, we only want to show properties that aren't already "owned" by a toggle,
// so if it is owned by another toggle, then return.
if (currentToggle == null)
{
for (int i = 0; i < Toggles.Count; i++)
{
if (Regex.IsMatch(propertyDescription, Toggles[i].InspectorPropertyHideTag, RegexOptions.IgnoreCase))
{
return;
}
}
}
// Only draw if we the current property is owned by the current toggle.
else if (!Regex.IsMatch(propertyDescription, currentToggle.InspectorPropertyHideTag, RegexOptions.IgnoreCase))
{
return;
}
// If we've gotten to this point, draw the shader property regulairly.
MaterialProperty matprop = ShaderGUI.FindProperty(propertyName, matpropset);
string matDisplayName = matprop.displayName;
matEditor.ShaderProperty(matprop, matDisplayName);
}
}
With the custom inspector of :
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class EtlokInspector : EtlokShaderGUI
{
protected override void CreateToggleList()
{
Toggles.Add(new FeatureToggle("DiffuseMap Enabled", "diffuse", "DIFFUSEMAP_ON", "DIFFUSEMAP_OFF"));
Toggles.Add(new FeatureToggle("AlphaMap Enabled", "alpha", "ALPHAMAP_ON", "ALPHAMAP_OFF"));
Toggles.Add(new FeatureToggle("SpecularMap Enabled", "specular", "SPECULAR_ON", "SPECULAR_OFF"));
Toggles.Add(new FeatureToggle("EnvironmentMap Enabled", "env", "ENVMAP_ON", "ENVMAP_OFF"));
Toggles.Add(new FeatureToggle("BumpMap Enabled", "bump", "BUMPMAP_ON", "BUMPMAP_OFF"));
Toggles.Add(new FeatureToggle("NormalMap Enabled", "normal", "NORMALMAP_ON", "NORMALMAP_OFF"));
Toggles.Add(new FeatureToggle("EmissiveMap Enabled", "emissive", "EMISSIVEMAP_ON", "EMISSIVEMAP_OFF"));
}
}
Comment
if I uncomment,
//base.OnGUI(materialEditor, properties);
I get duplicates of the existing properties in the Unity Shader window.
Your answer
