首页 >Unity3D频道 >【Unity3D研究院之游戏开发】 > 不写GUI面板自由拓展Lit着色器
2022
03-17

不写GUI面板自由拓展Lit着色器

在URP中PBR的材质是Lit.shader,由于项目组需要拓展不得不仿照它的写法在写一堆C#的代码来配合面板的显示,一方面容易出BUG另一方面非常麻烦。

首先复制一个Lit.shader改成MyLit.shader放到Asset目录下,Properties属性面板中下面写入

Properties
{
   //...

    [ext][Foldout]  _MytestName("溶解面板",Range (0,1)) = 0
    [ext][if(_MytestName)] [Toggle(GAME_TEST)] _Mytest ("启动溶解宏", Float) = 0
    [ext][if(_MytestName)] _Value("溶解参数1",Range (0,1)) = 0
    [ext][if(_MytestName)] [SingleLine] _MainTex2 ("溶解图", 2D) = "white" {}
    [ext][if(_MytestName)] [SingleLine] [Normal] _MainTex3 ("溶解图2", 2D) = "white" {}
    [ext][if(_MytestName)] [PowerSlider(3.0)] _Shininess ("溶解参数3", Range (0.01, 1)) = 0.08
    [ext][if(_MytestName)] [IntRange] _Alpha ("溶解参数4", Range (0, 255)) = 100

    [ext][Foldout] _Mytest2Name("特殊面板",Range (0,1)) = 0
    [ext][if(_Mytest2Name)] [Toggle] _Mytest2 ("启动特殊宏", Float) = 0
    [ext][if(_Mytest2Name)] _FirstColor("特殊颜色", Color) = (1, 1, 1, 1)
    [ext][if(_Mytest2Name)] _FirstValue("特殊向量", Vector) = (1, 1, 1, 1)
}

 

[ext]标签用于区分这个属性是我们新加的还是URP自带的。

[Foldout]标签用于面板展开关闭

[if(xxx)]标签表示将一种效果所用到的属性归类。

在Shader的最下面使用自己的面板

CustomEditor “LitShader”

由于原版的LitShader.cs是内部类,需要拷贝出来一份,我这里使用partial类将它们分开。如下代码所示

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;


partial class LitShader : BaseShaderGUI
{
    //自定义效果-单行显示图片
    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;
        }
    }

    static Dictionary<string, MaterialProperty> s_MaterialProperty = new Dictionary<string, MaterialProperty>();
    static List<MaterialData> s_List = new List<MaterialData>();
    public override void OnGUI(MaterialEditor materialEditorIn, MaterialProperty[] properties)
    {
        base.OnGUI(materialEditorIn, properties);


        EditorGUILayout.Space();

        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];
            var attributes = shader.GetPropertyAttributes(i);
            foreach (var item in attributes)
            {
                if (item.Contains("ext"))
                {
                    if (!s_MaterialProperty.ContainsKey(propertie.name))
                    {
                        s_MaterialProperty[propertie.name] = propertie;
                        s_List.Add(new MaterialData() { prop = propertie, indentLevel = false });
                        
                    }
                }
                else if (item.Contains("Toggle"))
                {
                    //根据Toggle标签每帧启动宏
                    if (s_MaterialProperty.TryGetValue(propertie.name, out var __))
                    {
                        if (propertie.type == MaterialProperty.PropType.Float)
                        {
                            string keyword = "";
                            Match match = Regex.Match(item, @"(w+)s*((.*))");
                            if (match.Success)
                                keyword = match.Groups[2].Value.Trim();
                            if(string.IsNullOrEmpty(keyword))
                                keyword = propertie.name.ToUpperInvariant() + "_ON";
                            foreach (Material material in propertie.targets)
                            {
                                if (propertie.floatValue == 1.0f)
                                    material.EnableKeyword(keyword);
                                else
                                    material.DisableKeyword(keyword);
                            }
                        }
                    }
                }
                else 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);
                            }
                            else
                                s_List[s_List.Count - 1].indentLevel = true;
                        }
                    }
                }
            }
        }
        PropertiesDefaultGUI(materialEditor, s_List);
    }

    public class MaterialData
    {
        public MaterialProperty prop;
        public bool indentLevel = false;
    }
    public void PropertiesDefaultGUI(MaterialEditor materialEditor, List<MaterialData> props)
    {
        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--;
            }
        }
    }
}

 

OK,面板已经拓展在原版Lit.shader下面了,开关启动Toggle就可以不需要在写GUI面板了。

不写GUI面板自由拓展Lit着色器 - 雨松MOMO程序研究院 - 1

最后编辑:
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
捐 赠写博客不易,如果您想请我喝一杯星巴克的话?就进来看吧!

留下一个回复

你的email不会被公开。 必填项已用 * 标注。