动态

详情 返回 返回

【光照】[漫反射]UnityURP蘭伯特有光照衰減嗎? - 动态 详情

【從UnityURP開始探索遊戲渲染】專欄-直達

光照衰減的基本原理

在物理正確的光照模型中,衰減需要遵循兩個基本定律:

  • 平方反比定律‌:光強與距離平方成反比 (I ∝ 1/r²)
  • 餘弦定律‌:表面接收的光強與入射角餘弦成正比 (I ∝ cosθ)

經典蘭伯特模型的衰減處理

標準蘭伯特公式

$漫反射 = 表面顏色 * 表面反照率 * max(0, N·L)$

衰減實現分析

  • 角度衰減‌:
    • ✅ 正確實現餘弦定律
    • 通過 N·L 點積計算入射角衰減
    • 符合物理規律:光線入射角越大,光照強度越小
  • 距離衰減‌:
    • ⚠️ ‌完全缺失距離衰減計算
    • 公式中沒有包含光源距離(r)相關項
    • 光強不會隨距離增加而減弱
    • 導致物理不準確性

Unity URP中的實現方案

距離衰減補償機制

URP通過額外計算衰減因子來彌補蘭伯特的不足:

hlsl
// URP光源獲取函數 (Lighting.hlsl)
Light GetMainLight()
{
    Light light;
    light.direction = _MainLightPosition.xyz;

    // 距離衰減計算
    float distance = length(_WorldSpaceCameraPos - positionWS);
    light.distanceAttenuation = 1.0 / max(distance * distance, 0.01);

    light.color = _MainLightColor.rgb;
    return light;
}

// 主光源 漫反射計算
lightingData.mainLightColor += CalculateBlinnPhong(mainLight, inputData, surfaceData);

half3 CalculateBlinnPhong(Light light, InputData inputData, SurfaceData surfaceData)
{
// 這裏通過顏色計算了光線衰減
    half3 attenuatedLightColor = light.color * (light.distanceAttenuation * light.shadowAttenuation);
    half3 lightDiffuseColor = LightingLambert(attenuatedLightColor, light.direction, inputData.normalWS);

    half3 lightSpecularColor = half3(0,0,0);
    #if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR)
    half smoothness = exp2(10 * surfaceData.smoothness + 1);

    lightSpecularColor += LightingSpecular(attenuatedLightColor, light.direction, inputData.normalWS, inputData.viewDirectionWS, half4(surfaceData.specular, 1), smoothness);
    #endif

#if _ALPHAPREMULTIPLY_ON
    return lightDiffuseColor * surfaceData.albedo * surfaceData.alpha + lightSpecularColor;
#else
    return lightDiffuseColor * surfaceData.albedo + lightSpecularColor;
#endif
}

URP衰減系統組成

光源類型處理‌:

  • 平行光:無距離衰減 (1.0)
  • 點光源:平方反比衰減 (1/r²)
  • 聚光燈:角度衰減 × 距離衰減

優化策略‌:

  • 使用預計算的衰減紋理
  • 最大距離截斷(light.range)
  • 平滑過渡邊緣處理
graph TD A[光源類型] --> B{平行光?} B -->|是| C[衰減=1.0] B -->|否| D{點光源?} D -->|是| E[1/r²計算] D -->|否| F[聚光燈衰減曲線] E --> G[距離截斷] F --> G G --> H[平滑過渡]

為什麼經典蘭伯特缺乏距離衰減

  • 歷史設計侷限‌:
    • 早期計算機圖形學簡化模型
    • 源自環境固定的CAD渲染需求
    • 僅考慮局部表面光照
  • 數學簡化考量‌:
    • 減少每像素計算量
    • 避免昂貴的距離計算
    • 保持公式簡潔性
  • 藝術導向設計‌:
    • 允許美術師手動控制光照範圍
    • 避免距離導致的過度變暗
    • 更適合風格化渲染

URP的實用解決方案

衰減校正技術

  • 物理混合方案‌:

    hlsl
    half3 ApplyAttenuation(Light light, float3 positionWS)
    {
        // 基礎平方反比衰減
        float dist = distance(light.position, positionWS);
        float atten = 1.0 / (dist * dist);
    
        // 範圍平滑過渡
        float fade = saturate(1.0 - (dist / light.range));
        atten *= fade * fade;
    
        // 聚光燈角度衰減
        if(light.type == SPOT)
        {
            float3 toLight = normalize(light.position - positionWS);
            float spotFactor = dot(toLight, light.direction);
            atten *= smoothstep(light.outerAngle, light.innerAngle, spotFactor);
        }
    
        return saturate(atten * light.intensity);
    }
    
  • 移動端優化版‌:

    hlsl
    half3 SimpleAttenuation(Light light, float3 positionWS)
    {
        // 使用預計算的衰減紋理
        float dist = distance(light.position, positionWS);
        float t = saturate(dist / light.range);
        half atten = SAMPLE_TEXTURE2D(_LightAttenuationTex, sampler_LinearClamp, float2(t, 0.5)).r;
        return atten * light.intensity;
    }
    

Unity編輯器中配置

csharp
// 光源組件屬性設置
Light light = gameObject.AddComponent<Light>();
light.type = LightType.Point;
light.range = 10.0f;// 控制衰減範圍
light.intensity = 1.0f;// 控制最大強度
light.color = Color.white;

結論與建議

核心結論

  • 經典蘭伯特模型自身不包含距離衰減‌,僅有角度衰減
  • URP通過外部衰減系統提供完整衰減支持‌,使經驗模型實用化
  • 現代實現已接近物理正確‌,但仍有可控的藝術化調整空間

開發實踐建議

  • 性能敏感場景‌:

    hls
    // 使用簡化距離衰減
    float atten = saturate(1.0 - distance/range);
    
  • 高品質渲染‌:

    hlsl
    // 物理精確衰減
    float atten = 1.0 / (distance * distance + 1e-5);
    
  • 風格化渲染‌:

    hlsl
    // 自定義衰減曲線
    float atten = exp(-_Falloff * distance);
    

在URP中,雖然經典蘭伯特模型本身不具備完整的物理衰減特性,但通過引擎層的光照系統補償,開發者可以輕鬆實現物理正確的衰減效果,同時保留藝術控制自由度。這種分層設計正是現代渲染管線的實用智慧體現。


【從UnityURP開始探索遊戲渲染】專欄-直達

(歡迎點贊留言探討,更多人加入進來能更加完善這個探索的過程,🙏)

Add a new 评论

Some HTML is okay.