Unity_ShaderLab笔记

什么是ShaderLab?

在图形API中有:OpenGL,DX,Vulkan等。Unity为了处理不同平台使用的Shader语言的差异,就用ShaderLab封装起来,最后根据不同平台编译成对应的着色器语言。

UnityShader 结构图:

Shader
SubShader
SubShader
SubShader
Pass
Pass
Program:Vertex
Program:Fragment
SubProgram:Variant 1
SubProgram:Variant 2

Shader 变体

1.什么是变体

官网介绍
在上面的结构图最底下的Variant就是变体部分,如下所示frag中有三个判断分支,Unity就会产生多个Shader变体。如果变体数量太多就会增加内存消耗,一般ShaderLab占用内存在30-70M左右,如果超出太多就要考虑优化变体数量。

        fixed4 frag (v2f i) : SV_Target
            {
                #if _OVERLAY_1
                	col += secCol;
                #elif _OVERLAY_2
                	col *= secCol;
                #endif
                	col *= _OtherCol;
                return col;
            }

2.变体的产生

主要是在Shader中使用了:#pragma shader_feature#pragma multi_compile起到宏的作用。不一样的是 shader_feature 没有用到的不会被包含进去, 而 multi_compile全部版本都会被包含,因此 shader_feature 适用于那些会在材质面板中直接设置的情况,但在脚本里通过DisableKeyword 和 EnableKeyword 来开启或关闭 keyword 的话就要使用 multi_compile

3.变体数量计算

Case1
#pragma multi_compile A B C
#pragma multi_compile D E
如果shader中使用了以上两个multi_compile那么不管后面是否使用到宏(A,B,C,D,E)它都会产生变体,这样计算的方法是(A,B,C)(D,E) => 32=>6。
Case2
#pragma multi_compile A B C
#pragma shader_feature D E
这里有两个shader_feature,当他们启用才会产生变体因此有以下几种组合情况:
(A+D,B+D,C+D) ,(A+E,B+E,C+E),(A+D,B+D,C+D,A+E,B+E,C+E)
Case3
#pragma multi_compile A B C
#pragma shader_feature _ D E
这里的(’_’)表示空,当D或E启用时会产生:(A,B,C,A+D,B+D,C+D) 或 (A,B,C,A+E,B+E,C+E)

4.变体查看

Unity在编辑器里提供了变体查看的方法,我们在shader中添加#pragma shader_feature_local CS_BOOL为例演示如何查看:
在这里插入图片描述
1.选中shader,在inspector面板中有个Keywords,它里面包含了全局和本地的所有keword。
2.点击inspector上的Compiled code右边的倒三角,再点击弹出框内的Show按钮即可看到当前shader用到的Keyword。

5.减少变体

1.shader内剔除
我们可以在shader中使用#pragma skip_variants来剔除不想要的Keyword变体。如下所示在shader中添加#pragma skip_variants CS_BOOL后就可以屏蔽该Keyword。
在这里插入图片描述

2.Build时剔除(只能用于Global )
使用以下方法剔除时发现无法把Local类型的keyword剔除掉,如果有哪位晓得方法麻烦留言指导下哈,非常感谢。

using System.Collections;
using System.Collections.Generic;
using UnityEditor.Build;
using UnityEditor.Rendering;
using UnityEngine;
using UnityEngine.Rendering;

namespace ZYF
{
    /// <summary>
    /// 在Build时剔除shader keyword
    /// </summary>
    public class ZYF_Test_ShaderKeywordStripping : IPreprocessShaders
    {
        public int callbackOrder => 0;

        //要剔除的keyword
        ShaderKeyword cs_bool_keyword;
        public ZYF_Test_ShaderKeywordStripping()
        {
            cs_bool_keyword = new ShaderKeyword("CS_BOOL");
        }
        public void OnProcessShader(Shader shader, ShaderSnippetData snippet, IList<ShaderCompilerData> data)
        {
            List<ShaderCompilerData> strippingList = new List<ShaderCompilerData>();
            //收集要剔除的data
            for (int i = 0, length = data.Count; i < length; i++)
            {
                if (data[i].shaderKeywordSet.IsEnabled(cs_bool_keyword))
                {
                    strippingList.Add(data[i]);
                }
            }
            //剔除收集到的data
            strippingList.ForEach(d =>
            {
                data.Remove(d);
            });
        }
    }
}

6.变体在Editor中的生成过程

在这里插入图片描述

Shader Load

Shader预加载

使用ShaderVariantCollection预加载指定Shader
官方说明
ShaderVariantCollection里记录着每个shader里真正使用到的变体,它可以用来预加载shader。
1.首先进入运行模式并让摄像机看到整个场景,然后到ProjectSettings/Graphics的最下方点击Save to asset保存。
2.把保存的SVC文件放到Project Settings/Graphics 中的Preloaded Shaders中,这样就能预加载shader了,当然你可以按需求修改SVC内容。
3.还可以在代码中进行预加载(因为预加载比较耗时最好放在加载场景中执行):Shader.WarmupAllShaders(预加载所有shader) 和ShaderVariantCollection.Warmup(加载指定SVC中的shader)。

发布了30 篇原创文章 · 获赞 5 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_26318597/article/details/104388522
今日推荐