Unity - 搬砖日志 - MatierlaPropertyDrawer 中的参数如何匹配 - 自定义 Attribute 的参数提取

news2024/12/23 11:11:07

环境

Unity : 2020.3.37f1


搬一下砖,并记录,免得后续重新搬砖


完成的测试shader

Shader "Unlit/TestMyEnuMatAttributeShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        [MyEnumMatAttribute] _TestProp ("MyPropDraw no args", Float) = 1
        [MyEnumMatAttribute(Arg1)] _TestProp1 ("MyPropDraw with arg1", Float) = 1
        [MyEnumMatAttribute(Arg1,1,Arg2,2)] _TestProp2 ("MyPropDraw with multi args1", Float) = 1
        [MyEnumMatAttribute(Arg1,1.0,Arg2,2.0)] _TestProp3 ("MyPropDraw with multi args2", Float) = 1
        [MyEnumMatAttribute(Arg1,Arg2)] _TestProp4 ("MyPropDraw with multi args3", Float) = 1
        [MyEnumMatAttribute(Arg1,Arg2,Arg3)] _TestProp5 ("MyPropDraw with multi args4", Float) = 1
        [MyEnumMatAttribute(Arg1,Arg2,Arg3,Arg4)] _TestProp6 ("MyPropDraw with multi args5", Float) = 1
        [MyEnumMatAttribute(Arg1,Arg2,Arg3,Arg4, Arg5)] _TestProp7 ("MyPropDraw with multi args6", Float) = 1
        [MyEnumMatAttribute(1,2,3,4,5)] _TestProp8 ("MyPropDraw with multi args7", Float) = 1
        [MyEnumMatAttribute(1.0,2.0)] _TestProp9 ("MyPropDraw with multi args8", Float) = 1
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}


完成的测试csharp代码

// jave.lin 2022/12/17 自定义 Enum 材质 attribute 的绘制
// 并测试 自定义的 attribute 中含带多个 参数的功能

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

public class MyEnumMatAttributeDrawer : MaterialPropertyDrawer
{
    private List<string> args = new List<string>();
    private List<float> vals = new List<float>();
    private string GetArgsValsStr()
    {
        return $"args:{string.Join(",", args)}, vals:{string.Join(",", vals)}";
    }
    public MyEnumMatAttributeDrawer()
    {
        Debug.Log($"MyEnumMatAttributeDrawer 0, GetArgsValsStr():{GetArgsValsStr()}");
    }
    public MyEnumMatAttributeDrawer(string arg1) : base()
    {
        args.Add(arg1);
        Debug.Log($"MyEnumMatAttributeDrawer 1, GetArgsValsStr():{GetArgsValsStr()}");
    }
    public MyEnumMatAttributeDrawer(string arg1, string arg2)
    {
        args.Add(arg1);
        args.Add(arg2);
        Debug.Log($"MyEnumMatAttributeDrawer 2, GetArgsValsStr():{GetArgsValsStr()}");
    }
    public MyEnumMatAttributeDrawer(string arg1, string arg2, string arg3)
    {
        args.Add(arg1);
        args.Add(arg2);
        args.Add(arg3);
        Debug.Log($"MyEnumMatAttributeDrawer 3, GetArgsValsStr():{GetArgsValsStr()}");
    }
    public MyEnumMatAttributeDrawer(string arg1, string arg2, string arg3, string arg4)
    {
        args.Add(arg1);
        args.Add(arg2);
        args.Add(arg3);
        args.Add(arg4);
        Debug.Log($"MyEnumMatAttributeDrawer 4, GetArgsValsStr():{GetArgsValsStr()}");
    }
    public MyEnumMatAttributeDrawer(string args1, int val1, string args2, int val2)
    {
        args.Add(args1);
        args.Add(args2);
        vals.Add(val1);
        vals.Add(val2);
        // jave.lin : 注意这个重载是死活都进不来,原因:
        // jave.lin : 参考这里:https://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/Inspector/MaterialPropertyDrawer.cs#L96

        /**
         * jave.lin : 可以看到 CreatePropertyDraw 调用的是 .net 
         * Activator.CreateInstance(string func_name, object[] args) 的方式来查找 匹配的 函数签名
         * 所以我们的 int 类型都是识别不了的,只能有 string, 或 float 能识别
        private static MaterialPropertyDrawer CreatePropertyDrawer(Type klass, string argsText)
        {
            // no args -> default constructor
            if (string.IsNullOrEmpty(argsText))
                return Activator.CreateInstance(klass) as MaterialPropertyDrawer;

            // split the argument list by commas
            string[] argStrings = argsText.Split(',');
            var args = new object[argStrings.Length];
            for (var i = 0; i < argStrings.Length; ++i)
            {
                float f;
                string arg = argStrings[i].Trim();

                // if can parse as a float, use the float; otherwise pass the string
                if (float.TryParse(arg, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture.NumberFormat, out f))
                {
                    args[i] = f;
                }
                else
                {
                    args[i] = arg;
                }
            }
            return Activator.CreateInstance(klass, args) as MaterialPropertyDrawer;
        }
         */


        Debug.Log($"MyEnumMatAttributeDrawer 4.1, GetArgsValsStr():{GetArgsValsStr()}");
    }
    public MyEnumMatAttributeDrawer(string args1, float val1, string args2, float val2)
    {
        // jave.lin : 根据 官方代码 https://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/Inspector/MaterialPropertyDrawer.cs#L96
        // jave.lin : 能匹配 string 和 float
        args.Add(args1);
        args.Add(args2);
        vals.Add(val1);
        vals.Add(val2);
        Debug.Log($"MyEnumMatAttributeDrawer 4.2, GetArgsValsStr():{GetArgsValsStr()}");
    }
    public MyEnumMatAttributeDrawer(params string[] args)
    {
        // jave.lin : 可以进入,所以如果要写一个通用的 不定长 string 处理,可以使用这个
        this.args.AddRange(args);
        Debug.Log($"MyEnumMatAttributeDrawer 5, GetArgsValsStr():{GetArgsValsStr()}");
    }

