UE4中的基於物理的著色(二)

相關原文鏈接:Real Shading in Unreal Engine 4

點贊是我最大的動力~

轉載請註明出處

上一節UE4中的基於物理的著色(一)說到得到了主要的BRDF值之後,將要計算最終各個方向光線影響下的輻射度值,漫反射和高光反射分開計算,積分式子都為:

L_o(v) = int_{H } L_i(l) f(l, v) n cdot l dl


對於漫反射,UE4選擇Lambert模型BRDFf(l,v) = frac{c_{diff}} pi

最後要求 L_o(v) = frac{c_{diff}} pi int_{H } L_i(l) n cdot l dl

為了方便積分,將該式子轉成球面坐標系對 	hetaphi 積分。

ncdot l dl 部分看成 n cdot omega_i domega_iomega_i 為入射方向立體角,根據立體角的定義有部分dw=sin(θ)dθd? ,轉成球面坐標系後得到:L_o(v,?_o,θ_o)=frac{c_{diff}}{π} int_{?=0}^{2π}int_{θ=0}^{frac{1}{2}π} L_i(l,?_i,θ_i)cosθsinθd?dθ

對半球上 	hetaphi 方向均勻的採樣或者說用黎曼和的思想積分得到:

L_o(v,?_o,θ_o)=frac{c_{diff}}{π}frac{1}{n_1n_2} sum_{?=0}^{n_1}{sum_{θ=0}^{n_2}{L_i(l,?_i,θ_i)cosθsinθ}}

L_i(l,?_i,θ_i) 為入射光線,需要注意的是這裡的 	hetaphi 是定義在切空間下的坐標,需要將其轉換到世界坐標下再從環境貼圖中採樣。


對於高光反射,建立在微表面模型下,UE4使用Cook-Torrance模型BRDFf(l, v) = frac{D(h) F(v, h) G(l, v) }{4 (n cdot l) (n cdot v)} = frac{D(h) F(v, h) G(l, v) }{4 cos 	heta_i cos 	heta_o}

最後要求 L_o(v)=∫_H L_i(l) frac{D(h) F(v, h) G(l, v)}{4(n cdot l)(n cdot v)}n?ldl

對這個式子使用蒙特卡洛求積分得到:

L_o(v)=∫_H L_i(l) frac{D(h) F(v, h) G(l, v)}{4(n cdot l)(n cdot v)}n?ldl approx frac{1}{N} sum_{k = 1}^{N}{frac{L_i(l_k) frac{D(h_k) F(v, h_k) G(l_k, v)}{4(n cdot l_k)(n cdot v)}n?l_k}{P(l_k, v)}}

要估計該式子的值需要從 D(h) 中入手,不從入射光線 l 入手,具體原因和式子推導可以參考最後引用部分的文章。 D(h) 為微表面的法線概率密度函數(未歸一化),這個定義的意義不從數學公式看,從直觀感受上來說,現實中人眼看到某一微小面積的高光區域同時結合微表面角度來考慮,這片高光區域的入射光線可能是從任意方向來的,但是大部分的光線肯定還是遵循宏觀表明的法線 n 反射,也就是微表面法線 h 和宏觀表面法線 n相似的概率大,相差很多的概率小,所以說微表面法線 h 可以近似一個正太分布的鐘形曲線。

在UE4中 D(h) 的選擇為GGX / Trowbridge-Reitz模型D(h)= frac{alpha^{2}}{pi ((n cdot h)^{2} (alpha^{2} - 1) + 1)^{2}}

這也是和Disney選擇一樣,在Physically Based Shading at Disney中對 D(h) 部分描述如下,可以看到 D(h) 的大概樣子:

所以我們以 D(h) 分布來進行採樣,為了得到 符合 D(h) 分布的數據,採樣求反函數的方法。 D(h) 的定義我們已經知道了,需要對其進行歸一化。

(v cdot n) = int_{}^{} D(h) ( v cdot h ) dhcdf(h) = int_{}^{} D(h) ( n cdot h ) dh = 1 where ( v = n)

p(h) = D(h) (n cdot h)

p(	heta, phi) = sinθp(h)=Dcosθsinθ = frac{alpha^{2}cosθsinθ}{pi (cos^{2}θ (alpha^{2} - 1) + 1)^{2}}

到這一步需要注意到 	hetaphi 為兩個獨立事件,我們需要單獨求出 p(	heta) 再求在 p(	heta) 之下的 p(phi | 	heta)

p(	heta) = int_{0}^{2pi}p(	heta, phi)dphi= frac{2alpha^{2}cosθsinθ}{ (cos^{2}θ (alpha^{2} - 1) + 1)^{2}}

p(phi | 	heta) = frac{p(phi , 	heta)}{p(	heta)} = frac{1}{2pi}

cdf(p(	heta))=int_{0}^{θ}p(θ)dθ = 2α^2(frac{1}{(2α^4?4α^2+2)cos^2θ+2α^2?2}+frac{1}{2α^4?2α^2}) = xi_0

cdf(p(phi | 	heta))=int_{0}^{phi}p(phi | 	heta)dphi = frac{phi}{2pi} = xi_1

	heta = cos^{-1}sqrt{frac{1?ξ_0}{(a^2?1)?ξ_0+1}}

