技美在调shader的时候可能不太擅长C#编辑面板的代码,所以有了这篇文章。我封装了一个通用的着色器GUI面板,这样就可以不需要写C#代码了,实现的过程中试图解决了这几个问题。
1.视图解决分组面板展开与缩进
2.if标签与原生标签的混合
我看了下编辑器下C#的代码自定义MaterialPropertyDrawer虽然也可以实现分组,但是无法与原生标签嵌套混合,所以改变了一下思路,在面板中如果有if标签,并且Foldout没有展开不进行绘制。
直接上代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
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标签来实现分组,与原生标签进行混合排版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
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”
这样以后就技美就不需要在写任何GUI面板了代码了,shader面板的原生标签可以参考这里 https://docs.unity3d.com/ScriptReference/MaterialPropertyDrawer.html
以上代码我在项目中简单的测试过,欢迎大家提出一键与建议~
- 本文固定链接: https://www.xuanyusong.com/archives/4769
- 转载请注明: 雨松MOMO 于 雨松MOMO程序研究院 发表
捐 赠写博客不易,如果您想请我喝一杯星巴克的话?就进来看吧!
感谢大佬的分享捏,十分简洁,不像有些太花里胡哨的中看不中用
感谢大佬的分享,很有用!
请不要使用纯英文评论
赞,还缺一个C#面板的