PBR中BRDF常用的各类法线分布函数、几何函数总结(unity)

顺序从老到新到实践拓展

一,法线分布函数(Normal Distribution Function,NDF)

1.1 各项同性NDF总结

1.1.1Blinn-Phong分布

D p ( h ) = 1 π α 2 ( n ⋅ h ) 2 α 2 − 2 D_{p}(h) = \frac{1}{πα^2}(n \cdot h)^{ \frac{2}{α^2} -2} Dp(h)=πα21(nh)α222

float D_BlinnPhong(float NdotH, float Roughness2)
{
    float n = 2 / Roughness2 - 2;
    return (n+2) / (2*UNITY_PI) * pow( NdotH, n );
}

1.1.2 Beckmann分布

D b ( h ) = 1 π α 2 ( n ⋅ h ) 4 e x p ( n ⋅ h ) 2 − 1 α 2 ( n ⋅ h ) 2 D_{b}(h) = \frac{1}{πα^2(n \cdot h)^4}exp^{\frac{(n \cdot h)^2-1}{α^2(n \cdot h)^2}} Db(h)=πα2(nh)41expα2(nh)2(nh)21

float D_Beckmann(float NdotH, float Roughness2)
{
    float NdotH2 = NdotH * NdotH;
    return exp( (NdotH2 - 1) / (Roughness2 * NdotH2) ) / ( UNITY_PI * Roughness2 * NdotH2 * NdotH2 );
}

1.1.3 GGX(Trowbridge-Reitz)分布

D G G X ( h ) = α 2 π ( ( n ⋅ h ) 2 ( α 2 − 1 ) + 1 ) 2 D_{GGX}(h) = \frac{α^2}{π((n \cdot h)^2(α^2 - 1)+1)^2} DGGX(h)=π((nh)2(α21)+1)2α2

float D_GGX (float NdotH, float Roughness2)
{
    float d = (Roughness2 - 1.0) * NdotH * NdotH + 1.0f; 
    return Roughness2 / (d * d * UNITY_PI);                               
}
  • 以上三个分布是常用模型,效果对比如下,由于GGX高光扩散性更好因此被更广泛的使用
    在这里插入图片描述

1.1.4 Generalized-Trowbridge-Reitz(GTR)分布

D G T R ( h ) = c ( ( n ⋅ h ) 2 ( α 2 − 1 ) + 1 ) γ D_{GTR}(h) = \frac{c}{((n \cdot h)^2(α^2 - 1)+1)^γ} DGTR(h)=((nh)2(α21)+1)γc
γ=2时,GTR即GGX分布
γ=1时,GTR即Berry分布

float D_GTR1 (float NdotH, float Roughness2)
{
    float d = (Roughness2 - 1.0) * NdotH * NdotH + 1.0f; 
    return (Roughness2-1) / ( d * log(Roughness2) * UNITY_PI);                               
}

1.2 各向异性NDF总结

at和ab分别是沿切线(tangent)方向t和副法线(binormal)方向b的粗糙度,如果at=ab,则回到了各向同性。
「注意网上shader一般会将切线方向t写作X,副法线(binormal)b方向写作Y」

1.2.1 Anisotropic Beckmann分布

D B a n i s o ( h ) = 1 π α x α y ( n ⋅ h ) 4 e x p ( − ( t ⋅ h ) 2 α x 2 + ( b ⋅ h ) 2 α y 2 ( n ⋅ h ) 2 ) D_{Baniso}(h) = \frac{1}{πα_xα_y(n \cdot h)^4} exp(- \frac{\frac{(t \cdot h)^2}{α_x^2} + \frac{(b \cdot h)^2}{α_y^2} }{(n \cdot h)^2}) DBaniso(h)=παxαy(nh)41exp((nh)2αx2(th)2+αy2(bh)2)

float D_Beckmann_aniso( float at, float ab, float NoH, float3 H, float3 T, float3 B )
{
    float ToH = dot( T, H );
    float BoH = dot( B, H );
    float d = - (ToH*ToH / (at*at) + BoH*BoH / (ab*ab)) / NoH*NoH;
    return exp(d) / ( PI * at*ab * NoH * NoH * NoH * NoH );
}

1.2.2 Anisotropic GGX分布

D G G X a n i s o ( h ) = 1 π α x α y 1 ( ( t ⋅ h ) 2 α x 2 + ( b ⋅ h ) 2 α y 2 + ( n ⋅ h ) 2 ) 2 D_{GGXaniso}(h) = \frac{1}{πα_xα_y} \frac{1}{(\frac{(t \cdot h)^2}{α_x^2} + \frac{(b \cdot h)^2}{α_y^2} +(n \cdot h)^2)^2} DGGXaniso(h)=παxαy1(αx2(th)2+αy2(bh)2+(nh)2)21

float D_GGXaniso( float at, float ab, float NoH, float3 H, float3 T, float3 B )
{
    float ToH = dot( T, H );
    float BoH = dot( B, H );
    float d = ToH*ToH / (at*at) + BoH*BoH / (ab*ab) + NoH*NoH;
    return 1 / ( PI * at*ab * d*d );
}

1.2.3 各项异性参数化方法

上述各向异性是将t、b两个方向的粗糙度进行两次参数化,但有时也可以用其他参数化方法。

Disney

比如Disney用同性粗糙度和k_aniso组合(0-1),0.9将纵横比限制为10:1
k a s p e c t = 1 − 0.9 ∗ k a n i s o k_{aspect} = \sqrt{1-0.9*k_{aniso}} kaspect=10.9kaniso
α t = r 2 k a s p e c t α_t = \frac{r^2}{k_{aspect}} αt=kaspectr2
α b = r 2 k a s p e c t α_b = r^2k_{aspect} αb=r2kaspect

Sony Imageworks

允许任意程度的各向异性:
α t = r 2 ( 1 + k a n i s o ) α_t = r^2(1+k_{aniso}) αt=r2(1+kaniso)
α b = r 2 ( 1 − k a n i s o ) α_b =r^2(1-k_{aniso}) αb=r2(1kaniso)

1.3 性能总结

「完全copy毛老师」

可以通过拉格朗日恒等式 ∣ a × b ∣ 2 = ∣ a ∣ 2 ∣ b ∣ 2 − ( a ⋅ b ) 2 \vert a \times b\vert^2 = \vert a \vert^2\vert b \vert^2 - (a \cdot b)^2 a×b2=a2b2(ab)2解决此问题:

带入n和h(单位向量)变为 ∣ n × h ∣ 2 = 1 − ( n ⋅ h ) 2 \vert n \times h\vert^2 = 1 - (n \cdot h)^2 n×h2=1(nh)2,因此:
D G G X ( h ) = α 2 π ( ( n ⋅ h ) 2 ( α 2 − 1 ) + 1 ) 2 = α 2 π ( ∣ n × h ∣ 2 + α 2 ( n ⋅ h ) 2 ) 2 D_{GGX}(h) = \frac{α^2}{π((n \cdot h)^2(α^2 - 1)+1)^2}= \frac{α^2}{π(\vert n \times h\vert^2 + α^2(n \cdot h)^2)^2} DGGX(h)=π((nh)2(α21)+1)2α2=π(n×h2+α2(nh)2)2α2

half D_GGX (half NdotH, half Roughness2, half3 H, half3 N)
{
	float3 NxH = cross(N, H);
	float OneMinusNoHSqr = dot(NxH, NxH);
	float d = OneMinusNoHSqr + NdotH * NdotH * Roughness2; 
	float p = Roughness2 / (d * d * UNITY_PI);
    return min(p, 65504.0);                               
}

二,几何函数

2.1 Disney(2012)

