About
- GGX のスペキュラシェーディングにおける重点サンプリングについて
- モンテカルロ法を使って, GGX のスペキュラシェーディングによる IBL を求めるのに使う
- 下の例だと, 1024 個の点をサンプリングしている
- 仮にミップマップを使ったとしても, 十分なクオリティを出すためには 16 点以上のサンプリングが必要とのこと
URL
- "Real Shading in Unreal Engine 4" SIGGRAPH2013
- NOTES ON IMPORTANCE SAMPLING @ AUGMENTED PIXELS
- "Moving Frostbite to Physically based rendering" SIGGRAPH 2014
- IBL
Note
// From NOTES ON IMPORTANCE SAMPLING @ AUGMENTED PIXELS vec2 importance_sample_ggx( vec2 xi ) { float phi = 2.0f * PI * xi.x; float theta = acos( sqrt( ( 1.0f - xi.y )/ ( ( a * a - 1.0f ) * xi.y + 1.0f ) ) ); return vec2( phi, theta ); }
- 以下は "Real Shading in Unreal Engine 4" のコースノートから引用してコメントをつけたもの
// GGX の重点サンプリングをする関数で, ハーフベクトルを返す float3 ImportanceSampleGGX( float2 Xi, float Roughness , float3 N ) { // α = ラフネス^2 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 ); return TangentX * H.x + TangentY * H.y + N * H.z; } // リファレンスとしての GGX の重点サンプリング float3 SpecularIBL( float3 SpecularColor, float Roughness, float3 N, float3 V ) { float3 SpecularLighting = 0; // サンプリングするためのループ const uint NumSamples = 1024; for( uint i = 0; i < NumSamples; i++ ) { // Hammersley サンプリングによる乱数 float2 Xi = Hammersley( i, NumSamples ); // 上の GGX の重点サンプリング 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; // G 項 float G = G_Smith( Roughness , NoV, NoL ); // F 項 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; }