    public MyEnumMatAttributeDrawer(params object[] args)
    {
        // jave.lin : 不会进入
        for (int i = 0; i < args.Length; i++)
        {
            this.args.Add(args[i].ToString());
        };
        Debug.Log($"MyEnumMatAttributeDrawer 6, GetArgsValsStr():{GetArgsValsStr()}");
    }

    public MyEnumMatAttributeDrawer(params float[] vals)
    {
        // jave.lin : 全是数值的时候会进入(注意如果是别的不是 float 意外的数值类型将不会匹配上)
        for (int i = 0; i < vals.Length; i++)
        {
            this.vals.Add(vals[i]);
        };
        Debug.Log($"MyEnumMatAttributeDrawer 7, GetArgsValsStr():{GetArgsValsStr()}");
    }

    public override void OnGUI(Rect position, MaterialProperty prop, string label, MaterialEditor editor)
    {
        base.OnGUI(position, prop, label, editor);

        //Debug.Log($"MyEnumMatAttribute draw, label : {label}, prop.dname:{prop.displayName}, prop.name:{prop.name}, with args:{string.Join(",", args)}, vals:{string.Join(",", vals)}");

        // jave.lin : 这里该怎么画,就怎么画

        // jave.lin : 但是这里有一个致命的设计,再 shader gui 中无法获取 drawer 对象,也就无法获取一些 drawer 中的参数、值,就无法制作一些高级的功能效果
    }

}

如果我们想要自定义 材质中的属性外观,就只能重写这个 MaterialPropertyDrawer 的派生类

无参数的还好

直接无参构造函数就完事

如果你想要提取 attribute 中的参数
那么就得有参数

这里值得注意的是,参数的类型声明,有一定规则,具体可以参考:https://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/Inspector/MaterialPropertyDrawer.cs#L96

可以看到,我们定义了一堆测试的 properties

    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        [MyEnumMatAttribute] _TestProp ("MyPropDraw no args", Float) = 1
        [MyEnumMatAttribute(Arg1)] _TestProp1 ("MyPropDraw with arg1", Float) = 1
        [MyEnumMatAttribute(Arg1,1,Arg2,2)] _TestProp2 ("MyPropDraw with multi args1", Float) = 1
        [MyEnumMatAttribute(Arg1,1.0,Arg2,2.0)] _TestProp3 ("MyPropDraw with multi args2", Float) = 1
        [MyEnumMatAttribute(Arg1,Arg2)] _TestProp4 ("MyPropDraw with multi args3", Float) = 1
        [MyEnumMatAttribute(Arg1,Arg2,Arg3)] _TestProp5 ("MyPropDraw with multi args4", Float) = 1
        [MyEnumMatAttribute(Arg1,Arg2,Arg3,Arg4)] _TestProp6 ("MyPropDraw with multi args5", Float) = 1
        [MyEnumMatAttribute(Arg1,Arg2,Arg3,Arg4, Arg5)] _TestProp7 ("MyPropDraw with multi args6", Float) = 1
        [MyEnumMatAttribute(1,2,3,4,5)] _TestProp8 ("MyPropDraw with multi args7", Float) = 1
        [MyEnumMatAttribute(1.0,2.0)] _TestProp9 ("MyPropDraw with multi args8", Float) = 1
    }