G D i s n e y ( v ) = 2 ( n ⋅ v ) ( n ⋅ v ) + k 2 + ( 1 − k 2 ) ( n ⋅ v ) 2 其中 k = ( 0.5 + r o u g h n e s s 2 ) 2 G_{Disney}(v)= \frac{2(n \cdot v)}{(n \cdot v)+\sqrt{k^2+(1-k^2)(n \cdot v)^2}} 其中 k = (0.5+\frac{roughness}{2})^2 GDisney(v)=(nv)+k2+(1k2)(nv)2 2(nv)其中k=(0.5+2roughness)2
G ( i , o , h ) = G 1 ( i ) G 2 ( o ) G(i,o,h)= G_{1}(i)G_{2}(o) G(i,o,h=G1(i)G2(o)

2.2 Schlick-GGX(2013)

G S c h l i c k G G X ( v ) = n ⋅ v ( n ⋅ v ) ( 1 − k ) + k 其中 k = ( α + 1 ) 2 8 G_{SchlickGGX}(v)= \frac{n \cdot v}{(n \cdot v)(1-k)+k} 其中 k = \frac{(α+1)^2}{8} GSchlickGGX(v)=(nv)(1k)+knv其中k=8(α+1)2
G ( i , o , h ) = G 1 ( i ) G 2 ( o ) G(i,o,h)= G_{1}(i)G_{2}(o) G(i,o,h=G1(i)G2(o)

2.3 转向Smith联合遮蔽阴影函数(2014)

2.3.1 Frostbite的近似方案

G ( l , v ) 4 ∣ n ⋅ l ∣ ∣ n ⋅ v ∣ = 0.5 μ o α 2 + μ i ( μ i − α 2 μ i ) + μ i α 2 + μ o ( μ o − α 2 μ o ) \frac{G{}(l,v)}{4\vert{n \cdot l}\vert\vert n \cdot v\vert}= \frac{0.5}{μ_o\sqrt{α^2+μ_i(μ_i-α^2μ_i)}+μ_i\sqrt{α^2+μ_o(μ_o-α^2μ_o)}} 4∣nl∣∣nvG(l,v)=μoα2+μi(μiα2μi) +μiα2+μo(μoα2μo) 0.5
其中 μ i = ( n ⋅ l ) + , μ o = ( n ⋅ v ) + μ_i = (n \cdot l)^+,μ_o = (n \cdot v)^+ μi=(nl)+,μo=(nv)+

2.3.2 UE4的近似方案

G ( l , v , h ) = 0.5 ( n ⋅ l ) ( ( n ⋅ v ) ( 1 − α 2 ) + α 2 ) + ( n ⋅ v ) ( ( n ⋅ l ) ( 1 − α 2 ) + α 2 ) G{}(l,v,h) = \frac{0.5}{(n \cdot l)((n \cdot v)(1-α^2)+α^2) + (n \cdot v)((n \cdot l)(1-α^2)+α^2)} G(l,v,h)=(nl)((nv)(1α2)+α2)+(nv)((nl)(1α2)+α2)0.5
其中 α = r o u g h n e s s α = roughness α=roughness

float Vis_SmithJointApprox( float NoL , float NoV,float a)
{
    float a2 = a*a;
    float Vis_SmithV = NoL * ( NoV * ( 1 - a2 ) + a2 );
    float Vis_SmithL = NoV * ( NoL * ( 1 - a2 ) + a2 );
    return 0.5 /( Vis_SmithV + Vis_SmithL );
}

2.3.3 Unity HDRP的近似方案

G ( l , v , h ) = 0.5 ( n ⋅ l ) ( ( n ⋅ v ) ( 1 − α ) + α ) + ( n ⋅ v ) ( 1 − α 2 ) ( n ⋅ l ) 2 + α 2 G{}(l,v,h) = \frac{0.5}{(n \cdot l)((n \cdot v)(1-α)+α) + (n \cdot v)\sqrt{(1-α^2)(n \cdot l)^2+α^2}} G(l,v,h)=(nl)((nv)(1α)+α)+(nv)(1α2)(nl)2+α2 0.5
其中 α = r o u g h n e s s α = roughness α=roughness

float V_SmithJointGGX(float NdotL, float NdotV, float roughness)
{
    float a2 = roughness*roughness;

    float lambdaV = NdotL * (NdotV * (1 - roughness) + roughness);
    float lambdaL = NdotV * sqrt((-NdotL * a2 + NdotL) * NdotL + a2);

    return 0.5 / (lambdaV + lambdaL);
}

2.3.4 Google Filament的近似方案

G ( l , v , h ) = 0.5 ( n ⋅ l ) ( 1 − α 2 ) ( n ⋅ v ) 2 + α 2 + ( n ⋅ v ) ( 1 − α 2 ) ( n ⋅ l ) 2 + α 2 G{}(l,v,h) = \frac{0.5}{(n \cdot l)\sqrt{(1-α^2)(n \cdot v)^2+α^2} + (n \cdot v)\sqrt{(1-α^2)(n \cdot l)^2+α^2}} G(l,v,h)=(nl)(1α2)(nv)2+α2 +(nv)(1α2)(nl)2+α2 0.5
其中 α = r o u g h n e s s α = roughness α=roughness

float G_SmithGGXCorrelated(float NoV, float NoL, float a)
{
    float a2 = a * a;
    float GGXL = NoV * sqrt((-NoL * a2 + NoL) * NoL + a2);
    float GGXV = NoL * sqrt((-NoV * a2 + NoV) * NoV + a2);
    return 0.5 / (GGXV + GGXL);
}

2.3.5 Respawn Entertainment的近似方案

G ( l , v ) 4 ∣ n ⋅ l ∣ ∣ n ⋅ v ∣ = 0.5 l e r p ( 2 ∣ n ⋅ l ∣ ∣ n ⋅ v ∣ , ∣ n ⋅ l ∣ + ∣ n ⋅ v ∣ , α ) \frac{G{}(l,v)}{4\vert{n \cdot l}\vert\vert n \cdot v\vert}= \frac{0.5}{lerp(2\vert{n \cdot l}\vert \vert{n \cdot v}\vert, \vert{n \cdot l}\vert + \vert{n \cdot v}\vert,α)} 4∣nl∣∣nvG(l,v)=lerp(2∣nl∣∣nv,nl+nv,α)0.5

2.4 各项异性几何函数总结

2.4.1 Unity HDRP方案

注意这里是算出来是 G ( l , v ) 4 ∣ n ⋅ l ∣ ∣ n ⋅ v ∣ \frac{G{}(l,v)}{4\vert{n \cdot l}\vert\vert n \cdot v\vert} 4∣nl∣∣nvG(l,v)

// Note: V = G / (4 * NdotL * NdotV)
// Ref: https://cedec.cesa.or.jp/2015/session/ENG/14698.html The Rendering Materials of Far Cry 4
float V_SmithJointGGXAniso(float TdotV, float BdotV, float NdotV, float TdotL, float BdotL, float NdotL, float roughnessT, float roughnessB, float partLambdaV)
{
    float lambdaV = NdotL * length(real3(roughnessT * TdotV, roughnessB * BdotV, NdotV));
    float lambdaL = NdotV * length(real3(roughnessT * TdotL, roughnessB * BdotL, NdotL));

    return 0.5 / (lambdaV + lambdaL);
}

参考资料

【基于物理的渲染(PBR)白皮书】(五)几何函数相关总结
【基于物理的渲染(PBR)白皮书】(四)法线分布函数相关总结

<think>好的,用户想在Unity中实现基于PBR的风格化草渲染。我需要先理清PBR和风格化如何结合。PBR通常追求物理准确,但风格化需要艺术化的调整,所以可能需要修改光照模型,保留部分PBR特性,比如能量守恒,同时引入非真实的着色方法。 首先,草的几何形状是关键。用户可能想要动态效果,比如随风摆动。可以考虑使用顶点着色器处理摆动,用噪声纹理或正弦波模拟运动。同时,草的模型要简单,可能用交叉的面片(cross-quad)或者自定义的几何着色器生成,但移动端可能需要注意性能。 材质方面,Albedo贴图需要风格化的颜色纹理,可能有渐变或手绘效果。PBR的金属度和粗糙度贴图可能需要调整,比如降低粗糙度变化,让高光更统一。或者完全自定义高光效果,比如卡通化的高光块。 光照部分,PBRBRDF如Disney或UE4的模型需要调整。可以简化漫反射,用Lambert加上渐变,或者Wrap Lighting来柔化阴影。镜面反射部分,可以用Blinn-Phong代替GGX,控制高光大小和强度,使其更风格化。 法线贴图可能不需要太复杂的细节,可以用平铺的法线贴图给草叶增加一些纹理,但强度调低,避免过于真实。或者完全不用法线,用顶点法线调整整体光照方向。 环境光照方面,风格化可能不需要IBL,但可以用简单的环境色或渐变天空盒来影响草的色调。可以考虑在Shader中加入自定义的环境光影响。 着色器结构方面,可能需要Surface Shader或Shader Graph。如果用Shader Graph,可以更直观地混合PBR节点和自定义效果。比如将Albedo与渐变贴图混合,修改Smoothness的输入源。 风的实现,在Shader中用世界坐标的噪声纹理采样,加上时间和风速参数,影响顶点位置。注意顶点动画的性能,可能需要限制影响的幅度,或者分区域计算。 LOD和剔除也很重要,远处的草可以减少面片数量或切换为更简单的模型,用抖动渐变避免突兀的切换。GPU Instancing可以提升渲染效率,特别是大面积的草地。 最后,测试不同光照条件下的效果,调整参数达到艺术风格的需求。可能需要参考其他风格化游戏的做法,比如《塞尔达传说》中的草,结合PBR的基础,但简化或夸张某些光照反应。</think>在Unity中实现基于PBR的风格化草渲染需要结合物理渲染基础和艺术化处理,以下是分步骤实现方案: 1. **基础几何构建** - 使用交叉四边形(cross-quad)或自定义面片 - 通过几何着色器生成叶片(移动端建议预生成) ```hlsl // 示例几何着色器叶片生成 [maxvertexcount(3)] void geom(point v2g input[1], inout TriangleStream<g2f> triStream) { g2f o; // 生成三角形顶点数据 // 添加顶点位置偏移形成叶片形状 } ``` 2. **PBR材质核心参数** ```mathematica Albedo = 渐变绿色纹理采样(如$$Color_{base} = tex2D(_MainTex, uv) \times 0.8 + 0.2$$) Smoothness = 0.3-0.5(保持适度光泽) Metallic = 0(草为非金属材质) ``` 3. **风格化光照改造** - 漫反射使用Lambert + 渐变修正: ```hlsl half4 LightingStylizedGrass (SurfaceOutput s, half3 lightDir, half atten) { half NdotL = dot(s.Normal, lightDir); half ramp = smoothstep(0, 0.7, NdotL); // 硬边缘渐变 half4 c; c.rgb = s.Albedo * _LightColor0.rgb * ramp * atten; c.a = s.Alpha; return c; } ``` 4. **动态风场模拟** ```hlsl // 顶点着色器中添加风力影响 float windStrength = _WindSpeed * sin(_Time.y + posWS.x * _WindFrequency); v.vertex.x += windStrength * _WindDirection.x * noiseTex.SampleLevel(sampler_noiseTex, uv, 0).r; v.vertex.z += windStrength * _WindDirection.y * noiseTex.SampleLevel(sampler_noiseTex, uv, 0).g; ``` 5. **高级特性实现** - **边缘透光**:添加次表面散射效果 ```hlsl float backLit = saturate(dot(-lightDir, viewDir)); col.rgb += _SubsurfaceColor * backLit * (1 - NdotL); ``` - **交互变形**:使用球体碰撞器检测 ```csharp void Update(){ foreach(var col in Physics.OverlapSphere(transform.position, _Radius)){ ApplyVertexDisplacement(col.transform.position); } } ``` 6. **性能优化方案** - GPU Instancing配置: ```hlsl #pragma multi_compile_instancing UNITY_INSTANCING_BUFFER_START(Props) UNITY_DEFINE_INSTANCED_PROP(float4, _ColorVariation) UNITY_INSTANCING_BUFFER_END(Props) ``` - LOD分级策略: ``` LOD0:完整细节(<10m) LOD1:简化面片(10-20m) LOD2:卡片式渲染(>20m) ``` 实现要点: 1. 在Shader中混合PBR光照计算和风格化处理 2. 使用噪声纹理驱动自然随机运动 3. 通过顶点颜色控制个体差异(如颜色偏移、摆动幅度) 4. 配置合理的渲染队列(建议使用AlphaTest) 5. 添加基于距离的视差效果增强空间感 最终效果调节建议: - 保持镜面反射强度在0.2-0.4之间 - 使用自定义阴影色(如偏蓝的暗部) - 添加全局高度渐变(草根到草尖颜色变化) - 实现与场景灯光的适配性测试(昼夜变化场景)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值