【光照】[PBR][漫反射]实现方法对比

【从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默认)

c 复制代码
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改进版)

c 复制代码
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使用)

c 复制代码
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 复制代码
    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

c 复制代码
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开始探索游戏渲染】专栏-直达

(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,🙏)

相关推荐
晚枫歌F5 小时前
三层时间轮的实现
网络·unity·游戏引擎
咸鱼永不翻身6 小时前
Lua脚本事件检查工具
unity·lua·工具
leo__5208 小时前
单载波中继系统资源分配算法MATLAB仿真程序
算法·matlab·unity
努力长头发的程序猿9 小时前
Unity使用ScriptableObject序列化资源
unity·游戏引擎
mxwin9 小时前
Unity Shader 手写基于 PBR 的 URP Lit Shader 核心光照计算
unity·游戏引擎·shader
小贺儿开发10 小时前
Unity3D 智能云端数字标牌系统
unity·阿里云·人机交互·视频·oss·广告·互动
魔士于安10 小时前
Unity windows 同步 异步 打开文件文件夹工具
游戏·unity·游戏引擎·贴图·模型
魔士于安11 小时前
unity lowpoly 风格 城市 建筑 道路 交通标志
游戏·unity·游戏引擎·贴图·模型
mxwin11 小时前
Unity GPU Shader 性能优化指南
unity·游戏引擎·shader
董董女友1 天前
unity mcp 配置指南
unity·游戏引擎