UnityShader自定义属性特性

news2024/11/15 11:29:59

前言:

在编写UnityShader时,我们常常会使用特性来更换材质球面板的属性外观,除此之外,还可以使用自定义的扩展脚本来实现自定义的材质球界面,参考我之前的文章UnityShaderUI编辑器扩展

但是自定义扩展每次都要单独写一个Editor脚本来扩展对应的Shader,而不能像特性那样,只要加一个[HDR],[Range]就能更改材质面板的界面。

那么我们如何方便又快速的创建自定义的特性,方便我们只要写一个全功能脚本,就能快速自定义扩展不同的Shader呢?

原理:

如图,只需要编写脚本,类继承MaterialPropertyDrawer就可以了,类名的命名方式是特性名+Drawer,如:SingleLineTextureDrawer,或者不加Drawer也可以Unity会自动添加并识别。

在Shader中使用:

写法:[特性类名(不加Drawer)]

材质面板显示:

自定义Group自动分组功能:

构想:一个特性Group,在Shader属性前添加时,作为折叠栏功能,如[Group]_group1表示一个折叠栏,如[Group(_MainTex,_IntTest)]_group2表示group2折叠栏下包含属性_MainTex与_IntTest属性的绘制或者不绘制。

如图:

效果:

实现:

在我们的构想中,Group可以包含子属性,也可以不包含,包含的子属性的数量不定,所以构建构造函数:

启用keys数组用来存放传递的命名,这些命名作为我们用来分组和查询属性的必要条件。

重写OnGUI函数:

这其中有一个GUIData调用,这是用来存放Shader的属性是否应该被绘制的数据类,如果不这样做,你就会发现就算使用了自定义的特性,这个属性还会被绘制一次,因为我们的实现逻辑需要在Group中处理其子属性的可见性。

GUIData类与自定义方法:

很简单,立面有一个字典,这个字典存放了属性的可见性,同样有两个方法,一个方法设置属性的可见性,一个方法获取属性的可见性。

然后,需要写一个自定义脚本,继承ShaderGUI并且在Shader中使用CustomEditor调用,我们自主实现Shader的OnGUI逻辑,如图:

为什么还要这样自定义ShaderGUI呢?因为上述说过,为了实现Group分组效果,需要避免其子属性不管有没有特性,都应该被Group折叠栏决定显影,若是不自主实现,你就会发现你自定义绘制了一遍,这些子属性不管有没有特性,也会再被绘制一遍,因为没有处理Unity默认的绘制逻辑,所以需要我们自定义一个ShaderGUI实现。

全部代码:

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


namespace CustomShaderPropertyDrawer
{
    #region Data
    public class GUIData
    {
        private static Dictionary<string, bool> propertyShow = new Dictionary<string, bool>();

        public static void SetPropertyVisible(string property, bool visiable)
        {
            if (propertyShow.ContainsKey(property))
                propertyShow[property] = visiable;
            else
                propertyShow.Add(property, visiable);
        }

        public static bool GetPropertyVisible(string property)
        {
            if (propertyShow.ContainsKey(property))
                return propertyShow[property];
            else
                return false;
        }
    }

    #endregion
    public class GUIShow : ShaderGUI
    {
        internal MaterialProperty[] Pops { get; private set; }


        public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
        {
            Pops = properties;
            var material = materialEditor.target as Material;
            var shader = material.shader;
            for (int i = 0; i < properties.Length; i++)
            {
                if (System.String.Concat(shader.GetPropertyAttributes(i)).Contains("Group"))
                {
                    materialEditor.ShaderProperty(properties[i], properties[i].displayName);
                }
                else
                {
                    if (GUIData.GetPropertyVisible(properties[i].name))
                        materialEditor.ShaderProperty(properties[i], properties[i].displayName);
                }
            }
        }

    }

    #region MaterialPropertyDrawer
    /// <summary>
    /// Group分组,采样Flodout形式,可使用自定义GUIStyle
    /// </summary>
    public class GroupDrawer : MaterialPropertyDrawer
    {
        readonly string[] keys;
        public GroupDrawer() { }
        public GroupDrawer(params string[] keys)
        {
            this.keys = keys;
        }

