![](https://i-blog.csdnimg.cn/blog_migrate/5608f9d55b61d28c766a0bcf66a6542a.jpeg)
同样的着色器,不同的贴图
用户界面
到目前为止,我们一直都为我们的材质使用Unity默认的材质监视器,它很耐用,但是Unity的标准着色器长得非常不一样。仿照着标准着色器,让我们一起来为我们自己的着色器创建一个自定义监视器吧。
![](https://i-blog.csdnimg.cn/blog_migrate/aeaf0aed517d44924d07be40b2a96dc9.jpeg)
我们默认的监视器和标准着色器监视器
着色器GUI
我们可以通过添加一个继承UnityEditor.ShaderGUI的类创建一个自定义监视器。因为它是一个编辑器类,所以应该把脚本文件放到Editor文件夹下。
usingUnityEngine;
usingUnityEditor;
publicclassMyLightingShaderGUI : ShaderGUI {
}
我们不需要继承MaterialEditor吗?
Unity 4.1支持通过继承MaterialEditor自定义材质监视器,你也可以依旧这样做,但是ShaderGUI在5.0版本中是作为备选被加入的,它的创建与Substance材质有一些关系。Unity为标准着色器使用ShaderGUI,所以我们也使用它。
要使用一个自定义GUI,你需要向着色器加入CustomEditor指令,紧跟着一个字符串,字符串包含要使用的GUI类的名字。
Shader"Custom/My First Lighting Shader"{
…
CustomEditor"MyLightingShaderGUI"
}
ShaderGUI类能放入命名空间吗?
可以。你需要在着色器中指定完全限定的类名。
CustomEditor"MyNamespace.MyShaderGUI"
为了替换默认监视器,我们需要重写ShaderGUI.OnGUI方法,该方法有两个参数,第一个参数是MaterialEditor的引用,这个对象管理当前被选材质的监视器;第二个参数是包含材质属性的数组。
publicclassMyLightingShaderGUI : ShaderGUI {
publicoverridevoidOnGUI (
MaterialEditor editor, MaterialProperty[] properties
) {
}
}
在这个方法内部,我们已经创建了我们自己的GUI。因为我们还什么都没做,所以监视器还是空的。
创建一个标签
标准着色器GUI被分成两部分,一部分针对主要贴图,另一部分针对次要贴图。我们会在我们的GUI中采用相同的布局。为了保持代码整洁,我们会为GUI不同的部分采用单独的方法。我们从主要部分以及其标签入手。
publicoverridevoidOnGUI ( MaterialEditor editor, MaterialProperty[] properties ) {
DoMain();
}
voidDoMain() {
GUILayout.Label("Main Maps");
}
![](https://i-blog.csdnimg.cn/blog_migrate/0521bbfc8425855d7965576e51ce85b0.jpeg)
主要贴图标签
GUILayout是如何工作的?
UnityEditor是用Unity的立即模式UI创建的,这是Unity老的UI系统,在当今基于画布的系统之前,它也用于游戏内UI。
立即模式UI的基础是GUI类,它包含创建UI小工具的方法。你需要利用矩形来精确定位每个元素。GUILayout类提供了相同的功能,但是它会使用简单布局系统自动定位小工具。
除此之外,EditorGUI类和EditorGUILayout类提供了针对编辑器UI的小工具和特征的访问。
标准着色器有一个粗体标签,所以我们也想要一个粗体标签,通过向标签添加GUI样式就可以实现,这样一来就是EditorStyles.boldLabel。
GUILayout.Label("Main Maps", EditorStyles.boldLabel);
![](https://i-blog.csdnimg.cn/blog_migrate/c926d255b575237d984572ccbe0fde50.jpeg)
粗体标签.
显示Albedo
为了显示我们材质的属性,我们需要在我们的方法中访问它们。我们会把OnGUI的参数传递到其他所有方法中,但是这会导致大量重复代码。我们不这么做,我们把它们放到域中。
MaterialEditor editor;
MaterialProperty[] properties;
publicoverridevoidOnGUI ( MaterialEditor editor, MaterialProperty[] properties ) {
this.editor = editor;
this.properties = properties;
DoMain();
}
每次OnGUI被调用时我们都需要拷贝引用吗?
当一个新的ShaderGUI实例被创建时,MaterialEditor会做出决定。目前来讲,这会在一个材质被选了的时候发生,就像你可能预期的那样。但是它也可能在撤销会重做动作执行的时候发生。这意味着你不能继续依赖ShaderGUI实例了。每次,它都会是一个新的对象实例,你可以把OnGUI想成它好像是一个静态方法,尽管它并不是。
Albedo贴图在标准着色器中第一次展现。这是主要纹理,它的属性在属性数组的某一位置设置,它的数组下标取决于我们着色器中定义属性的顺序。但是通过名称查找的鲁棒性更强一些。ShaderGUI包括FindProperty方法,它就是干这件事的,通过给定名称和属性数组找到对应结果。
voidDoMain () {
GUILayout.Label("Main Maps", EditorStyles.boldLabel);
MaterialProperty mainTex = FindProperty("_MainTex", properties);
}
除了纹理属性之外,我们也需要定义标签的内容,这可以通过GUIContent实现,它是一个简单的容器类。
MaterialProperty mainTex = FindProperty("_MainTex", properties);
GUIContent albedoLabel =newGUIContent("Albedo");
但是我们已经在我们的着色器中为主要纹理Albedo命名了,我们只能使用已定义好的名称,我们可以通过属性访问到。
GUIContent albedoLabel =newGUIContent(mainTex.displayName);
为了创建那些小的纹理小工具,我们必须依赖我们已经引用的编辑器,它具有许多绘制这样小工具的方法。
MaterialProperty mainTex = FindProperty("_MainTex", properties);
GUIContent albedoLabel =newGUIContent(mainTex.displayName);
editor.TexturePropertySingleLine(albedoLabel, mainTex);
![](https://i-blog.csdnimg.cn/blog_migrate/6d6527b0a988dee72ba53d7b0a6731b9.jpeg)
Albedo贴图
这就是看起来像标准着色器的开始!但是当你鼠标经过属性标签时,那个监视器还有提示信息,在Albedo贴图的情况中,上面写着Albedo (RGB)和Transparency (A)。
我们也可以加一个提示信息,很简单,只要向标签内容中添加就可以了。因为我们还不支持透明度,我们就只使用Albedo(RGB)。
GUIContent albedoLabel =
newGUIContent(mainTex.displayName,"Albedo (RGB)");
![](https://i-blog.csdnimg.cn/blog_migrate/ff714d22e69370539b4b719f934f9770.jpeg)
带提示信息的Albedo
TexturePropertySingleLine方法有可以与多个(最多三个)属性作用的变体,第一个应该是纹理,但是其他可能就是别的什么了,它们都会被放在一行中,我们可以用这来显示纹理旁边的取色工具。
MaterialProperty tint = FindProperty("_Tint", properties);
editor.TexturePropertySingleLine(albedoLabel, mainTex, tint);
![](https://i-blog.csdnimg.cn/blog_migrate/53cf29865deb845a4221ba72e8cc7b6a.jpeg)
Albedo贴图和取色
让我们直接跳到主要部分的底部,那是显示主要纹理贴砖和偏移量的位置,这可以通过