【光照】[PBR][法线分布]GGX实现方法对比

【从UnityURP开始探索游戏渲染】专栏-直达

GGX的全称与基本概念

GGX的全称‌:Ground Glass X (或 Generalized Trowbridge-Reitz Distribution)

首次提出‌:Walter等人在2007年发表的论文《Microfacet Models for Refraction through Rough Surfaces》中提出

GGX是一种‌法线分布函数‌(Normal Distribution Function, NDF),用于描述微表面模型中微观几何表面法线的概率分布。它是Unity URP中PBR渲染的核心组成部分,替代了传统的Beckmann分布。

GGX的数学原理

核心公式

在Unity URP中,GGX分布的实现基于以下公式:

D_{GGX}(h)=\\frac{α_g^2}{π\[(n⋅h)^2(α_g^2−1)+1\]^2}

其中:

  • h:半角向量(光线方向与视线方向的中间向量)
  • n:表面法线
  • α_g:粗糙度参数(α_g=roughness\^2

Unity URP中的代码实现

Packages/com.unity.render-pipelines.universal/ShaderLibrary/BRDF.hlsl中:

c 复制代码
hlsl
// GGX/Trowbridge-Reitz分布函数
float D_GGX(float NdotH, float roughness)
{
    float a = roughness * roughness;  // 粗糙度平方
    float a2 = a * a;
    float NdotH2 = NdotH * NdotH;

    float denom = NdotH2 * (a2 - 1.0) + 1.0;
    denom = PI * denom * denom;

    return a2 / max(denom, 0.000001); // 避免除零错误
}

GGX的核心特性

长尾分布特性

  • 相比Beckmann分布,GGX具有更长的"尾巴"
  • 能更好地模拟真实世界的材质高光衰减
  • 产生更自然的反射光晕效果

能量守恒

  • ∫_ΩD_{GGX}(h)(n⋅h)dω=1
  • 保证了光线能量在反射过程中不会无故增加或减少
  • 是PBR渲染的基础要求

各向同性/各向异性支持

c 复制代码
hlsl
// URP中各向异性GGX实现
float D_GGX_Anisotropic(float NdotH, float HdotX, float HdotY, float ax, float ay)
{
    float denom = HdotX*HdotX/(ax*ax) + HdotY*HdotY/(ay*ay) + NdotH*NdotH;
    return 1.0 / (PI * ax * ay * denom * denom);
}

GGX与其他分布函数对比

特性 GGX Beckmann Blinn-Phong
真实度 ★★★★☆ ★★★☆☆ ★★☆☆☆
性能开销 ★★☆☆☆ ★★★☆☆ ★☆☆☆☆
长尾表现 优异 中等 较差
移动端支持 良好 一般 优秀
URP默认 仅在SimpleLit中使用

GGX在Unity URP中的实际应用

材质粗糙度映射

c 复制代码
hlsl
// 粗糙度处理流程
float perceptualRoughness = PerceptualSmoothnessToPerceptualRoughness(smoothness);
float roughness = PerceptualRoughnessToRoughness(perceptualRoughness);

// 应用纹理采样
roughness = roughness * _RoughnessMap.Sample(sampler_MainTex, uv).r;

高光反射计算

c 复制代码
hlsl
// BRDF.hlsl中的完整镜面反射计算
half3 BRDF_SpecularGGX(half3 F0, half roughness, half NdotH, half NdotL, half NdotV, half LdotH)
{
    half D = D_GGX(NdotH, roughness); // GGX法线分布
    half V = V_SmithGGXCorrelated(NdotL, NdotV, roughness); // 几何衰减
    half3 F = F_Schlick(LdotH, F0); // 菲涅尔反射

    return (D * V) * F;
}

环境光反射处理

c 复制代码
hlsl
// 环境BRDF计算(使用GGX分布)
half2 envBRDF = tex2D(_BRDFLUT, float2(NdotV, roughness)).rg;
half3 envSpecular = specularColor * envBRDF.x + envBRDF.y;

GGX的视觉表现特点

粗糙材质表现

  • 低粗糙度:锐利的高光反射
  • 中粗糙度:柔和的散射光晕
  • 高粗糙度:均匀的漫反射外观

边缘响应

  • 在材质边缘产生自然的亮度衰减
  • 模拟真实物体的菲涅尔效应

材质连续性

  • 粗糙度参数从0到1变化时表现平滑过渡
  • 避免传统模型的突兀变化

性能优化技巧

近似计算

c 复制代码
hlsl
// GGX的移动端近似
float D_GGX_Mobile(float NdotH, float roughness)
{
    float a = roughness * roughness;
    float a2 = a * a;
    float d = NdotH * NdotH * (a2 - 1.0) + 1.0;
    return a2 / (d * d * PI);
}

预积分技术

  • URP使用预计算的BRDF查找纹理(_BRDFLUT)
  • 将复杂计算转移到预处理阶段

动态降级

c 复制代码
hlsl
#if defined(SHADER_API_MOBILE)
   // 移动端简化版GGX
#else
   // 完整精度GGX
#endif

GGX分布作为Unity URP中PBR渲染的核心,通过其独特的数学特性和长尾分布,实现了比传统模型更真实的材质表现。虽然计算复杂度略高,但其在视觉质量和物理准确性上的优势使其成为现代实时渲染的标准选择。


【从UnityURP开始探索游戏渲染】专栏-直达

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

相关推荐
mxwin4 小时前
Unity Shader 半透明物体为什么不能写入深度缓冲?
unity·游戏引擎·shader
晚枫歌F5 小时前
三层时间轮的实现
网络·unity·游戏引擎
咸鱼永不翻身6 小时前
Lua脚本事件检查工具
unity·lua·工具
leo__5208 小时前
单载波中继系统资源分配算法MATLAB仿真程序
算法·matlab·unity
努力长头发的程序猿9 小时前
Unity使用ScriptableObject序列化资源
unity·游戏引擎
mxwin10 小时前
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