        public override void OnGUI(Rect position, MaterialProperty prop, GUIContent label, MaterialEditor editor)
        {
            if (editor.customShaderGUI == null || !(editor.customShaderGUI is GUIShow))
                editor.DefaultShaderProperty(prop, prop.displayName);
            else
            {
                if (prop.type == MaterialProperty.PropType.Float || prop.type == MaterialProperty.PropType.Int)
                {
                    bool group_foldout = false;
                    switch (prop.type)
                    {
                        case MaterialProperty.PropType.Float:
                            group_foldout = prop.floatValue == 1.0f ? true : false;
                            EditorGUI.BeginChangeCheck();
                            group_foldout = EditorGUI.Foldout(position, group_foldout, prop.displayName);
                            if (EditorGUI.EndChangeCheck())
                            {
                                prop.floatValue = group_foldout ? 1f : 0f;
                                if (keys != null && keys.Length > 0)
                                {
                                    foreach (var key in keys)
                                    {
                                        GUIData.SetPropertyVisible(key, group_foldout);
                                    }
                                }
                            }
                            break;
                        case MaterialProperty.PropType.Int:
                            group_foldout = prop.intValue == 1 ? true : false;
                            EditorGUI.BeginChangeCheck();
                            group_foldout = EditorGUI.Foldout(position, group_foldout, prop.displayName);
                            if (EditorGUI.EndChangeCheck())
                            {
                                prop.intValue = group_foldout ? 1 : 0;
                                if (keys != null && keys.Length > 0)
                                {
                                    foreach (var key in keys)
                                    {
                                        GUIData.SetPropertyVisible(key, group_foldout);
                                    }
                                }
                            }
                            break;
                    }
                }
            }

        }
    }

    /// <summary>
    /// 单线贴图样式
    /// </summary>
    public class SingleLineTexture : MaterialPropertyDrawer
    {
        public override float GetPropertyHeight(MaterialProperty prop, string label, MaterialEditor editor)
        {
            return 0;
        }
        public override void OnGUI(Rect position, MaterialProperty prop, GUIContent label, MaterialEditor editor)
        {
            if (prop.type == MaterialProperty.PropType.Texture)
            {
                editor.TexturePropertySingleLine(label, prop);
            }
        }
    }

    #endregion
}

注意:官方说明,为了性能,EditorGUILayout不能和MaterialPropertyDrawers一起使用,所以最好还是使用EditorGUI

更多内容可以参考官方MaterialEditor,MaterialPropertyDrawer,ShaderOnGUI,EditorGUI等编辑器内容,同时可以阅读我的编辑器扩展基础知识:Unity拓展编辑器基础知识

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

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

相关文章

JavaScript接下来的小项目

前言 ● 接下来&#xff0c;我们将学习如下所示的一个小项目&#xff0c;这个项目是一个地图的项目&#xff0c;我们可以在地图上标记一些我们运动的位置进行记录&#xff0c;并且浏览器在本地会帮我们记录他们&#xff0c;其他一些功能后面慢慢阐述并实现 启动代码 JS代码…

基于SSM+Vue+MySQL的出租车管理系统

系统背景 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本出租车管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息…

phpstorm格式化代码

快捷键&#xff1a;Ctrl Alt L 1.代码按等号按键值对自动对齐 第一步&#xff1a;点击左上角File&#xff0c;点击Settings 第二步&#xff1a;

Unity界面、组件以及脚本

Unity界面 菜单栏 菜单栏&#xff1a;位于屏幕顶部&#xff0c;包含文件、编辑、资产、游戏对象、组件、地形、动画、图形、AI、窗口、工具和帮助等菜单项。 工具栏 工具栏&#xff1a;位于菜单栏下方&#xff0c;提供了快速访问常用功能的按钮&#xff0c;如播放、暂停、停止…

【14.1运行版】C++俄罗斯方块-实现欢迎界面

实现欢迎界面 #include <stdio.h>//C语言形式的输入输出 #include <graphics.h>//图形库的头文件//实现欢迎界面 void welcome(void);int main(void) {welcome();//colsegraph();return 0; }void welcome(void) {//初始化画布initgraph(550, 660);//设置窗口标题H…

面壁小钢炮3.0发布:端侧ChatGPT时代的技术飞跃

一、面壁小钢炮3.0模型介绍 ➤ MiniCPM 3.0 开源地址&#xff1a; &#x1f517; https://github.com/OpenBMB/MiniCPM &#x1f517; https://huggingface.co/openbmb/MiniCPM3-4B 2024年9月5日&#xff0c;面壁智能发布 MiniCPM3-4B&#xff01;该模型的表现超越 Phi-3.5-…

【Linux】gcc/g++ 、make/Makefile、git、gdb 的使用

目录 1. Linux编译器-gcc/g1.1 编译器gcc/g的工作步骤1.2 函数库1.2.1 函数库的作用及分类1.2.2 动态链接和静态链接1.2.3 动态库和静态库的优缺点 1.3 gcc选项 2. Linux项目自动化构建工具-make/Makefile2.1 .PHONY2.2 尝试编写进度条程序 3. git3.1 安装 git3.2 下载项目到本…

