本文介绍在ShaderEditor中添加ToolTip字段提示。

Custom Shader GUI官方文档click here!

前言

最近群里群友咨询如何给Shader Vector类型的参数添加ToolTip。

MaterialEditor中跟Vector有关的只有VectorProperty函数

然而两个重载均没有提供传入ToolTip或者GUIContent的参数,目前从文档来看ColorProperty、FloatProperty默认没有提供ToolTip支持,MaterialEditor.TextureProperty中倒是支持传入ToolTip。

接下来翻一翻MaterialEditor的源码

最终VectorProperty的函数实现如下图:

可见,参数只支持一个string类型的lable,但是!!!EditorGUI.Vector4Field明明是支持传入GUIContent的(🤔🤔🤔 Unity 你想干嘛???)

再来看看内部的默认ShaderProperty函数:DefaultShaderPropertyInternal

这个函数明明是传的GUIContent!!!为什么在调用TextureProperty和VectorProperty的时候,你又只用了GUIContent的text,抛弃了ToolTip🤣🤣🤣(Unity,我跟你讲,你不要搞事情啊)

正文

接下来上代码支持各类型Property的ToolTip。先反射DefaultShaderPropertyInternal函数,由于该函数里不支持TextureProperty和VectorProperty的ToolTip,需要额外做些事。

TextureProperty有个重载支持传入ToolTip的,只是DefaultShaderPropertyInternal里没用而已。

定义一个ToolTipDrawer继承至MaterialPropertyDrawer。

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
using System;
using System.Reflection;
using UnityEditor;
using UnityEngine;

public class ToolTipDrawer : MaterialPropertyDrawer
{
private GUIContent _guiContent;
private MethodInfo _internalMethod;
private Type[] _methodArgumentTypes;
private object[] _methodArguments;
private MethodInfo _getPropertyRectMethodInfo;
private object[] _getPropertyRectMethodInfoArguments;

public ToolTipDrawer(string tooltip)
{
_guiContent = new GUIContent(string.Empty, tooltip);
_methodArgumentTypes = new[] {typeof(Rect), typeof(MaterialProperty), typeof(GUIContent)};
_methodArguments = new object[3];
_internalMethod = typeof(MaterialEditor)
.GetMethod("DefaultShaderPropertyInternal", BindingFlags.Instance | BindingFlags.NonPublic,
null,
_methodArgumentTypes,
null);

_getPropertyRectMethodInfo = typeof(MaterialEditor).GetMethod("GetPropertyRect", BindingFlags.Instance | BindingFlags.NonPublic, null,
new[] {typeof(MaterialProperty), typeof(string), typeof(bool)}, null);
_getPropertyRectMethodInfoArguments = new object[3];
}

//拷贝至https://github.com/Unity-Technologies/UnityCsReference/blob/master/Editor/Mono/Inspector/MaterialEditor.cs
private Vector4 VectorProperty(Rect position, MaterialProperty prop, GUIContent content)
{
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = prop.hasMixedValue;
var oldLabelWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 0f;
//修改拷贝出来的函数,修改函数参数和以下content
Vector4 newValue = EditorGUI.Vector4Field(position, content, prop.vectorValue);
EditorGUIUtility.labelWidth = oldLabelWidth;
EditorGUI.showMixedValue = false;
if (EditorGUI.EndChangeCheck())
prop.vectorValue = newValue;
return prop.vectorValue;
}

public override void OnGUI(Rect position, MaterialProperty prop, String label, MaterialEditor editor)
{
_guiContent.text = label;
if (prop.type == MaterialProperty.PropType.Vector)
{
VectorProperty(position, prop, _guiContent);
}
else if (prop.type == MaterialProperty.PropType.Texture)
{
bool scaleOffset = (prop.flags & MaterialProperty.PropFlags.NoScaleOffset) == 0;
_getPropertyRectMethodInfoArguments[0] = prop;
_getPropertyRectMethodInfoArguments[1] = label;
_getPropertyRectMethodInfoArguments[2] = true;
Rect r = (Rect)_getPropertyRectMethodInfo.Invoke(editor,_getPropertyRectMethodInfoArguments);
editor.TextureProperty(r, prop, _guiContent.text, _guiContent.tooltip, scaleOffset);
}
else
{
//其余几个类型,默认就支持
if (_internalMethod != null)
{
_methodArguments[0] = position;
_methodArguments[1] = prop;
_methodArguments[2] = _guiContent;

_internalMethod.Invoke(editor, _methodArguments);
}
}
}
}

再定义一个测试的Shader

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
Shader "Custom/TestToolTip"
{
Properties
{
[ToolTip(This is MainTex)]
_Texture ("Texture", 2D) = "white" {}
[ToolTip(This is Range)]
_Range("Range", Range(0, 1)) = 0.02
[ToolTip(This is Color)]
_Color("Color", Color) = (1,1,1,1)
[ToolTip(This is Float)]
_Float("Float", Float) = 8
[ToolTip(This is Vector)]
_Vector("Vector", Vector) = (1,1,1,1)
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}

fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
}
FallBack "Diffuse"
}

示意图

结尾

通过阅读MaterialEditor源码,还是能收获一些东西的,最后1024节日快乐。

本篇文章,如果有不懂,欢迎留言~click here!

以上知识分享,如有错误,欢迎指出,共同学习,共同进步。如果有不懂,欢迎留言评论!