US5L1——ShaderGUI类
US5L1——ShaderGUI类
前置知识:UG1——IMGUI系列,UED——Unity编辑器拓展
本章代码关键字
1 | ShaderGUI // 用于自定义材质Inspector界面的基类,通过继承ShaderGUI,可以完全控制材质编辑界面的布局和功能 |
自定义材质面板
我们目前可以通过在 Shader 中添加属性的形式,把一些我们希望从外部设置的内容在材质球的 Inspector 窗口中显示
1 | Properties |
自定义材质面板指的就是,Unity 除了这些默认的显示内容外,还可以让我们自定义材质球的 Inspector 窗口显示
ShaderGUI
它是一个用于自定义材质 Inspector 界面 的基类,通过继承 ShaderGUI
,你可以完全控制材质编辑界面的布局和功能
而不仅仅局限于 Shader 的 属性(Properties
)语句块定义的默认行为
ShaderGUI
可以让我们:
- 自定义材质界面布局
- 通过脚本逻辑,可以基于某些属性值动态隐藏或禁用其他属性
- 添加高级功能,比如通过添加按钮控件,触发某些操作,如实时更新材质预览,显示调试信息等
- 增强材质编辑体验,使美术人员或其他开发者无需关心底层 Shader 实现,而是通过友好的界面快速调整材质
等等
ShaderGUI类的基本使用
- 自定义 C# 脚本继承
ShaderGUI
- 重写
OnGUI
方法 - 在
OnGUI
方法中书写自定义布局逻辑 - 在
Shader
语句块最后加入CustomEditor "自定义C#脚本名"
这样便可以让使用该 Shader 的材质面板使用自定义布局规则
假设要对下面的 Shader 自定义材质 Inspector 界面:
1 | Shader "Unlit/CustomInspectorTest" |
当直接调用基类的方法时:
1 | using UnityEditor; |
显示效果:
可见,base.OnGUI
的逻辑就是原来的绘制逻辑
当 OnGUI
不实现任何内容时:
1 | using UnityEditor; |
显示效果:
可见,当 OnGUI
没有逻辑时,Shader 在 Inspector 窗口上也没有任何内容
自定义材质面板
使用 ShaderGUI
自定义材质面板的核心方法就是我们重写的:void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
方法
其中两个参数非常重要:
-
materialEditor
:提供与材质交互的接口,比如材质属性值等-
关键属性:
target
,可以利用它获取到材质球1
2
3
4
5
6public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
{
// 获取当前材质球
Material material = materialEditor.target as Material;
// 之后即可利用材质球去Set或者Get属性的值
} -
关键方法:
ShaderProperty(MaterialProperty对象, "名字")
,可以将属性设置为对应名字,并且使用默认 GUI 显示- 参数一:要显示的
MaterialProperty
对象 - 参数二:属性名显示文本,可以自定义,也可以直接使用
materialProperty.displayName
用 Shader 定义的属性名设置
1
2
3
4
5
6
7
8public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
{
// 之后即可利用材质球去Set或者Get属性的值
foreach (MaterialProperty property in properties)
{
materialEditor.ShaderProperty(property, property.displayName);
}
}显示效果:
- 参数一:要显示的
-
-
properties
:包含所有在 Shader 的属性语句块中定义的属性可以通过
foreach
遍历properties
的所有MaterialProperty
,也就是 Shader 内定义的属性
也可以直接使用FindProperty
来直接查找某个特定的MaterialProperty
属性-
MaterialProperty
关键属性:displayName
,获取属性名我们可以通过
displayName
来判断是否是特定属性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
28using UnityEditor;
using UnityEngine;
public class Lesson127_CustomShaderInspector : ShaderGUI
{
private float testFloatValue;
public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
{
// 获取当前材质球
Material material = materialEditor.target as Material;
foreach (MaterialProperty property in properties)
{
// 如果是TestFloat就自定义其显示
if (property.displayName == "TestFloat")
{
testFloatValue = EditorGUILayout.Slider("自定义float属性", testFloatValue, -1, 1);
material.SetFloat(property.displayName, testFloatValue);
}
// 其他属性按照原样绘制
else
{
materialEditor.ShaderProperty(property, property.displayName);
}
}
}
}显示效果:
可见,
TestFloat
这个属性的显示方式被改变了 -
通过
类型+Value
的属性可以直接获取材质的 Shader 属性当前值除了通过获取材质球然后使用
Get
和Set
的方法去获取或设置对应的属性的值,
还可以使用materialProperty.类型+Value
的属性直接获取和修改对应属性的值,
例如floatValue
即可获取float
类型属性当前的值、textureValue
即可获取贴图类型属性的当前值1
2
3
4
5
6
7
8
9
10public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
{
// 获取当前材质球
Material material = materialEditor.target as Material;
// 自定义一个拖动条去设置TestFloat属性
property = FindProperty("_TestFloat", properties);
property.floatValue = EditorGUILayout.Slider("自定义float属性", property.floatValue, -1, 1);
material.SetFloat(property.displayName, property.floatValue);
} -
直接查找某个属性:
MaterialProperty 属性对象 = FindProperty("属性名", properties)
可以利用
FindProperty
方法,通过属性名直接获取到对应属性对象,而不用从properties
遍历查找1
2
3
4
5
6
7
8
9
10
11
12public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
{
// 获取当前材质球
Material material = materialEditor.target as Material;
MaterialProperty property = FindProperty("_MainTex", properties);
materialEditor.ShaderProperty(property, property.displayName);
// 自定义一个拖动条去设置TestFloat属性
property = FindProperty("_TestFloat", properties);
property.floatValue = EditorGUILayout.Slider("自定义float属性", property.floatValue, -1, 1);
material.SetFloat(property.displayName, property.floatValue);
}显示效果:
-
-
如果要设置材质的渲染队列,可以使用
material.renderQueue
属性去获取和修改1
2
3
4
5
6public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
{
// 获取当前材质球
Material material = materialEditor.target as Material;
material.renderQueue = EditorGUILayout.IntField("渲染队列", material.renderQueue);
}显示效果
示例:
1 | using UnityEditor; |
显示效果: