【從UnityURP開始探索遊戲渲染】專欄-直達
URP BRDF漫反射方法對比
| 方法名稱 | 數學公式 | 特點 | 性能消耗 | 適用場景 |
|---|---|---|---|---|
| Lambert | $L_d = k_d * max(0, N·L)$ | 經典模型,能量不守恆 | ★☆☆ | 移動端低配 |
| Half-Lambert | $L_d = k_d * (0.5*(N·L)+0.5)^2$ | 增強暗部細節 | ★★☆ | 卡通渲染 |
| Disney Diffuse | 複雜能量守恆公式 | 物理準確,計算複雜 | ★★★ | PC/主機高品質 |
| Burley Diffuse | 基於微表面理論 | PBR標準,次表面散射近似 | ★★★ | 金屬/粗糙度工作流 |
具體實現方法及示例
Lambert模型(URP默認)
hlsl
// Lighting.hlsl 中的實現
half3 DiffuseLambert(half3 diffuseColor)
{
return diffuseColor / PI; // 能量歸一化
}
// 實際調用示例
half NdotL = saturate(dot(normalWS, light.direction));
half3 lambert = DiffuseLambert(_BaseColor.rgb) * NdotL;
Half-Lambert(Valve改進版)
hlsl
half3 DiffuseHalfLambert(half3 diffuseColor, half NdotL)
{
half wrap = 0.5 * (NdotL + 1.0);
return diffuseColor * wrap * wrap;
}
// 調用示例
half3 halfLambert = DiffuseHalfLambert(_BaseColor.rgb, NdotL);
Disney Diffuse(URP Lit.shader使用)
hlsl
// BRDF.hlsl 中的實現
half3 DiffuseDisney(half3 baseColor, half NdotV, half NdotL, half LdotH, half roughness)
{
half fd90 = 0.5 + 2 * LdotH * LdotH * roughness;
half lightScatter = (1 + (fd90 - 1) * pow(1 - NdotL, 5));
half viewScatter = (1 + (fd90 - 1) * pow(1 - NdotV, 5));
return baseColor * lightScatter * viewScatter / PI;
}
URP實際使用情況
-
默認採用方案:
- Simple Lit管線:Lambert模型(簡化版)
- Lit管線:Disney Diffuse + Burley改進(見
BRDF.hlsl)
-
核心代碼路徑:
Packages/com.unity.render-pipelines.universal/ShaderLibrary/BRDF.hlsl → DirectBDRF()函數 → DisneyDiffuse()分支 -
性能優化策略:
csharp // URP Asset中可關閉高質量漫反射 UniversalRenderPipelineAsset.asset → Lighting → UseRoughnessRefraction = false
方法對比
- 視覺差異:
- Lambert:明暗對比強烈
- Half-Lambert:暗部提亮約30%
- Disney:邊緣光更自然(菲涅爾效應)
- 推薦選擇:
- 移動端:Lambert(Simple Lit)
- 主機/PC:Disney(Lit Shader)
- 風格化:Half-Lambert(需自定義Shader)
URP 2022 LTS版本中,主流的Lit.shader默認使用改進版Disney模型,通過#define _BRDF_BURLEY宏啓用。開發者可通過修改BRDF.hlsl中的#define語句切換不同模型。
除了以上Unity URP中涉及到的基於物理光照模型的漫反射實現方式,還有Oren-Nayar模型來實現漫反射
Oren-Nayar模型原理
-
核心思想:
由Michael Oren和Shree Nayar於1994年提出,基於微表面自陰影理論,適用於粗糙表面(如布料、砂石)。其公式為:
$L = k_d * max(0, N·L) * (A + B * max(0, cos(φ_v-φ_l)) * sin(α) * tan(β))$
$A = 1 - 0.5*(σ²)/(σ²+0.33)$
$B = 0.45*(σ²)/(σ²+0.09)$
$α = max(θ_v, θ_l)$
$β = min(θ_v, θ_l)$
- σ:表面粗糙度參數(0°-90°)
- φ:方位角
-
視覺特性:
- 粗糙表面邊緣亮度增強
- 逆向光時出現"後向散射"效果
- 相比Lambert更符合真實布料觀測
Unity URP中的使用情況
- 默認未採用原因:
- 性能考量:需要額外計算角度和粗糙度(比Lambert多30%指令數)
- 藝術控制:參數物理意義不如PBR直觀
- 光照一致性:URP優先保證移動端性能
- 替代方案:
- 簡單場景:使用
SimpleLit的Lambert - 複雜材質:通過
LitShader的Smoothness參數間接控制
- 簡單場景:使用
手動實現方案
若需在URP中使用Oren-Nayar,可修改BRDF.hlsl:
hlsl
// 在BRDF.hlsl中添加
half3 DiffuseOrenNayar(half3 albedo, half roughness, half NdotV, half NdotL, half LdotV)
{
half sigma2 = roughness * roughness;
half A = 1.0 - 0.5 * sigma2 / (sigma2 + 0.33);
half B = 0.45 * sigma2 / (sigma2 + 0.09);
half s = LdotV - NdotL * NdotV;
half t = s > 0 ? 1.0 / max(NdotL, NdotV) : 1.0;
return albedo * (A + B * s * t) * NdotL;
}
適用場景建議
-
推薦使用情況:
- 風格化渲染(如手繪布料)
- 考古/地質仿真項目
- 需要特殊邊緣光效果的場景
-
性能對比:
模型 指令數(移動端) 內存訪問 Lambert 12 3 Oren-Nayar 38 5 Disney 45 6
當前URP 2022 LTS版本中,可通過自定義Shader Graph節點實現Oren-Nayar,但官方未內置因其不符合URP的"性能優先"設計原則。實際項目中建議通過法線貼圖+Lambert近似替代。
【從UnityURP開始探索遊戲渲染】專欄-直達
(歡迎點贊留言探討,更多人加入進來能更加完善這個探索的過程,🙏)