Unity Shader - multi_compile 变体测试

Code

脚本的注释可以按看,有些说明,与技巧

Main Testing script - 主要测试的脚本

// jave.lin 2019.06.24
using UnityEngine;

public enum AMBIENT_TOGGLE
{
    On,
    Off
}

public enum AMBIENT_COLOR_TYPE
{
    LightModel,
    Sky,
    Equator,
    Ground
}

public enum AMBIENT_APPLY_ONLY_R
{
    On,
    Off
}

public class TestMultiCompile : MonoBehaviour
{
    public AMBIENT_TOGGLE ambientToggle = AMBIENT_TOGGLE.On;
    public AMBIENT_COLOR_TYPE ambientColorType = AMBIENT_COLOR_TYPE.LightModel;
    public AMBIENT_APPLY_ONLY_R ambientApplyOnlyR = AMBIENT_APPLY_ONLY_R.Off;
    public string[] enabledLocalKeywords;

    private MeshRenderer[] mrs;
    // Start is called before the first frame update
    void Start()
    {
        mrs = GetComponentsInChildren<MeshRenderer>();
        //避免有时你在退出unity运行时,有些开关的状态还是退出钱的设置,所以这里需要初始化一下
        //string[] allGlobalKeywords = { ... }; // 所有你想控制的全局关键字数组
        //for (int i = 0; i < allGlobalKeywords.Length; i++)
        //{
        //  Shader.DisableKeyword(allGlobalKeywords[i]);
        //}
        //然后有些需要Enable的,可以在下面这里再Enable
        //对局部的关键字就不需要上面的处理,因为你可以从Material.shaderKeywords里很容易看出来
        //对关键字的维护,可以参考TestMultiCompileEditor.cs的写法(目前是简单的写法)
    }

    // Update is called once per frame
    void Update()
    {
        // 应用优先级会被Shader.material.Enable/DisableKeyword覆盖
        if (ambientToggle == AMBIENT_TOGGLE.On)
            Shader.EnableKeyword("AMBIENT_ON");
        else
            Shader.DisableKeyword("AMBIENT_ON");

        // 下面的Enable/DisableKeyword都可以封装一下,用分组的方式,让同一组的互斥就好了
        switch (ambientColorType)
        {
            case AMBIENT_COLOR_TYPE.LightModel:
                Shader.EnableKeyword("LIGHTMODEL_AMBIENT");
                Shader.DisableKeyword("SKY_COLOR");
                Shader.DisableKeyword("EQUATOR_COLOR");
                Shader.DisableKeyword("GROUND_COLOR");
                break;
            case AMBIENT_COLOR_TYPE.Sky:
                Shader.DisableKeyword("LIGHTMODEL_AMBIENT");
                Shader.EnableKeyword("SKY_COLOR");
                Shader.DisableKeyword("EQUATOR_COLOR");
                Shader.DisableKeyword("GROUND_COLOR");
                break;
            case AMBIENT_COLOR_TYPE.Equator:
                Shader.DisableKeyword("LIGHTMODEL_AMBIENT");
                Shader.DisableKeyword("SKY_COLOR");
                Shader.EnableKeyword("EQUATOR_COLOR");
                Shader.DisableKeyword("GROUND_COLOR");
                break;
            case AMBIENT_COLOR_TYPE.Ground:
                Shader.DisableKeyword("LIGHTMODEL_AMBIENT");
                Shader.DisableKeyword("SKY_COLOR");
                Shader.DisableKeyword("EQUATOR_COLOR");
                Shader.EnableKeyword("GROUND_COLOR");
                break;
            default:
                break;
        }

        SetApplyOnlyR(ambientApplyOnlyR);

        // material.shaderKeywrods只会返回局部的关键字,所以Shader.EnableKeyword设置的是不会在这增加的
        enabledLocalKeywords = mrs[0].material.shaderKeywords;
    }

    private void SetApplyOnlyR(AMBIENT_APPLY_ONLY_R v)
    {

        for (int i = 0; i < mrs.Length; i++)
        {
            var mr = mrs[i];
            switch (v)
            {
                case AMBIENT_APPLY_ONLY_R.On:
                    mr.sharedMaterial.EnableKeyword("AMBIENT_ONLY_R");
                    break;
                case AMBIENT_APPLY_ONLY_R.Off:
                    mr.sharedMaterial.DisableKeyword("AMBIENT_ONLY_R");
                    break;
                default:
                    break;
            }
        }
    }
}

