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;
}