You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中ForwardAdd通道下点/聚光灯衰减计算异常排查

问题分析与解决方案

核心问题原因

  1. 衰减纹理UV采样错误:Unity的_LightTextureB0衰减纹理的UV范围是[0,1],对应光源的0到最大照射范围(_LightRange)。你直接使用原始距离值作为UV,当距离超过1后,纹理会重复采样,导致衰减值不再变化,最终出现方形光照区域。
  2. 缺少光源范围变量:代码中未声明_LightRange变量,无法将实际距离归一化到纹理的UV区间内。
  3. 聚光灯未处理角度衰减:当前代码仅处理了距离衰减,未结合聚光灯的锥角衰减逻辑。

修正后的代码

首先在CGPROGRAM块中添加缺失的uniform变量:

uniform float _LightRange;

然后修改片段着色器中的衰减计算部分:

else
{
    float3 vertexToLightSource = _WorldSpaceLightPos0.xyz - i.world.xyz;
    float distance = length(vertexToLightSource); 
    lightDirection = normalize(vertexToLightSource);
    
    // 将距离归一化到衰减纹理的UV范围[0,1]
    float normalizedDistance = distance / _LightRange;
    // 采样衰减纹理,x分量对应距离衰减,y分量对聚光灯是角度衰减
    attenuation = tex2D(_LightTextureB0, float2(normalizedDistance, 0.0)).a;
    
    // 强制超出光源范围的像素衰减为0
    attenuation *= step(distance, _LightRange);
    
    // 聚光灯额外处理:添加角度衰减
    float3 lightSpacePos = mul(unity_WorldToLight, float4(i.world.xyz, 1.0)).xyz;
    attenuation *= tex2D(_LightTextureB0, float2(length(lightSpacePos.xy) / _LightRange, lightSpacePos.z / _LightRange)).a;
}

额外检查项

  • 几何着色器位置传递:确保geometryOutput结构体中的world变量是正确的世界空间位置,且在几何着色器中从顶点着色器传递并输出时,每个顶点的位置都被正确赋值,保证片段着色器能得到插值后的像素级世界位置。
    示例顶点着色器输出:
    struct vertexOutput {
        float4 worldPos : TEXCOORD0;
    };
    
    vertexOutput vert(appdata v) {
        vertexOutput o;
        o.worldPos = mul(unity_ObjectToWorld, v.vertex);
        return o;
    }
    
    几何着色器中传递位置:
    [maxvertexcount(3)]
    void geo(triangle vertexOutput input[3], inout TriangleStream<geometryOutput> outStream) {
        geometryOutput o;
        for (int i = 0; i < 3; i++) {
            o.world = input[i].worldPos;
            // 其他输出参数赋值
            outStream.Append(o);
        }
    }
    

内容的提问来源于stack exchange,提问作者Velorexe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 19:45:49