但是能匹配的函数签名有下面几个:
在这里插入图片描述

匹配不上的可以参考代码注意,写的很详细:


        /**
         * jave.lin : 可以看到 CreatePropertyDraw 调用的是 .net 
         * Activator.CreateInstance(string func_name, object[] args) 的方式来查找 匹配的 函数签名
         * 所以我们的 int 类型都是识别不了的,只能有 string, 或 float 能识别
        private static MaterialPropertyDrawer CreatePropertyDrawer(Type klass, string argsText)
        {
            // no args -> default constructor
            if (string.IsNullOrEmpty(argsText))
                return Activator.CreateInstance(klass) as MaterialPropertyDrawer;

            // split the argument list by commas
            string[] argStrings = argsText.Split(',');
            var args = new object[argStrings.Length];
            for (var i = 0; i < argStrings.Length; ++i)
            {
                float f;
                string arg = argStrings[i].Trim();

                // if can parse as a float, use the float; otherwise pass the string
                if (float.TryParse(arg, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture.NumberFormat, out f))
                {
                    args[i] = f;
                }
                else
                {
                    args[i] = arg;
                }
            }
            return Activator.CreateInstance(klass, args) as MaterialPropertyDrawer;
        }
         */

我们也可以看到官方有类似的写法应用在:KeywordEnum, Enum 之类的 attribute
在这里插入图片描述

在这里插入图片描述


注意问题 - MaterialPropertyDraw 不生效

解决方法就是重新 Reimport 一下对应的 Editor 脚本就完事
在这里插入图片描述


Unity MaterialPropertyDrawer 的设计不友好问题

// jave.lin : 但是这里有一个致命的设计,再 shader gui 中无法获取 drawer 对象,也就无法获取一些 drawer 中的参数、值,就无法制作一些高级的功能效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/95816.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端CSS实现苹果官网文字渐入效果

效果 分析 文字是从左到有慢慢呈现出来&#xff0c;不是整体消失和出现&#xff0c;那么肯定不能使用透明度。 我们可以想到渐变文字&#xff0c;然后通过改变背景的位置来控制文字的显示与隐藏。 渐变文字 渐变文字该如何实现呢&#xff1f;这是实现这个效果的关键步骤。 其…

计算机毕设Python+Vue校园闲置物品管理系统的实现(程序+LW+部署)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

看了那么多SSM整合,这一篇真的很用心。

1.邂逅 SSM 前言 记得大二上学期老师第一次讲 SSM 整合的时候&#xff0c;自己竟然浑浑噩噩睡过去了。 平时上课不好好听讲&#xff0c;后来听说期末要交大作业了&#xff0c;只能被迫去网上自学。 不对。。。少打个S&#xff0c;不过这真的是我第一次搜 SSM 的资料&#xff0…

华新环保深交所上市:市值49亿 前9个月净利降幅近30%

雷递网 雷建平 12月16日华新绿源环保股份有限公司&#xff08;简称&#xff1a;“华新环保”&#xff0c;证券代码&#xff1a;301265&#xff09;今日在深交所上市。华新环保本次发行股票7575万股&#xff0c;发行价13.28元&#xff0c;募资10.06亿元。华新环保开盘价为16元&a…

爬虫应用场景的利弊分析

相信大家在春节的时候都有过抢火车票的经历&#xff0c;对一些抢票软件一定不会感到陌生。今天我们就来从技术的角度&#xff0c;来看看抢票软件背后的东西——爬虫。通俗点说&#xff0c;爬虫就是模拟人的行为去各个网站溜达&#xff0c;并把看到的信息背回来的探测机器。如今…

Swagger是什么?Swagger怎么用?

Swagger 是一个规范且完整的框架&#xff0c;用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。 Swagger 的目标是对 REST API 定义一个标准且和语言无关的接口&#xff0c;可以让人和计算机拥有无须访问源码、文档或网络流量监测就可以发现和理解服务的能力。当通过 S…

(直连主题扇形)交换机

目录 一、交换机简介 1. Exchange&#xff08;交换机&#xff09;的作用 2.Exchange&#xff08;交换机&#xff09;的类型 ①.直连交换机&#xff1a;Direct Exchange ② 主题交换机&#xff1a;Topic Exchange ③ 扇形交换机&#xff1a;Fanout Exchange ④ 首部交换机…

NMS与Soft NMS算法解析与numpy实现

