• 在URP管线中添加ShaderMaterial自定义GUI的方法


    编写GUI面板

    1. 新建GUI子面板

    using UnityEngine;
    using UnityEngine.Rendering;
    
    namespace UnityEditor.Rendering.Universal.ShaderGUI
    {
        internal class CP_XXXOutLineGUI
        {
            public static class Styles{}
    
            public struct LitProperties
            {
                public LitProperties(MaterialProperty[] properties){}
            }
            public static void DoDetailArea(LitProperties properties, MaterialEditor materialEditor){}
            public static void SetMaterialKeywords(Material material){}
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2. 将在Shader关联的GUI面板中注册该子面板

    internal class CP_XXXLitShader : BaseShaderGUI
    {
    	//声明子面板属性
        private CP_XXXOutLineGUI.LitProperties litXXXOutLineProperties;
    
    
        public override void FillAdditionalFoldouts(MaterialHeaderScopeList materialScopesList)
        {
      		
        }
      	public override void FindProperties(MaterialProperty[] properties)
        {
            base.FindProperties(properties);
            // 新建子面板属性
            litXXXOutLineProperties = new CP_XXXOutLineGUI.LitProperties(properties);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3. 注册列表头部展开区域

    FillAdditionalFoldouts(MaterialHeaderScopeList)会在继承BaseShaderGUI的类中由系统自动调用,它传入当前材质GUI的列表实例,我们通过RegisterHeaderScope可以添加新的列表项目。

    public override void FillAdditionalFoldouts(MaterialHeaderScopeList materialScopesList)
    {
    	materialScopesList.RegisterHeaderScope(LitDetailGUI.Styles.detailInputs, Expandable.Details, _ => LitDetailGUI.DoDetailArea(litDetailProperties, materialEditor));
    }
    
    • 1
    • 2
    • 3
    • 4

    注册函数:materialScopesList.RegisterHeaderScope(GUIContent, TEnum, Action)
    在这里插入图片描述

    (1)创建头部列表GUIContext对象

    public GUIContent(...);
    - string text	文本
    - Texture image	图片
    - string tooltip 鼠标指针当前悬停在其上或具有键盘焦点的控件的工具提示。
    
    • 1
    • 2
    • 3
    • 4
    internal class CP_XXXOutLineGUI{
    	public static class Styles
    	{
    	     public static readonly GUIContent OutLineInputs = new GUIContent("Outline Inputs",
    	        "This Let You Open The OutLine Panel");
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    (2)设置掩码

    掩码设置要求,掩码按照位来设置,每个掩码占一个位字节。
    如:在URP内置代码BaseShaderGUI:ShaderGUI类中已经设置了部分掩码

    [URPHelpURL("shaders-in-universalrp")]
    protected enum Expandable
    {
        SurfaceOptions = 1 << 0,
        SurfaceInputs = 1 << 1,
        Advanced = 1 << 2,
        Details = 1 << 3,
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    其中SurfaceOptions、SurfaceInputs、Advanced 都已被系统注册,在URPShader的LitShader(其他Shader中可能也有)中,Details也在重写函数FillAdditionalFoldouts中被注册

    materialScopesList.RegisterHeaderScope(
    	LitDetailGUI.Styles.detailInputs, 
    	Expandable.Details, 
    	_ => LitDetailGUI.DoDetailArea(litDetailProperties, materialEditor)
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5

    我们仿照URP标准库中的写法,添加自定义掩码的扩展

    在CP_XXXLitShader中自定义
    protected enum AdditionalExpandable
    {
    	...其他掩码(163264128256)
    	OutlineMask = 512,
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (3) 注册列表头部区域

    public override void FillAdditionalFoldouts(MaterialHeaderScopeList materialScopesList)
    {
        materialScopesList.RegisterHeaderScope(
        	CP_XXXOutLineGUI.Styles.OutLineInputs, 
        	AdditionalExpandable.OutlineMask, 
        	_ => CP_XXXOutLineGUI.DoDetailArea(litXXXOutLineProperties, materialEditor));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    现在返回Unity,查看Shader列表。发现已经有了列表头显示。
    在这里插入图片描述

    4. 添加属性列表的显示

    首先OutLine需要的参数有OutLineColor和OutLineSize。
    首先在LitProperties中声明该属性,并绑定该属性的Shader名称。

    public struct LitProperties
    {
        public MaterialProperty OutLineColor;
        public MaterialProperty OutLineSize;
    
    
        public LitProperties(MaterialProperty[] properties)
        {
            OutLineColor = BaseShaderGUI.FindProperty("_OutlineColor", properties, false);//false-->未找到不抛出异常
            OutLineSize  = BaseShaderGUI.FindProperty("_OutlineSize", properties, false); 
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    当展开OutLine下拉框时:调用public static void DoDetailArea(LitProperties properties, MaterialEditor materialEditor)函数

    public static void DoDetailArea(LitProperties properties, MaterialEditor materialEditor)
    {
        materialEditor.ColorProperty(properties.OutLineColor, Styles.OutLineColorContent.text);
        materialEditor.FloatProperty(properties.OutLineSize, Styles.OutLineSizeContent.text);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述
    展开显示
    在这里插入图片描述
    修改属性,Shader中参数被修改。

    其他类型

    // 按钮类型
    bool depthFadeEnabled = EditorGUILayout.Toggle(Styles.depthFadeEnabledText, properties.depthFadeEnabled.floatValue > 0.5f);
    properties.depthFadeEnabled.floatValue = depthFadeEnabled ? 1.0f : 0.0f;
    
    //滑轮类型
    properties.depthFadeDist.floatValue = 
    	EditorGUILayout.Slider(Styles.depthFadeDistText, properties.depthFadeDist.floatValue, 0.01f, 10.0f);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    其他参照Unity官方文档
    https://docs.unity.cn/cn/2019.4/ScriptReference/EditorGUILayout.html

    整体架构

    using System;
    using UnityEngine;
    using UnityEditor;
    
    namespace UnityEditor.Rendering.Universal.ShaderGUI
    {
    
        internal class CP_DragonLitShader : BaseShaderGUI
        {
            protected enum AdditionalExpandable
            {
                SnowInputs = 16,
                DepthFadeInputs = 32,
                。。。
            }
    
    
            private LitGUI.LitProperties litProperties;
            private CP_LitDetailGUI.LitProperties litDetailProperties;
            private CP_SnowGUI.LitProperties litSnowProperties;
           。。。
    
    
            public override void FillAdditionalFoldouts(MaterialHeaderScopeList materialScopesList)
            {
                materialScopesList.RegisterHeaderScope(CP_LitDetailGUI.Styles.detailInputs, Expandable.Details, _ => CP_LitDetailGUI.DoDetailArea(litDetailProperties, materialEditor));
                materialScopesList.RegisterHeaderScope(CP_DragonColorGUI.Styles.inputs, AdditionalExpandable.DragonColorInputs, _ => CP_DragonColorGUI.DoDetailArea(litDragonColorProperties, materialEditor));
                materialScopesList.RegisterHeaderScope(CP_SnowGUI.Styles.snowInputs, AdditionalExpandable.SnowInputs, _ => CP_SnowGUI.DoDetailArea(litSnowProperties, materialEditor));
                。。。
    
            }
    
            // collect properties from the material properties
            public override void FindProperties(MaterialProperty[] properties)
            {
                base.FindProperties(properties);
                litProperties = new LitGUI.LitProperties(properties);
                litDetailProperties = new CP_LitDetailGUI.LitProperties(properties);
                litDragonColorProperties = new CP_DragonColorGUI.LitProperties(properties);
                litSnowProperties = new CP_SnowGUI.LitProperties(properties);
                。。。
            }
    
            // material changed check
            public override void ValidateMaterial(Material material)
            {
                SetMaterialKeywords(material, LitGUI.SetMaterialKeywords, CP_LitDetailGUI.SetMaterialKeywords);
                CP_SnowGUI.SetMaterialKeywords(material);
               。。。
            }
    
    
            // material main surface options
            public override void DrawSurfaceOptions(Material material)
            {
                if (material == null)
                    throw new ArgumentNullException("material");
    
                // Use default labelWidth
                EditorGUIUtility.labelWidth = 0f;
    
                // Detect any changes to the material
                EditorGUI.BeginChangeCheck();
                if (litProperties.workflowMode != null)
                {
                    DoPopup(LitGUI.Styles.workflowModeText, litProperties.workflowMode, Enum.GetNames(typeof(LitGUI.WorkflowMode)));
                }
                if (EditorGUI.EndChangeCheck())
                {
                    foreach (var obj in blendModeProp.targets)
                        MaterialChanged((Material)obj);
                }
                base.DrawSurfaceOptions(material);
            }
    
            // material main surface inputs
            public override void DrawSurfaceInputs(Material material)
            {
                base.DrawSurfaceInputs(material);
                LitGUI.Inputs(litProperties, materialEditor, material);
                DrawEmissionProperties(material, true);
                DrawTileOffset(materialEditor, baseMapProp);
            }
    
            // material main advanced options
            public override void DrawAdvancedOptions(Material material)
            {
                if (litProperties.reflections != null && litProperties.highlights != null)
                {
                    EditorGUI.BeginChangeCheck();
                    materialEditor.ShaderProperty(litProperties.highlights, LitGUI.Styles.highlightsText);
                    materialEditor.ShaderProperty(litProperties.reflections, LitGUI.Styles.reflectionsText);
                    if (EditorGUI.EndChangeCheck())
                    {
                        MaterialChanged(material);
                    }
                }
    
                base.DrawAdvancedOptions(material);
            }
    
            public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader)
            {
                if (material == null)
                    throw new ArgumentNullException("material");
    
                // _Emission property is lost after assigning Standard shader to the material
                // thus transfer it before assigning the new shader
                if (material.HasProperty("_Emission"))
                {
                    material.SetColor("_EmissionColor", material.GetColor("_Emission"));
                }
    
                base.AssignNewShaderToMaterial(material, oldShader, newShader);
    
                if (oldShader == null || !oldShader.name.Contains("Legacy Shaders/"))
                {
                    SetupMaterialBlendMode(material);
                    return;
                }
    
                SurfaceType surfaceType = SurfaceType.Opaque;
                BlendMode blendMode = BlendMode.Alpha;
                if (oldShader.name.Contains("/Transparent/Cutout/"))
                {
                    surfaceType = SurfaceType.Opaque;
                    material.SetFloat("_AlphaClip", 1);
                }
                else if (oldShader.name.Contains("/Transparent/"))
                {
                    // NOTE: legacy shaders did not provide physically based transparency
                    // therefore Fade mode
                    surfaceType = SurfaceType.Transparent;
                    blendMode = BlendMode.Alpha;
                }
                material.SetFloat("_Surface", (float)surfaceType);
                material.SetFloat("_Blend", (float)blendMode);
    
                if (oldShader.name.Equals("Standard (Specular setup)"))
                {
                    material.SetFloat("_WorkflowMode", (float)LitGUI.WorkflowMode.Specular);
                    Texture texture = material.GetTexture("_SpecGlossMap");
                    if (texture != null)
                        material.SetTexture("_MetallicSpecGlossMap", texture);
                }
                else
                {
                    material.SetFloat("_WorkflowMode", (float)LitGUI.WorkflowMode.Metallic);
                    Texture texture = material.GetTexture("_MetallicGlossMap");
                    if (texture != null)
                        material.SetTexture("_MetallicSpecGlossMap", texture);
                }
    
                MaterialChanged(material);
            }
        }
    }
    
    
    • 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
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
  • 相关阅读:
    HTML期末作业 蛋糕bootstrap响应式网站html+css+javascript+jquery+bootstarp
    SpringBoot(三) - Ribbon客户端负载均衡,Zuul网关,Config配置中心
    在家自己动手修电视解决屏幕跳动问题
    js array数组json去重
    instanceOf原理及手动实现
    Grafana+Prometheus+Windows_exporter+Mysql_exporter
    GPC规范--安全域基础概念
    微信小程序-微信授权登录
    c语言回文数
    【小海实习日记】Git使用规范
  • 原文地址:https://blog.csdn.net/weixin_44518102/article/details/133940978