シェーダを使用する場合に,興味深いデータタイプがあり,Unity ビルトイン シェーダで綺麗に再現できる場合があります。Unityにはデフォルトのマテリアル インスペクタを自身で定義できるようにオーバライドできる方法が用意されています。この機能を用いてカスタムのコントロールおよびデータ範囲のバリデーションをを定義できます。
カスタムのマテリアル エディタを記述する最初の部分は, カスタム エディタ を必要とするシェーダを定義することです。カスタム エディタで使用する名前は Unity でマテリアルエディタをルックアップするときのクラス名です。
カスタム エディタを定義するには,MaterialEditor クラスを拡張し,スクリプトを Assets ディレクトリの中の Editor フォルダにスクリプトを配置します。
using UnityEditor;
public class CustomMaterialInspector : MaterialEditor {
public override void OnInspectorGUI () {
base.OnInspectorGUI ();
}
}
Any shader that has a custom editor defined (CustomEditor “CustomMaterialInspector”) will find the editor listed above and execute the associated code.
So we have a situation where we have a shader that can work in two modes; it renders standard diffuse lighting or it only renders the red components of the source texture. This is achieved using shader multi compilation.
Shader "Custom/Redify" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert
#pragma multi_compile REDIFY_ON REDIFY_OFF
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Alpha = c.a;
#if REDIFY_ON
o.Albedo.gb = (o.Albedo.g + o.Albedo.b) / 2.0;
#endif
}
ENDCG
}
FallBack "Diffuse"
CustomEditor "CustomMaterialInspector"
}
As you can see the shader has two Keywords available for setting: REDIFY_ON and REDIFY_OFF. These can be changed be set on a per material basis by using the shaderKeywords property of the material. below is an editor that does this.
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Linq;
public class CustomMaterialInspector : MaterialEditor {
public override void OnInspectorGUI ()
{
// render the default inspector
base.OnInspectorGUI ();
// if we are not visible... return
if (!isVisible)
return;
// get the current keywords from the material
Material targetMat = target as Material;
string[] keyWords = targetMat.shaderKeywords;
// see if redify is set, then show a checkbox
bool redify = keyWords.Contains ("REDIFY_ON");
EditorGUI.BeginChangeCheck();
redify = EditorGUILayout.Toggle ("Redify material", redify);
if (EditorGUI.EndChangeCheck())
{
// if the checkbox is changed, reset the shader keywords
var keywords = new List<string> { redify ? "REDIFY_ON" : "REDIFY_OFF"};
targetMat.shaderKeywords = keywords.ToArray ();
EditorUtility.SetDirty (targetMat);
}
}
}
The default Unity editor renders all the properties that exist in a shader to the the material editor. Below is a custom material editor that behaves similar to the Unity material editor. Use this example if you wish to manually render the default fields.
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Linq;
public class CustomMatInspector : MaterialEditor {
// this is the same as the ShaderProperty function, show here so
// you can see how it works
private void ShaderPropertyImpl(Shader shader, int propertyIndex)
{
int i = propertyIndex;
string label = ShaderUtil.GetPropertyDescription(shader, i);
string propertyName = ShaderUtil.GetPropertyName(shader, i);
switch (ShaderUtil.GetPropertyType(shader, i))
{
case ShaderUtil.ShaderPropertyType.Range: // float ranges
{
GUILayout.BeginHorizontal();
float v2 = ShaderUtil.GetRangeLimits(shader, i, 1);
float v3 = ShaderUtil.GetRangeLimits(shader, i, 2);
RangeProperty(propertyName, label, v2, v3);
GUILayout.EndHorizontal();
break;
}
case ShaderUtil.ShaderPropertyType.Float: // floats
{
FloatProperty(propertyName, label);
break;
}
case ShaderUtil.ShaderPropertyType.Color: // colors
{
ColorProperty(propertyName, label);
break;
}
case ShaderUtil.ShaderPropertyType.TexEnv: // textures
{
ShaderUtil.ShaderPropertyTexDim desiredTexdim = ShaderUtil.GetTexDim(shader, i);
TextureProperty(propertyName, label, desiredTexdim);
GUILayout.Space(6);
break;
}
case ShaderUtil.ShaderPropertyType.Vector: // vectors
{
VectorProperty(propertyName, label);
break;
}
default:
{
GUILayout.Label("ARGH" + label + " : " + ShaderUtil.GetPropertyType(shader, i));
break;
}
}
}
public override void OnInspectorGUI ()
{
serializedObject.Update ();
var theShader = serializedObject.FindProperty ("m_Shader");
if (isVisible && !theShader.hasMultipleDifferentValues && theShader.objectReferenceValue != null)
{
float controlSize = 64;
EditorGUIUtility.LookLikeControls(Screen.width - controlSize - 20);
EditorGUI.BeginChangeCheck();
Shader shader = theShader.objectReferenceValue as Shader;
for (int i = 0; i < ShaderUtil.GetPropertyCount(shader); i++)
{
ShaderPropertyImpl(shader, i);
}
if (EditorGUI.EndChangeCheck())
PropertiesChanged ();
}
}
}