Editor - 编辑器Inspector扩展

// jave.lin 2019.06.24
using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(TestMultiCompile))]
public class TestMultiCompileEditor : Editor
{
    // 可以从配置中读取
    private string[][] globalKeywordList =
    {
        new string[]{ "AMBIENT_ON", },  // group one
        new string[]{                   // group two
        "LIGHTMODEL_AMBIENT",
        "SKY_COLOR",
        "EQUATOR_COLOR",
        "GROUND_COLOR",
        }
    };
    // 可以从配置中读取
    private string[][] localKeywordList =
    {
        new string[] {"AMBIENT_ONLY_R", }   // group
    };

    private Material m;

    private bool globalKeywordFoldSummary = true;
    private bool localKeywordFoldSummary = true;

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        
        if (m == null)
            m = AssetDatabase.LoadAssetAtPath<Material>("Assets/Materials/TestMulitCompile.mat");
        
        int idx = 0;
        const int indent = 1;
        // global
        globalKeywordFoldSummary = EditorGUILayout.Foldout(globalKeywordFoldSummary, "Global Keyword Summary");
        if (globalKeywordFoldSummary)
        {
            EditorGUI.indentLevel += indent;
            idx = 0;
            foreach (var kws in globalKeywordList)
            {
                EditorGUILayout.Foldout(true, $"Global Keyword_Group{idx++}");
                foreach (var kw in kws)
                {
                    EditorGUILayout.Toggle(kw, Shader.IsKeywordEnabled(kw));
                }
            }
            EditorGUI.indentLevel -= indent;
        }

        // local
        localKeywordFoldSummary = EditorGUILayout.Foldout(localKeywordFoldSummary, "Local Keyword Summary");
        if (localKeywordFoldSummary)
        {
            EditorGUI.indentLevel += indent;
            idx = 0;
            foreach (var kws in localKeywordList)
            {
                EditorGUILayout.Foldout(true, $"Local Keyword_Group{idx++}");
                foreach (var kw in kws)
                {
                    EditorGUILayout.Toggle(kw, m.IsKeywordEnabled(kw));
                }
            }
            EditorGUI.indentLevel -= indent;
        }
    }
}

Shader Code

// jave.lin 2019.06.23
Shader "Test/TestMultiCompile"{
    SubShader{
        Pass{
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // ====global keyword start====
            #pragma multi_compile __ AMBIENT_ON // 2个选项,定义multi_compile keyword 开关,_ 表示未选
            #pragma multi_compile __ LIGHTMODEL_AMBIENT SKY_COLOR EQUATOR_COLOR GROUND_COLOR // 5个选项,定义颜色选用的关键字
            // ====global keyword end====
            // ====local keyword start====
            #pragma multi_compile_local __ AMBIENT_ONLY_R // 2个选项,环境光颜色只有R通道的开关
            // ====local keyword end====
            #include "UnityCG.cginc"
            float4 vert (float4 vertex : POSITION) : SV_POSITION { return UnityObjectToClipPos(vertex); }
            fixed4 frag () : SV_Target{
                fixed4 col = fixed4(1,1,1,1);
                #if AMBIENT_ON // 判断开关而使用环境色调
                    #if AMBIENT_ONLY_R // 仅使用R通道的
                        #if LIGHTMODEL_AMBIENT // 光照综合处理后的系数
                        col.rgb *= UNITY_LIGHTMODEL_AMBIENT.r;
                        #elif SKY_COLOR
                        col.rgb *= unity_AmbientSky.r;
                        #elif EQUATOR_COLOR
                        col.rgb *= unity_AmbientEquator.r;
                        #elif GROUND_COLOR
                        col.rgb *= unity_AmbientGround.r;
                        #else
                        // nops
                        #endif
                    #else
                        #if LIGHTMODEL_AMBIENT // 光照综合处理后的系数
                        col.rgb *= UNITY_LIGHTMODEL_AMBIENT.rgb;
                        #elif SKY_COLOR
                        col.rgb *= unity_AmbientSky.rgb;
                        #elif EQUATOR_COLOR
                        col.rgb *= unity_AmbientEquator.rgb;
                        #elif GROUND_COLOR
                        col.rgb *= unity_AmbientGround.rgb;
                        #else
                        // nops
                        #endif
                    #endif
                #endif
                return col;
            }
            ENDCG
        }
    }
}

