US5L2——MaterialPropertyDrawer类
US5L2——MaterialPropertyDrawer类
MaterialPropertyDrawer
MaterialPropertyDrawer
(材质属性绘制器)用于自定义材质属性在材质面板中的显示和交互方式的
材质属性通常在 Shader 中通过属性语句块定义。默认情况下,Unity 提供了一些基础的控件(如滑块、颜色选择器等)
通过继承 MaterialPropertyDrawer
(材质属性绘制器),你可以为自定义 Shader 属性创建更加灵活和直观的控件
MaterialPropertyDrawer 和 ShaderGUI 的区别
ShaderGUI
是用来自定义整个材质面板的,
而 MaterialPropertyDrawer
(材质属性绘制器)是用来自定义某一个属性的
相当于可以更加精细的来进行属性自定义显示封装
MaterialPropertyDrawer 类的声明
-
新建一个 C# 脚本,继承自
MaterialPropertyDrawer
类,类名最好以 Drawer
结尾 -
重写
void OnGUI(Rect position, MaterialProperty prop, string label, MaterialEditor editor)
方法也可以重写
void OnGUI(Rect position, MaterialProperty prop, GUIContent label, MaterialEditor editor)
方法
区别只在于是否想让控件标签的又要显示字符串又要显示图片,详见:GUIContent -
在其中实现 UI 自定义布局
1 | using UnityEditor; |
MaterialPropertyDrawer 类的使用
假设我们要实现一个自带最大值和最小值的滑动条,最大值和最小值通过构造函数由外部提供:
1 | using UnityEditor; |
-
配合
ShaderGUI
使用假设要对下面的 Shader 自定义材质 Inspector 界面,并且要自定义 Shader 的
float
类型的属性的绘制方法:1
2
3
4
5
6
7
8
9
10
11Shader "Unlit/CustomInspectorTest"
{
Properties
{
_MainTex("Texture", 2D) = "white"{}
_TestFloat("TestFloat", Float) = 1
}
SubShader {/*...*/}
CustomEditor "Lesson127_CustomShaderInspector"
}以上节课实现的
ShaderGUI
派生类为例,代码详见:US5L1——ShaderGUI类
要使用MaterialPropertyDrawer
派生类,需要在类内部声明相应变量并实例化,
然后再ShaderGUI
派生类的OnGUI
方法内调用MaterialPropertyDrawer
派生类的OnGUI
方法
其中MaterialPropertyDrawer
派生类的OnGUI
需要传入绘制位置,MaterialProperty
属性,控件名,以及MaterialEditor
参数关于绘制位置参数,如果是自动布局,可以直接使用 EditorGUILayout.GetControlRect()
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
36using UnityEditor;
using UnityEngine;
public class Lesson127_CustomShaderInspector : ShaderGUI
{
private bool isShow;
private Lesson128 floatDrawer = new(-2, 2);
public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
{
if (GUILayout.Button(isShow ? "隐藏所有属性设置" : "显示所有属性设置"))
{
isShow = !isShow;
}
// 获取当前材质球
Material material = materialEditor.target as Material;
if (GUILayout.Button("重置材质球属性"))
{
material.SetTexture("_MainTex", null);
material.SetFloat("_TestFloat", 0);
}
if (isShow)
{
MaterialProperty property = FindProperty("_MainTex", properties);
materialEditor.ShaderProperty(property, property.displayName);
// 使用自定义的控件去设置TestFloat属性
property = FindProperty("_TestFloat", properties);
floatDrawer.OnGUI(EditorGUILayout.GetControlRect(), property, property.displayName, materialEditor);
// 绘制渲染队列控件
material.renderQueue = EditorGUILayout.IntField("渲染队列", material.renderQueue);
}
}
}显示效果:
-
独立使用
注意!这个功能的 BUG 比较多,可能需要多调整以解决问题
我们往往不会让
MaterialPropertyDrawer
派生类只配合ShaderGUI
类使用,因为这些逻辑也可以在ShaderGUI
类实现
MaterialPropertyDrawer
派生类更多的时候会单独使用,我们可以直接在 Shader 内让某个特定属性使用这个MaterialPropertyDrawer
派生类假设要对下面的 Shader 自定义
float
类型的属性的绘制方法:1
2
3
4
5
6
7
8
9
10Shader "Unlit/CustomInspectorTest"
{
Properties
{
_MainTex("Texture", 2D) = "white"{}
_TestFloat("TestFloat", Float) = 1
_TestFloat2("TestFloat2", Float) = 1
}
SubShader {/*...*/}
}假设要让
_TestFloat2
这个属性使用自定义的MaterialPropertyDrawer
派生类,
直接在_TestFloat2
使用[MaterialPropertyDrawer派生类名(构造函数参数)]
即可,它的使用方法类似于 C# 的特性:CS4L21——特性,
如果MaterialPropertyDrawer
派生类类名由Drawer
后缀,在 Shader 中使用是可以忽略的,就如同 C# 特性的Attribute
后缀那样
如果MaterialPropertyDrawer
派生类拥有有参构造参数,则可以通过类名后边填入参数。警告!参数内不要填入
-
,即使要传递负数也不能这么填,如果要传递负数,可能需要寻求其他方式解决
Unity Shader 会在例如[Lesson128_FloatProperty(-3, 3)]
的语句上报错,报错原因不明!1
2
3
4
5
6
7
8
9
10
11Shader "Unlit/CustomInspectorTest"
{
Properties
{
_MainTex("Texture", 2D) = "white"{}
_TestFloat("TestFloat", Float) = 1
// [Lesson128_FloatProperty(-3.0, 3,0)] _TestFloat2("TestFloat2", Float) = 1 // 不能使用'-',否则会报错,原因不明
[Lesson128_FloatProperty(0.0, 3.0)] _TestFloat2("TestFloat2", Float) = 1
}
SubShader {/*...*/}
}显示效果: