动态

详情 返回 返回

【光照】[漫反射diffuse]以UnityURP為例 - 动态 详情

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

漫反射基本流程

漫反射遵循蘭伯特定律(Lambert's Cosine Law),其核心流程如下:

  • 法線準備‌:獲取表面法線向量(通常來自頂點法線或法線貼圖)
  • 光源方向計算‌:確定光源到表面點的單位方向向量
  • 點積運算‌:計算法線向量與光源方向的點積(N·L)
  • 能量約束‌:使用saturate函數將結果限制在[0,1]範圍
  • 顏色混合‌:將結果與光源顏色和表面反照率(albedo)相乘

數學表達式:

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

漫反射基本原理

漫反射遵循蘭伯特定律(Lambert's Law),描述光線在粗糙表面均勻散射的現象。其核心特點是:

  • 光線入射角度影響反射強度
  • 表面法線方向決定反射分佈
  • 與觀察角度無關的各向同性反射

蘭伯特定律 Lambert’s law

$Cdiffuse=(Clight*Mdiffuse)max(0,n·I)$

fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLight));

半蘭伯特

$Cdiffuse=(Clight*Mdiffuse)(a(n·I)+b)$

絕大多數a和b都為0.5

$Cdiffuse=(Clight*Mdiffuse)(0.5(n·I)+0.5)$

Unity URP中的實現細節

核心實現位置

URP中的漫反射計算主要分佈在以下文件:

  • Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl

實現原理

  • 法線處理‌:
    • 世界空間法線轉換
    • 法線貼圖支持
    • 雙面渲染處理
  • 光源計算‌:
    • 主光源方向計算
    • 附加光源循環處理
    • 點光源/聚光燈方向計算
  • 漫反射核心‌:
    • 使用half精度優化
    • 能量守恆處理
    • 多光源疊加支持

關鍵代碼實現

  • UnityURP_漫反射實現

    hlsl
    // 簡化版Lambert漫反射實現
    half3 DiffuseLighting(Light light, half3 normalWS, half3 albedo)
    {
        half NdotL = saturate(dot(normalize(normalWS), light.direction));
        return light.color * albedo * NdotL;
    }
    
    // 完整光照計算入口
    half3 UniversalFragmentBlinnPhong(InputData inputData, SurfaceData surfaceData)
    {
        // 初始化光照結果
        half3 color = surfaceData.emission;
        
        // 主光源漫反射計算
        Light mainLight = GetMainLight();
        color += DiffuseLighting(mainLight, inputData.normalWS, surfaceData.albedo);
        
        // 附加光源計算
        uint pixelLightCount = GetAdditionalLightsCount();
        for (uint lightIndex = 0; lightIndex < pixelLightCount; ++lightIndex)
        {
            Light light = GetAdditionalLight(lightIndex, inputData.positionWS);
            color += DiffuseLighting(light, inputData.normalWS, surfaceData.albedo);
        }
        
        return color;
    }
    

快速調用方法

在URP着色器中調用漫反射的標準方式:

自定義着色器方式‌:

hlsl
// 片元着色器示例
half4 frag(Varyings input) : SV_Target
{
    // 初始化表面數據
    SurfaceData surfaceData;
    InitializeStandardLitSurfaceData(input.uv, surfaceData);

    // 準備光照輸入數據
    InputData inputData;
    InitializeStandardLitInputData(input, surfaceData.normalTS, inputData);

    // 計算漫反射光照
    half4 color = UniversalFragmentBlinnPhong(inputData, surfaceData);

    return color;
}

Shader Graph可視化方式‌:

  • 使用"Dot Product"節點計算N·L
  • 使用"Multiply"節點混合顏色
  • 連接至"Fragment"輸出的Base Color通道

URP選擇此方案的原因

性能優化‌:

  • 使用half精度計算
  • 內置光照循環優化
  • 最小化分支預測

物理一致性‌:

  • 線性空間計算
  • 正確的光照衰減(通過顏色與距離和陰影衰減相乘做到)

擴展性‌:

  • 支持多光源場景
  • 與PBR工作流兼容
  • 可擴展自定義光照模型

跨平台支持‌:

  • 適配移動端TBDR架構
  • 支持SRP Batcher優化
  • 兼容各種渲染路徑

在URP中,這種實現方式既保持了經典光照模型的直觀性,又通過現代渲染管線的優化手段確保了高性能表現,特別適合需要跨平台部署的項目。


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

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

Add a new 评论

Some HTML is okay.