如果是自定义shader的通用面板可以看我之前的文章 Unity3D研究院之材质Shader通用面板(一百二十一) 这篇文章和它的原理是一样的。
首先shader graph有个很麻烦的问题就是自定义的keyword始终在面板的最下面不能和普通的属性进行排序,而且也无法展开分组的功能。为了实现通用面板,我们要定义一定的规则
XX面板 溶解面板
XX参数1 溶解参数1
XX参数2 溶解参数2
如果命名中包含面板会特意提出来,如果下面的属性包含XX部分则合并在一个分组中,自定义的keyword始终在最下面的问题,有可以根据命名的规则来进行排序,我会始终让宏在分页的第一位。
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 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
using System; using System.Collections.Generic; using System.Text.RegularExpressions; using UnityEditor; using UnityEngine; using UnityEngine.Rendering; public class CustomShaderGraphGUI : ShaderGUI { public class GraphData { public string groupName; //组名 public MaterialProperty title; //标题 public List<GraphData> child;//表示有子节点 } static Dictionary<string, GraphData> s_GraphProperty = new Dictionary<string, GraphData>(); public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties) { Shader shader = (materialEditor.target as Material).shader; s_GraphProperty.Clear(); for (int i = 0; i < properties.Length; i++) { var propertie = properties[i]; var displayName = propertie.displayName; GraphData data = new GraphData() { title = propertie }; if (TryGetGroupName(displayName, out var groupName)) { if (!s_GraphProperty.TryGetValue(groupName, out var graph)) { data.child = new List<GraphData>(); data.groupName = groupName; s_GraphProperty[groupName] = data; } else { var attributes = shader.GetPropertyAttributes(i); bool keyword = Array.FindIndex(attributes, (t) => (t == "Toggle" || t.StartsWith("KeywordEnum"))) >= 0; if (keyword) graph.child.Insert(0, data); else graph.child.Add(data); } } else { s_GraphProperty[displayName] = data; } } PropertiesDefaultGUI(materialEditor); } private static int s_ControlHash = "EditorTextField".GetHashCode(); public void PropertiesDefaultGUI(MaterialEditor materialEditor) { 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)); } } foreach (var props in s_GraphProperty.Values) { MaterialProperty prop = props.title; if ((prop.flags & (MaterialProperty.PropFlags.HideInInspector | MaterialProperty.PropFlags.PerRendererData)) == MaterialProperty.PropFlags.None) { if(props.child!=null && props.child.Count > 0) { //如果发现有面板,使用Foldout来绘制 prop.floatValue = Convert.ToSingle(EditorGUILayout.Foldout(Convert.ToBoolean(prop.floatValue), prop.displayName)); if (prop.floatValue == 1f) { foreach (var child in props.child) { DrawGUI(materialEditor, child.title, true); } } } else { DrawGUI(materialEditor, prop, false); } } } EditorGUILayout.Space(); EditorGUILayout.Space(); if (SupportedRenderingFeatures.active.editableMaterialRenderQueue) { materialEditor.RenderQueueField(); } materialEditor.EnableInstancingField(); materialEditor.DoubleSidedGIField(); //unity 2020 新版本功能 ,老版本需要注释掉 materialEditor.EmissionEnabledProperty(); } void DrawGUI(MaterialEditor materialEditor, MaterialProperty prop, bool indentLevel) { 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--; } const string INSPECTOR_TXT = "面板"; bool TryGetGroupName(string displayName,out string groupName) { //根据displayName找到组名 if (displayName.Contains(INSPECTOR_TXT)) { groupName = Regex.Split(displayName, INSPECTOR_TXT, RegexOptions.IgnoreCase)[0]; return true; } foreach (var property in s_GraphProperty.Values) { if (!string.IsNullOrEmpty(property.groupName)){ if (displayName.StartsWith(property.groupName)) { groupName = property.groupName; return true; } } } groupName = string.Empty; return false; } } |
欢迎大家来测试
- 本文固定链接: https://www.xuanyusong.com/archives/4778
- 转载请注明: 雨松MOMO 于 雨松MOMO程序研究院 发表
捐 赠写博客不易,如果您想请我喝一杯星巴克的话?就进来看吧!