当前位置: 首页> 健康> 知识 > UnityShader自定义属性特性

UnityShader自定义属性特性

时间:2025/7/11 19:55:09来源:https://blog.csdn.net/m0_68267247/article/details/141937705 浏览次数:0次

前言:

在编写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 Datapublic 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;elsepropertyShow.Add(property, visiable);}public static bool GetPropertyVisible(string property){if (propertyShow.ContainsKey(property))return propertyShow[property];elsereturn false;}}#endregionpublic 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拓展编辑器基础知识

关键字:UnityShader自定义属性特性

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: