Shader筆記——自定義Material面板

Unity為用戶提供了專門快速實現(xiàn)自定義材質(zhì)面板的基礎類:MaterialPropertyDrawer。

1.0不同類型的DrawerClass

類型 描述
ToggleDrawer 將float類型數(shù)據(jù)顯示為開關,數(shù)值只能是0(關閉)或1(開啟)
EnumDrawer 枚舉會將float型數(shù)據(jù)顯示為下拉列表,可以用于選擇混合系數(shù),比較方法等,也可以自定義
KeywordEnumDrawer 和EnumDrawer類似,但是需要先定義shader keyword才能使用
PowerSliderDrawer 指數(shù)對應關系的滑動條,滑動條上的數(shù)值不再按照線性關系進行對應
IntRangeDrawer 將范圍型的數(shù)據(jù)顯示為只能設置整數(shù)的滑動條

在編寫Shader的時候,DrawerClass需要寫在對應屬性之前的“[]”中,類別的后綴名稱“Drawer”不需要添加,因為Unity在編輯的時候會自動添加。

1.1 Toggle

將float類型的數(shù)據(jù)以開關的形式在材質(zhì)屬性面板上顯示,數(shù)值只能設置為0或1,0為關閉,1為開啟,Shader keyword會被Unity默認設置為“property name”+“_ON”,需要注意的一點是,關鍵詞的所有字母必須大寫。如:

// Shader的關鍵詞會被設置為_INVERT_ON
[Toggle] _Invert ("Invert color?", Float) = 0

除了使用Unity默認的關鍵詞,也可以自定義一個特殊的關鍵詞,如:

// ENABLE_FANCY即為自定義的Shader關鍵詞
[Toggle(ENABLE_FANCY)] _Fancy ("Fancy?", Float) = 0

1.2 Enum

Enum將float類型的數(shù)據(jù)以下拉列表的形式在材質(zhì)面板上顯示,Unity為用戶提供了一些內(nèi)置的枚舉類,如BlendMode,CompareFunction。如:

[Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend("Src Blend Mode", Float)=1
在材質(zhì)設置面板中選擇混合系數(shù)

用戶也可以自定義枚舉的名稱/數(shù)值對,但是一個枚舉最多只能自定義7個名稱/數(shù)值對。如:

[Enum(Off, 0, On, 1)] _ZWrite ("ZWrite", Float) = 0
自定義枚舉的名稱/數(shù)值對

1.3 KeywordEnum

KeywordEnum跟Enum類似,不過KeywordEnum會有與之對應的Shader keyword,在Shader中通過# pragma shader_feature# pragma multi_compile指令可以或者關閉某一部分Shader代碼。
Shader keyword格式為:property name_enum name,屬性名稱+"下劃線"+枚舉名稱,所有英文必須大寫,并且最多支持9個關鍵詞。如:

// 對應的Shader keyword分別為:_OVERLAY_NONE,_OVERLAY_ADD,_OVERLAY_MULTIPLY
[KeywordEnum(None, Add, Multiply)] _Overlay ("Overlay mode", Float) = 0

1.4 PowerSlider

PowerSlider會將范圍型數(shù)值的屬性顯示為非線性對應的滑動條?;瑒訔l上的值不再按照線性關系進行對應,而是以指數(shù)的方式。如:

 [PowerSlider(3.0)] _Brightness ("Brightness", Range (0.01, 1)) = 0.1

這是一個以3為指數(shù)對應關系的滑動條,括號內(nèi)的數(shù)值為指數(shù)。
曲線y=x^3,函數(shù)中的變量x就是滑動塊所在位置,y就是屬性的數(shù)值。


PowerSlider

1.5 InRange

IntRange也是將數(shù)值以滑動條的形式在材質(zhì)屬性面板上顯示,只不過數(shù)值不再是float類型,只能是整數(shù)型數(shù)值,如:

[IntRange] _Alpha ("Alpha", Range (0, 255)) = 100

只能在滑動條上使用區(qū)間[0,255]之內(nèi)的整數(shù)值。


IntRange

2.0 在編譯指令中定義Keyword

定義了ToggleDrawer或者KeywordEnumDrawer之后,如果想要正常使用,還需要在編譯指令中聲明Shader keyword。如:

#pragma shader_feature _OVERLAY_NONE _OVERLAY_ADD _OVERLAY_MULTIPLY

或者

#pragma multi_compile _OVERLAY_NONE _OVERLAY_ADD _OVERLAY_MULTIPLY

不同keyword之間需要用空格隔開。

雖然表面上看似通過一個Shader文件實現(xiàn)了不同種情況,但是Unity會自動將不同情況編譯成不同版本的Shader文件,這些不同版本的Shader文件被稱為Shader變體(Variants),上述編譯指令中包含三個Shader變體。
假設在添加一個指令:

#pragma shader_feature _INVERT_ON

本指令包含Toggle的關閉與開啟倆種情況,所以Unity最終會編譯出2x3=6個Shader變體。

倆種不同編譯指令之間的區(qū)別如下:
<1>shader_feature:只會為材質(zhì)使用到的keyword生成變體,沒有使用到的keyword不會生產(chǎn)變體,因此無法在運行的時候通過腳本切換效果。
<2>multi_compile:會為所有keyword生產(chǎn)變體,因此可以在運行的時候通過腳本切換效果。

在Shader文件的屬性設置面板中可以查看到本Shader生成的變體數(shù)量。
開啟Skip unused shader_features選項可以只查看使用keyword的變體數(shù)量。
關閉Skip unused shader_features選項查看所有keyword的變體數(shù)量。
如果需要確定具體變體有哪些keyword組成,可以單擊Show查看。

查看Shader的變體數(shù)量

3.0 屬性的特性和Drawer

如果需要對開放出來的屬性進行一些限制,可以對屬性的特性和Drawer進行修改,這些修改命令需要寫在屬性語句之前。

指令 描述
[HideInInspector] 可以添加到任何Property之前,使屬性在材質(zhì)面板上隱藏
[NoScaleOffset] 添加在2D Property之前,可以在材質(zhì)面板上隱藏紋理貼圖的Tiling和Offset選項
[Normal] 添加在2D Property之前,可以檢測關聯(lián)的紋理貼圖是否為法線貼圖,如果不是,則會彈出修復提示
[HDR] 添加在2D或Color Property之前,可以是屬性開啟HDR效果,從而使數(shù)值突破1的限制,常用于自發(fā)光屬性

4.0 裝飾性 PropertyDrawer

裝飾性的PropertyDrawer只起到界面美觀作用,不會影響屬性本身。

類型 描述
SpaceDecorator 在材質(zhì)屬性面板上添加空白行
HeaderDecorator 在材質(zhì)屬性面板上添加標題文字

在編寫Shader的時候,類別的后綴名稱“Decorator”依然不需要添加,Unity在編譯的時候會自動添加。

4.1 SpaceDecorator

SpaceDecorator可以在屬性之前添加空白行,以起到分割屬性的作用。如:

[Space]_MainTex ("Main Tex", 2D) = "white" {}

可以在后邊直接寫上空白行的數(shù)量,如:

[Space(30)]_MainTex ("Main Tex", 2D) = "white" {}

4.2 HeaderDecorator

當Shader開放了很多屬性的時候,可以使用HeaderDecorator在屬性前添加一個標題文字,從而對不同類別的屬性進行區(qū)分。如:

[Header(Custom Material Inspector)]
HeaderDecorator

5.0 完整PropertyDrawer示列

Shader "Custom/Custom Material Inspector"
{
    Properties
    {
        // 在材質(zhì)面板插入一行標題
        [Header(Custom Material Inspector)]

        // 在材質(zhì)面板插入一行空白行,可以寫在單獨一行
        [Space]
        _MainTex ("Main Tex", 2D) = "white" {}

        // 在材質(zhì)面板上隱藏Tiling和Offset
        [NoScaleOffset] _SecondTex ("Second Tex", 2D) = "white" {}

        // 在材質(zhì)面板插入30行空白行,可以寫在單獨一行
        [Space(30)]

        // 開關
        [Toggle] _Invert ("Invert color?", Float) = 0

        // 自定義Shader關鍵詞的開關
        [Toggle(ENABLE_FANCY)] _Fancy ("Fancy?", Float) = 0

        // Unity內(nèi)置的枚舉下拉菜單
        [Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend("Src Blend Mode", Float)=1
        [Enum(UnityEngine.Rendering.BlendMode)] _DstBlend("Dst Blend Mode", Float)=1
        [Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull Mode", Float) = 1
        [Enum(UnityEngine.Rendering.CompareFunction)] _ZTest ("ZTest", Float) = 0

        // 自定義枚舉下拉菜單
        [Enum(Off, 0, On, 1)] _ZWrite ("ZWrite", Float) = 0
        
        // 關鍵詞枚舉下拉菜單
        [KeywordEnum(None, Add, Multiply)] _Overlay ("Overlay mode", Float) = 0

        // 指數(shù)滑動條
        [PowerSlider(3.0)] _Brightness ("Brightness", Range (0.01, 1)) = 0.1
        // 整數(shù)滑動條
        [IntRange] _Alpha ("Alpha", Range (0, 255)) = 100
    }
    SubShader
    {
        Tags { "Queue"="Transparent" "RenderType"="Transparent" }
        Blend [_SrcBlend] [_DstBlend]
        Cull [_Cull]
        ZTest [_ZTest]
        ZWrite [_ZWrite]

        Pass
        {
            CGPROGRAM

            // 通過"#pragma shader_feature"定義 _INVERT_ON shader關鍵詞
            #pragma shader_feature _INVERT_ON

            // 通過"#pragma shader_feature"定義 ENABLE_FANCY shader關鍵詞
            #pragma shader_feature ENABLE_FANCY

            // 通過"#pragma multi_compile"定義關鍵詞枚舉的每一個shader關鍵詞
            #pragma multi_compile _OVERLAY_NONE _OVERLAY_ADD _OVERLAY_MULTIPLY

            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _SecondTex;
            float4 _SecondTex_ST;
            float _Brightness;

            struct v2f
            {
                float4 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata_base v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
                o.uv.zw = TRANSFORM_TEX(v.texcoord, _SecondTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_TARGET
            {
                fixed4 col = tex2D(_MainTex, i.uv.xy);

                // 通過 #if, #ifdef 或者 #if defined啟用某一部分代碼
                #if _INVERT_ON
                col = 1 - col;
                #endif

                #if ENABLE_FANCY
                col.r = 0.5;
                #endif

                fixed4 secCol = tex2D(_SecondTex, i.uv.zw);

                #if _OVERLAY_ADD
                col += secCol;
                #elif _OVERLAY_MULTIPLY
                col *= secCol;
                #endif

                col *= _Brightness;

                return col;
            }
            ENDCG
        }
    }
}
自定義材質(zhì)面板效果
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容