Shader变体(Shader Variants)是什么?

  • 定义:通过预处理器指令(如 #if)动态修改Shader代码分支,生成不同功能的Shader实例。
  • 用途:实现动态光照、平台适配、画质分级等功能,避免运行时分支判断开销。
  • 代价:变体过多会导致包体增大、编译时间增长、内存占用上升。

两种变体

multi_compile

强制编译所有组合:无论是否使用,声明中的所有变体组合都会被编译。

  • 语法
    GLSL
    #pragma multi_compile A B C    // 生成变体:A, B, C
    #pragma multi_compile _ D E   // 生成变体:<空>, D, E
    点击展开查看更多
  • 典型场景
    • 需运行时动态切换的功能(如昼夜系统)
    • 全局开关(如 DEBUG 模式)
  • 缺点:易导致变体爆炸(多个 multi_compile 会组合叠加)。

shader_feature

按需编译:仅编译材质实际使用的变体(依赖材质参数或Keywords设置)。

  • 语法
    GLSL
    #pragma shader_feature _TOON _CELLSHADING  // 只编译材质启用的Keyword
    点击展开查看更多
  • 典型场景
    • 材质专属功能(如风格化渲染选项)
    • 不频繁切换的静态效果
  • 关键限制:变体仅包含在最终Build中需满足:
    1. 材质显式启用了该Keyword
    2. Shader中通过 #pragma shader_feature 声明
    3. 变体被场景或Resources文件夹引用

示例代码

GLSL
Shader "Custom/Example" {
    Properties {
        [Toggle(TOON)] _UseToon ("Toon Shading", Int) = 0
    }

    SubShader {
        Pass {
	        // 1. 使用multi_compile
	        #pragma multi_compile _ TOON
	        #pragma multi_compile TOON  // 缺少空变体"_"
	        // 2. 使用shader_feature
            #pragma shader_feature TOON
            #pragma shader_feature _ TOON

            #ifdef TOON
                // 卡通渲染逻辑
            #else
	            // 其他渲染逻辑
	        #endif
        }
    }
}
点击展开查看更多

解析

  • multi_compile
    • 会强制编译所有组合。在代码2.中,包含空变体变体_ 和 变体TOON
    • 第一个变体为常开变体,故一般情况下第一个变体为空变体_
  • shader_feature
    • 仅编译启用的组合;
    • 当仅有一个变体时,可以不需要添加空变体_
    • 当有多个变体时,第一个变体为常开变体,故一般情况下第一个变体为空变体_

区别对比

特性 multi_compile shader_feature
编译策略 强制编译所有组合 按材质实际使用编译
包体影响 可能包含未使用变体 仅包含被引用的变体
运行时切换 支持(Material.EnableKeyword 支持,但需预编译进包
适用场景 全局/高频切换功能 材质级/低频切换功能
变体丢失风险 高(未引用的材质变体会被剔除)

优化变体数量

  • 优先用 shader_feature:减少未使用变体的编译。
  • 避免冗余组合
    GLSL
    // 错误:生成 3x3=9 个变体
    #pragma multi_compile A B C
    #pragma multi_compile D E F
    
    // 正确:合并为单一声明
    #pragma multi_compile A_D A_E A_F B_D ... // 显式控制组合
    点击展开查看更多
  • 使用 #pragma skip_variants:跳过指定变体编译。
  • 限制Keyword数量:N个Keyword → 2^N个变体(慎用!)。

变体管理

  1. 变体收集
    • 方法:Edit > Project Settings > Graphics > Shader Stripping
    • 添加需保留的变体Keyword(仅对 shader_feature 生效)。
  2. 调试工具
    • 查看编译结果:在Shader Inspector点击 「Compile and Show Code」
    • 检查当前Keyword:ShaderVariantCollection 资源。
  3. 代码中切换Keyword
    CSHARP
    material.EnableKeyword("_TOON");  // 启用变体分支
    material.DisableKeyword("_CELLSHADING");
    点击展开查看更多

版权声明

作者: Cheyne Xie

链接: https://chaim.eu.org/posts/8f3f5154/

许可证: CC BY-NC-SA 4.0

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. Please attribute the source, use non-commercially, and maintain the same license.

开始搜索

输入关键词搜索文章内容

↑↓
ESC
⌘K 快捷键