phi = 2 pi xi_1

最終得到 	hetaphi 的表達式, (xi_0,xi_1) 為隨機數,利用低差異序列(low-discrepancy sequence)可以得到分布更加均勻的隨機數,簡單來說就是隨機數生成過程中總是往最還沒生成過的區域生成。

通過 (xi_0,xi_1) 的隨機結果得到帶入表達式得到 	hetaphi 再轉換坐標系得到 h ,該 h 符合 p(h) 分布的數據,然後通過 hl 之間的關係,調整樣本的權重。引用自Surface Reflection: Physical and Geometrical Perspectives有frac{d omega_h}{d omega_l} = frac{1}{4 cos 	heta_h},這些參數都是在微表面下, 	heta_hlh 也為 vh 的夾角,所以 p(l) = frac{D(h) (n cdot h) }{4 (v cdot h)}

實現代碼如下:

float3 ImportanceSampleGGX( float2 Xi, float Roughness, float3 N ){ float a = Roughness * Roughness; float Phi = 2 * PI * Xi.x; float CosTheta = sqrt( (1 - Xi.y) / ( 1 + (a*a - 1) * Xi.y ) ); float SinTheta = sqrt( 1 - CosTheta * CosTheta ); float3 H; H.x = SinTheta * cos( Phi ); H.y = SinTheta * sin( Phi ); H.z = CosTheta; float3 UpVector = abs(N.z) < 0.999 ? float3(0,0,1) : float3(1,0,0); float3 TangentX = normalize( cross( UpVector, N ) ); float3 TangentY = cross( N, TangentX ); // Tangent to world space return TangentX * H.x + TangentY * H.y + N * H.z;}float3 SpecularIBL( float3 SpecularColor , float Roughness, float3 N, float3 V ){ float3 SpecularLighting = 0; const uint NumSamples = 1024; for( uint i = 0; i < NumSamples; i++ ) { float2 Xi = Hammersley( i, NumSamples ); float3 H = ImportanceSampleGGX( Xi, Roughness, N ); float3 L = 2 * dot( V, H ) * H - V; float NoV = saturate( dot( N, V ) ); float NoL = saturate( dot( N, L ) ); float NoH = saturate( dot( N, H ) ); float VoH = saturate( dot( V, H ) ); if( NoL > 0 ) { float3 SampleColor = EnvMap.SampleLevel( EnvMapSampler , L, 0 ).rgb; float G = G_Smith( Roughness, NoV, NoL ); float Fc = pow( 1 - VoH, 5 ); float3 F = (1 - Fc) * SpecularColor + Fc; // Incident light = SampleColor * NoL // Microfacet specular = D*G*F / (4*NoL*NoV) // pdf = D * NoH / (4 * VoH) SpecularLighting += SampleColor * F * G * VoH / (NoH * NoV); } } return SpecularLighting / NumSamples;}

ImportanceSampleGGX函數運用到最後 	hetaphi 的表達式,得到符合 p(h) 分布的 h 樣本數據,需要注意的是切空間和世界坐標系的轉換。SpecularIBL進行1024次採樣,計算最後的高光值,Hammersley為獲得地差異序列。

到此已經可以估計各個方向的光線漫反射和高光反射對著色的影響,然而對於實時來說,雖然用到了重要性採樣,但是採樣的數量還是很多,UE4選擇的方案將採樣數量降為1次。

frac{1}{N} sum_{k = 1}^{N}{frac{L_i(l_k) frac{D(h_k) F(v, h_k) G(l_k, v)}{4(n cdot l_k)(n cdot v)}n?l_k}{P(l_k, v)}} approx (frac{1}{sum_{k = 1}^{N}{n cdot l_k}} sum_{k = 1}^{N}{L_i(l_k) (ncdot l_k)}) (frac{1}{N} sum_{k = 1}^{N}{frac{frac{D(h_k) F(v, h_k) G(l_k, v)}{4(n cdot l_k)(n cdot v)}n?l_k}{P(l_k, v)}})

將最後積分的公式拆分成兩部分,進行預處理計算。下一節將繼續介紹。

Surface Reflection : Physical and Geometrical Perspectives ri.cmu.edu/pub_files/pu

Physically Based Shading at Disney : blog.selfshadow.com/pub

Real Shading in Unreal Engine 4 : de45xmedrsdbp.cloudfront.net.

LearnOpenGL - Theory : LearnOpenGL - Theory

LearnOpenGL - Lighting : LearnOpenGL - Lighting

LearnOpenGL - Diffuse irradiance : Diffuse irradiance

LearnOpenGL - Specular IBL : LearnOpenGL - Specular IBL

Microfacet Models for Refraction through Rough Surfaces : cs.cornell.edu/~srm/pub

基於物理著色:BRDF : 基於物理著色:BRDF

圖形學數學基礎之採樣分布映射 : 圖形學數學基礎之採樣分布映射 - CSDN博客

NOTES ON IMPORTANCE SAMPLING : Notes on importance sampling

點贊是我最大的動力~


推薦閱讀:

TAG:虛幻4遊戲引擎 | 計算機圖形學 | 實時渲染 |