Shader Variants

在这里插入图片描述
图中variants included有20个

那么20个变体是怎么生成的呢?
我们才定义了那么几个关键字,生成就这么多了

compile and show code 右边有个下拉按钮,点击后有个小面板,再点击小面板中的 show 按钮。

Shader Variants Combines

点击面板中的 show 按钮后,我们在脚本中看到它是如何确定20个变体的

// Total snippets: 1
// -----------------------------------------
// Snippet #0 platforms ffffffff:
Keywords always included into build: AMBIENT_ON LIGHTMODEL_AMBIENT SKY_COLOR EQUATOR_COLOR GROUND_COLOR AMBIENT_ONLY_R // 我们定义的关键字列表,该shader中的全局,局部关键字都列在这

20 keyword variants used in scene: // 共有20个关键字

// 下面是所有可能的变体组合情况,这里就是变体的数量
// 我们就不要一个一个数了
// 它是通过每行的 multi_compile 的数量相乘的总数
// 例如:有3行multi_compile,每行分别有2,3,4个,那么总数就有2*3*4=24
// 所以我们的multi_compile行定义越多,影响的系数越大。
<no keywords defined> // 我们手写无定义的:__或是_,或是不写,Unity也会默认生出的项
AMBIENT_ONLY_R
LIGHTMODEL_AMBIENT
AMBIENT_ONLY_R LIGHTMODEL_AMBIENT
SKY_COLOR
AMBIENT_ONLY_R SKY_COLOR
EQUATOR_COLOR
AMBIENT_ONLY_R EQUATOR_COLOR
GROUND_COLOR
AMBIENT_ONLY_R GROUND_COLOR
AMBIENT_ON
AMBIENT_ON AMBIENT_ONLY_R
AMBIENT_ON LIGHTMODEL_AMBIENT
AMBIENT_ON AMBIENT_ONLY_R LIGHTMODEL_AMBIENT
AMBIENT_ON SKY_COLOR
AMBIENT_ON AMBIENT_ONLY_R SKY_COLOR
AMBIENT_ON EQUATOR_COLOR
AMBIENT_ON AMBIENT_ONLY_R EQUATOR_COLOR
AMBIENT_ON GROUND_COLOR
AMBIENT_ON AMBIENT_ONLY_R GROUND_COLOR



Runtime

Lighting - Environment Lighting

菜单:Windows->Rendering->Lighting Settings->Scene Tab

Scene Tab->Environment->Environment Lighting
在这里插入图片描述
将场景的环境光的Source设置为:Gradient,分别设置Sky,Equator,GroundColor颜色为:红,绿,蓝,因为我们的shader用到

Inspector Informations

在这里插入图片描述
在Global Keyword Summary与Local Keyword Summary都可以很方便看到关键字的的开关情况

  • Ambient Toggle 是控制Shader里头使用是否使用AMBIENT_ON 变体代码。
  • Ambient Color Type 对应就是环境光的颜色
  • Ambient Apply Only R 是否对环境观值应用R通道,On:是,那么环境光R通道将影响整体亮度;Off:否,那么环境光RGB通道将影响整体色调

其中 Ambient Toggle、Amibent Color Type都是全局关键字,Amibent Apply Only R是局部关键字

某个shader有多少个全局、局部关键字,都可以通过在Shader Inspector->…按钮,然后弹出的面板中可以看到

如下图:
Global Keywords:
在这里插入图片描述
Local Keywords:
在这里插入图片描述

Scene View

在这里插入图片描述
最后开启 AmbientApplyOnlyR就花屏了,然后用Ground Color的R通道就可以设置亮度了

Project

MultiCompileTest 提取码: gdck

References

Making multiple shader program variants 制作shader程序多变体

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值