技美在调shader的时候可能不太擅长C#编辑面板的代码,所以有了这篇文章。我封装了一个通用的着色器GUI面板,这样就可以不需要写C#代码了,实现的过程中试图解决了这几个问题。
1.视图解决分组面板展开与缩进
2.if标签与原生标签的混合
我看了下编辑器下C#的代码自定义MaterialPropertyDrawer虽然也可以实现分组,但是无法与原生标签嵌套混合,所以改变了一下思路,在面板中如果有if标签,并且Foldout没有展开不进行绘制。
直接上代码
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Text.RegularExpressions;
using UnityEngine.Rendering;
using System;
//自定义效果-单行显示图片
internal class SingleLineDrawer : MaterialPropertyDrawer
{
public override void OnGUI(Rect position, MaterialProperty prop, GUIContent label, MaterialEditor editor)
{
editor.TexturePropertySingleLine(label, prop);
}
public override float GetPropertyHeight(MaterialProperty prop, string label, MaterialEditor editor)
{
return 0;
}
}
//自定义效果-折行显示图片
internal class FoldoutDrawer : MaterialPropertyDrawer
{
bool showPosition;
public override void OnGUI(Rect position, MaterialProperty prop, string label, MaterialEditor editor)
{
showPosition = EditorGUILayout.Foldout(showPosition, label);
prop.floatValue = Convert.ToSingle(showPosition);
}
public override float GetPropertyHeight(MaterialProperty prop, string label, MaterialEditor editor)
{
return 0;
}
}
public class CustomShaderGUI : ShaderGUI
{
public class MaterialData
{
public MaterialProperty prop;
public bool indentLevel = false;
}
static Dictionary<string, MaterialProperty> s_MaterialProperty = new Dictionary<string, MaterialProperty>();
static List<MaterialData> s_List = new List<MaterialData>();
public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
{
Shader shader = (materialEditor.target as Material).shader;
s_List.Clear();
s_MaterialProperty.Clear();
for (int i = 0; i < properties.Length; i++)
{
var propertie = properties[i];
s_MaterialProperty[propertie.name] = propertie;
s_List.Add(new MaterialData() { prop = propertie, indentLevel = false });
var attributes = shader.GetPropertyAttributes(i);
foreach (var item in attributes)
{
if (item.StartsWith("if"))
{
Match match = Regex.Match(item, @"(\w+)\s*\((.*)\)");
if (match.Success)
{
var name = match.Groups[2].Value.Trim();
if (s_MaterialProperty.TryGetValue(name, out var a))
{
if (a.floatValue == 0f) {
//如果有if标签,并且Foldout没有展开不进行绘制
s_List.RemoveAt(s_List.Count - 1);
break;
}
else
s_List[s_List.Count - 1].indentLevel = true;
}
}
}
}
}
/*如果不需要展开子节点像右缩进,可以直接调用base方法
base.OnGUI(materialEditor, s_List.ToArray());*/
PropertiesDefaultGUI(materialEditor, s_List);
}
private static int s_ControlHash = "EditorTextField".GetHashCode();
public void PropertiesDefaultGUI(MaterialEditor materialEditor, List<MaterialData> props)
{
var f = materialEditor.GetType().GetField("m_InfoMessage", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
if (f != null)
{
string m_InfoMessage = (string)f.GetValue(materialEditor);
materialEditor.SetDefaultGUIWidths();
if (m_InfoMessage != null)
{
EditorGUILayout.HelpBox(m_InfoMessage, MessageType.Info);
}
else
{
GUIUtility.GetControlID(s_ControlHash, FocusType.Passive, new Rect(0f, 0f, 0f, 0f));
}
}
for (int i = 0; i < props.Count; i++)
{
MaterialProperty prop = props[i].prop;
bool indentLevel = props[i].indentLevel;
if ((prop.flags & (MaterialProperty.PropFlags.HideInInspector | MaterialProperty.PropFlags.PerRendererData)) == MaterialProperty.PropFlags.None)
{
float propertyHeight = materialEditor.GetPropertyHeight(prop, prop.displayName);
Rect controlRect = EditorGUILayout.GetControlRect(true, propertyHeight, EditorStyles.layerMaskField);
if(indentLevel) EditorGUI.indentLevel++;
materialEditor.ShaderProperty(controlRect, prop, prop.displayName);
if (indentLevel) EditorGUI.indentLevel--;
}
}
EditorGUILayout.Space();
EditorGUILayout.Space();
if (SupportedRenderingFeatures.active.editableMaterialRenderQueue)
{
materialEditor.RenderQueueField();
}
materialEditor.EnableInstancingField();
materialEditor.DoubleSidedGIField();
}
}
实现展开效果
shader的GUI代码,使用foldout和if标签来实现分组,与原生标签进行混合排版
Properties
{
[Foldout] _MytestName("溶解面板",Range (0,1)) = 0
[if(_MytestName)] [Toggle] _Mytest ("启动溶解宏", Float) = 0
[if(_MytestName)] _Value("溶解参数1",Range (0,1)) = 0
[if(_MytestName)] [SingleLine] _MainTex2 ("溶解图", 2D) = "white" {}
[if(_MytestName)] [SingleLine] [Normal] _MainTex3 ("溶解图2", 2D) = "white" {}
[if(_MytestName)] [PowerSlider(3.0)] _Shininess ("溶解参数3", Range (0.01, 1)) = 0.08
[if(_MytestName)] [IntRange] _Alpha ("溶解参数4", Range (0, 255)) = 100
[Foldout] _Mytest1Name("扰动面板",Range (0,1)) = 0
[if(_Mytest1Name)] [Toggle] _Mytest1 ("启动扰动宏", Float) = 0
[if(_Mytest1Name)] _Value1("扰动参数1",Range (0,1)) = 0
[if(_Mytest1Name)] [SingleLine] _MainTex4 ("扰动图", 2D) = "white" {}
[if(_Mytest1Name)] [SingleLine] [Normal] _MainTex5 ("扰动图2", 2D) = "white" {}
[if(_Mytest1Name)] [Header(A group of things)][Space(10)] _Prop1 ("扰动参数2", Float) = 0
[if(_Mytest1Name)] [KeywordEnum(Red, Green, Blue)] _ColorMode ("扰动颜色枚举", Float) = 0
[Foldout] _Mytest2Name("特殊面板",Range (0,1)) = 0
[if(_Mytest2Name)] [Toggle] _Mytest2 ("启动特殊宏", Float) = 0
[if(_Mytest2Name)] _FirstColor("特殊颜色", Color) = (1, 1, 1, 1)
}
shader的底部写上 CustomEditor “CustomShaderGUI” 文章来源