20

Unity3D研究院之材质Shader通用面板(一百二十一)

 3 years ago
source link: https://www.xuanyusong.com/archives/4769
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Unity3D研究院之材质Shader通用面板(一百二十一)

技美在调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;
                                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);
                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();

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK