Unity3D的内置宏 _ADDITIONAL_LIGHTS_VERTEX

Table of Contents

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com

在Unity URP中,_ADDITIONAL_LIGHTS_VERTEX 是一个与 附加光源处理方式 相关的内置变体关键字(Shader Variant Keyword)。它的核心作用是 控制附加光源的光照计算阶段,决定是在 顶点着色器 还是 片元着色器 中处理附加光源的贡献。


核心含义

1. 光源计算阶段选择

  • 启用时_ADDITIONAL_LIGHTS_VERTEX 被定义):
    附加光源的光照计算在 顶点着色器 阶段完成,计算结果通过顶点插值传递到片元着色器。
  • 未启用时(默认或使用 _ADDITIONAL_LIGHTS):
    附加光源的光照计算在 片元着色器 阶段逐像素完成。

2. 性能与质量的权衡

模式 性能消耗 光照精度 适用场景
_ADDITIONAL_LIGHTS_VERTEX 较低 中等(顶点插值) 移动端、低性能设备
_ADDITIONAL_LIGHTS 较高 高(逐像素) PC/主机、高质量渲染需求

触发条件

该宏的激活由以下因素决定:

  1. URP Asset设置

    • 在URP资源中启用 Additional Lights(附加光源)
    • 设置 Per Object Light 类型为 VertexFragment(对应不同模式)
  2. Shader编译指令
    在Shader中使用以下指令声明变体:

    #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
    
  3. 实际光源数量
    当场景中存在 附加光源(点光源、聚光灯等) 且影响当前渲染对象时,Unity自动选择对应变体。


技术实现原理

顶点着色器阶段处理(_ADDITIONAL_LIGHTS_VERTEX

// 顶点着色器中计算附加光源
Varyings vert(Attributes input) {
    Varyings output;
    // ...
    #ifdef _ADDITIONAL_LIGHTS_VERTEX
        output.vertexLighting = CalculateVertexLights(input.positionWS);
    #endif
    return output;
}

片元着色器阶段处理(_ADDITIONAL_LIGHTS

// 片元着色器中计算附加光源
half4 frag(Varyings input) : SV_Target {
    // ...
    #ifdef _ADDITIONAL_LIGHTS
        half3 additionalLights = CalculateFragmentLights(input.positionWS);
    #endif
    return color;
}

典型应用场景

1. 顶点着色器模式(优化性能)

  • 代码特征
    在顶点输出结构体(Varyings)中存储预计算的光照值:
    struct Varyings {
        float4 positionCS : SV_POSITION;
        #if defined(_ADDITIONAL_LIGHTS_VERTEX)
            half3 vertexLighting : TEXCOORD5; // 存储顶点光照结果
        #endif
    };
    
  • 视觉效果
    光照过渡呈现顶点插值的“块状”效果,适用于动态物体或低精度需求场景。

2. 片元着色器模式(追求质量)

  • 代码特征
    在片元着色器中直接调用光照计算函数:
    half4 frag(Varyings input) : SV_Target {
        InputData lightingData = ...;
        #if defined(_ADDITIONAL_LIGHTS)
            additionalLights += GetAdditionalLights(lightingData);
        #endif
    }
    
  • 视觉效果
    光照过渡平滑,适用于静态高精度场景(如角色面部、复杂材质)。

调试与手动控制

1. 强制指定模式(测试用)

在Shader顶部添加定义:

#define _ADDITIONAL_LIGHTS_VERTEX // 强制顶点模式
// #define _ADDITIONAL_LIGHTS     // 强制片元模式

2. 查看当前激活模式

通过条件编译判断:

#if defined(_ADDITIONAL_LIGHTS_VERTEX)
    // 当前为顶点光照模式
#elif defined(_ADDITIONAL_LIGHTS)
    // 当前为片元光照模式
#endif

3. 性能分析工具

使用 Unity ProfilerFrame Debugger 观察:

  • 顶点模式:SRPBatcher 提交批次更多,但GPU负载更低
  • 片元模式:Draw Call数量可能减少,但片元计算压力更大

常见问题与解决方案

问题 1:附加光源不生效

  • 可能原因
    未正确声明变体或URP设置中附加光源被禁用。
  • 解决方案
    1. 检查Shader中的 #pragma multi_compile 指令
    2. 确认URP Asset中 Additional Lights > Mode 未设置为 Not Enabled

问题 2:光照出现明显锯齿

  • 现象
    使用顶点模式时,光源边缘呈现块状过渡。
  • 优化方案
    1. 切换为片元模式(_ADDITIONAL_LIGHTS
    2. 增加受影响物体的顶点密度
    3. 使用光照贴图烘焙静态光源

问题 3:Shader变体爆炸

  • 现象
    multi_compile 组合过多导致构建时间过长。
  • 优化方案
    1. 使用 shader_feature 替代 multi_compile
    2. 在URP Asset中限制最大附加光源数量:
      // URP Asset设置路径
      Graphics > URP Global Settings > Lighting > Additional Lights > Per Object Limit
      

最佳实践建议

  1. 移动端优先策略

    • 默认启用 _ADDITIONAL_LIGHTS_VERTEX
    • 通过URP Asset设置 Per Object Limit = 1-4
    • 使用LOD系统动态切换光源模式
  2. 高质量场景配置

    • 启用 _ADDITIONAL_LIGHTS
    • 结合 Screen Space ShadowsLight Layers
    • 使用 Compute Shader 处理复杂光源
  3. 混合模式设计
    在Shader中实现动态切换逻辑:

    half3 GetAdditionalLights(InputData input) {
        #if defined(_ADDITIONAL_LIGHTS_VERTEX)
            return input.vertexLighting;
        #elif defined(_ADDITIONAL_LIGHTS)
            return CalculatePerPixelLights(input);
        #endif
    }
    

通过合理使用 _ADDITIONAL_LIGHTS_VERTEX,开发者可以在渲染质量和性能之间找到最佳平衡点,尤其对于需要支持多平台的Unity项目至关重要。

kumakoko avatar
kumakoko
pure coder
comments powered by Disqus