Linux 竞争与并发(学习总结)

在Linux驱动开发中&#xff0c;“并发”和“竞争”是两个重要的概念&#xff0c;它们涉及到多任务环境下资源的管理和使用。 并发 (Concurrency) 并发指的是在同一时间段内&#xff0c;多个任务看似同时运行的现象。实际上&#xff0c;在单核处理器上&#xff0c;这通常是通过…

Android之LiveTemplate注释模板

目录 效果图步骤 效果图 步骤 1.首先通过File->Setting->Editor->LiveTemplate 我是放在Android下的&#xff0c;然后点击右侧&#xff08;新版本的话不在右侧&#xff09;加号&#xff0c; 点击&#xff08;加号&#xff09;之后&#xff0c;如图 /*** author:T…

RK3588 系列之3—rknn使用过程中遇到的bug

RK3588 系列之3—rknn使用过程中遇到的bug 1.librockchip_mpp.so: file format not recognized&#xff1b; treating as linker scrip2.Could not find a package configuration file provided by "OpenCV" with any of the following names参考文献 1.librockchip_…

java后端保存的本地图片通过ip+端口直接访问

直接上代码吧 package com.ydx.emms.datapro.controller;import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.…

Docker Image 命令

文章目录 目录 文章目录 1 . Docker镜像是什么? 2 . 镜像命令详解 docker images docker tag docker pull docker rmi docker save 总结 1 . Docker镜像是什么? Docker image 本质上是一个 read-only 只读文件&#xff0c; 这个文件包含了文件系统、 源码、库文件…

性能测试经典案例解析——远程培训系统

各位好&#xff0c;我是 道普云 一站式云测试SaaS平台。一个在软件测试道路上不断折腾十余年的萌新。 欢迎关注我的专栏和我的主页 道普云 文章内容具有一定门槛&#xff0c;建议先赞再收藏慢慢学习&#xff0c;有不懂的问题欢迎私聊我。 希望这篇文章对想提高软件测试水平…

负载均衡调度器--LVS

文章目录 集群和分布式集群分布式 LVS介绍LVS特点LVS工作原理LVS集群架构 LVS集群中的术语CIPVIPRSDIPRIP LVS集群的工作模式NAT模式DR模式DR模式的特点: TUN模式 LVS调度算法LVS相关软件ipvsadm 命令管理集群服务&#xff1a;增、改、删管理集群上的RS:增、改、删 创建集群 LV…

神经网络搭建的那点事

1.全连接网络 python&#xff1a; nn.Linear(in, out) matlab: layer fullyConnectedLayer(outputSize) layer fullyConnectedLayer(outputSize,Name,Value) 2.add和concat的区别 concat作用 concat是通道数的增加&#xff0c;也就是说描述图像本身的特征数&#xff08;通道…

ITK-高斯滤波

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 高斯滤波原理 高斯滤波&#xff08;Gaussian Blur&#xff09;是数字图像处理中常见的一种平滑滤波器&#xff0c;旨在通过模糊处…

Python 从入门到实战8(字典)

我们的目标是&#xff1a;通过这一套资料学习下来&#xff0c;通过熟练掌握python基础&#xff0c;然后结合经典实例、实践相结合&#xff0c;使我们完全掌握python&#xff0c;并做到独立完成项目开发的能力。 上篇文章我们通过举例学习了python 中元组的定义及相关操作。今天…

css弹性盒子——flex布局

目录 ​编辑 一、flex容器的样式属性(父元素属性) display:flex 弹性盒子&#xff0c;实现水平排列,在父盒子设置&#xff0c;适用于单行/单列 justify-content 二、flex元素的样式属性(子元素属性) 1.flex-grow 2.flex-shrink 3.flex-basis 4.flex组合属性 flex:flex-…

【WPS Excel】复制表格时,提示“图片太大,超过部份将被截去“ 问题

WPS表格 2019版本 升级到 WPS最新版 WPS-支持多人在线协作编辑Word、Excel和PPT文档_WPS官方网站 使用最新版就能够解决这个问题&#xff0c;如果仍旧无法解决可以勾选如下配置 重启Excel解决。 请勾选&#xff1a;文件 - 选项 - 编辑 - 不提示且不压缩文件中的图像

无需更换摄像头,无需施工改造,降低智能化升级成本的智慧工业开源了。

智慧工业视觉监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒&#xff0c;省去繁琐重复的适配流程&#xff0c;实现芯片、算法、应用的全流程组合&#xff0c;从而大大减少企业级应用约95%的开发成本。用户只需在界面上…