1. NMS算法 1.1 什么是NMS算法 NMS全称为Non Maximum Suppression&#xff0c;中文意思是非极大值抑制&#xff0c;字面意思就是不是极大值的元素被抑制掉&#xff0c;其实就是筛选出局部最大值得到最优解。NMS算法被广泛运用于目标检测算法处理网络输出的边界框。 1.2 为什…

【HTML基础篇002】HTML之form表单超详解

文章目录 &#x1f304;一、form表单是什么 &#x1f304;二、form表单的属性 &#x1f304;三、input中的各种Type属性值 &#x1f304;四、标签 &#x1f304;一、form表单是什么 表单是一个包含表单元素的区域。表单用于向服务器传输数据&#xff0c;从而实现用户与Web服…

jsp+ssm计算机毕业设计潮流服饰网店平台【附源码】

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JSPSSM mybatis Maven等等组成&#xff0c;B/S模式 Mave…

第十四届蓝桥杯集训——if——配套用法示例

第十四届蓝桥杯集训——if——配套用法示例 目录 第十四届蓝桥杯集训——if——配套用法示例 方法1 方法2 其它指数幂 输入一个数n&#xff0c;判断n是否是2的指数。 n的取值范围(0>n<)​​​​ 题目看着很简单&#xff0c;其实在比较小的数上还是挺容易做的&…

CARIS11.4基本使用流程及其bug解决

今天博主介绍一下CARIS11.4的基本流程以及它的界面bug。 一、CARIS11.4的基本流程 如果以前用过CARIS9&#xff0c;不用看帮助说明&#xff0c;你摸索一段时间也能掌握CARIS11.4的使用流程。相比CARIS9&#xff0c;CARIS11.4的主要功能基本不变&#xff0c;增加了生成变分辨率…

毕业设计 - java web 进销存管理系统的设计与实现【源码+论文】

文章目录前言一、项目设计1. 模块设计系统需要具备以下功能2. 实现效果二、部分源码项目源码前言 今天学长向大家分享一个 java web 项目: 进销存管理系统的设计与实现 一、项目设计 1. 模块设计 系统需要具备以下功能 ⑴一般企业人员的计算机知识掌握的不多&#xff0c;因…

Android studio profiler中的Shallow size和retained sizes是什么意思

这个文章说得非常好&#xff1a;https://www.yourkit.com/docs/java/help/sizes.jsp#:~:textYourKit%20Java%20Profiler%20is%20capable%20of%20measuring%20shallow,the%20number%20and%20types%20of%20%20its%20fields. Shallow size&#xff1a;用于存储一个对象的内存大小…

【Python机器学习】聚类算法任务,评价指标SC、DBI、ZQ等系数详解和实战演示(附源码 图文解释)

需要源码和数据集请点赞关注收藏后评论区留言私信~~~ 一、聚类任务 设样本集S{x_1,x_2,…,x_m}包含m个未标记样本&#xff0c;样本x_i(x_i^(1),x_i^(2),…,x_i^(n))是一个n维特征向量。 聚类在分簇过程的任务是建立簇结构&#xff0c;即要将S划分为k&#xff08;有的聚类算法…

你不知道的 Git 技巧:如何实现核心代码保护

大家好&#xff0c;我是 shixin。 前段时间完成了一个核心代码保护的功能&#xff0c;目标是在关键代码被修改及时同步给其他人&#xff0c;避免没经过 review 就上线导致问题&#xff0c;提示的效果图如下&#xff1a; 在实现的过程中&#xff0c;用到一些平时使用不多的 Git…

微服务框架 SpringCloud微服务架构 多级缓存 48 多级缓存 48.8 查询Redis 缓存

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 多级缓存 文章目录微服务框架多级缓存48 多级缓存48.8 查询Redis 缓存48.8.1 OpenResty的Redis模块48 多级缓存 48.8 查询Redis 缓存 48.8…

spring切入点函数

切入点函数&#xff1a;用于执行切入点函数 1.execution 1.最为重要的切入点函数&#xff0c;功能最全 2.可以执行方法切入点表达式&#xff0c;可以执行类切入点表达式&#xff0c;可以执行包切入点表达式 弊端&#xff1a;书写比较麻烦 2.args 1.作用&#xff1a;主要用…

原创10个python自动化化案例,一口一个高效办公!

以下为我的自动化办公代码&#xff0c;有需要的同学建议点赞收藏并熟读背诵&#xff01;&#xff08;持续更新&#xff09; 1.自动化批量调整word中含有关键词句子的样式 就随便拿一段我在网上找到的文字来做例子&#xff1a; 若关键词为“资金”&#xff0c;则处理后的word…

CentOS不再维护,跃跃欲试AlmaLinux

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&#x1f61…