About
- Frostbite の資料で ディフューズ BRDF と スペキュラ BRDF のコードが載っていたので, メモとして貼り付け
URL
- Siggraph 2014 : Moving Frostbite to Physically based rendering
- "SIGGRAPH 2014 Course: Physically Based Shading in Theory and Practice"
Note
- 以下は "Moving Frostbite to Physically based rendering" から引用したコードにコメントをつけたもの
// F 項 : フレネルのシュリック近似
float3 F_Schlick( in float3 f0, in float f90, in float u )
{
return f0 + ( f90 - f0 ) * pow( 1. f - u, 5.f );
}
// V 項 : スミスを GGX 向けに補正したもの
float V_SmithGGXCorrelated( float NdotL, float NdotV, float alphaG )
{
// Original formulation of G_SmithGGX Correlated
// lambda_v = (-1 + sqrt ( alphaG2 * (1 - NdotL2 ) / NdotL2 + 1)) * 0.5 f;
// lambda_l = (-1 + sqrt ( alphaG2 * (1 - NdotV2 ) / NdotV2 + 1)) * 0.5 f;
// G_SmithGGXCorrelated = 1 / (1 + lambda_v + lambda_l );
// V_SmithGGXCorrelated = G_SmithGGXCorrelated / (4.0 f * NdotL * NdotV );
// This is the optimize version
float alphaG2 = alphaG * alphaG;
// Caution : the " NdotL *" and " NdotV *" are explicitely inversed , this is not a mistake .
float Lambda_GGXV = NdotL * sqrt( ( -NdotV * alphaG2 + NdotV ) * NdotV + alphaG2 );
float Lambda_GGXL = NdotV * sqrt( ( -NdotL * alphaG2 + NdotL ) * NdotL + alphaG2 );
return 0.5 f / ( Lambda_GGXV + Lambda_GGXL );
}
// D 項 : GGX
float D_GGX( float NdotH, float m )
{
// Divide by PI is apply later
float m2 = m * m;
float f = ( NdotH * m2 - NdotH ) * NdotH + 1;
return m2 / ( f * f );
}
// ディズニーのディフューズ
float Fr_DisneyDiffuse ( float NdotV , float NdotL , float LdotH ,
float linearRoughness )
{
float energyBias = lerp (0, 0.5 , linearRoughness );
float energyFactor = lerp (1.0 , 1.0 / 1.51 , linearRoughness );
float fd90 = energyBias + 2.0 * LdotH * LdotH * linearRoughness ;
float3 f0 = float3 (1.0f, 1.0f, 1.0 f);
float lightScatter = F_Schlick (f0 , fd90 , NdotL ).r;
float viewScatter = F_Schlick (f0 , fd90 , NdotV ).r;
return lightScatter * viewScatter * energyFactor ;
}
// 以下は使用例
// 最後の項はアーティファクト対策
float NdotV = abs( dot( N, V ) ) + 1e - 5f;
float3 H = normalize( V + L );
float LdotH = saturate( dot( L, H ) );
float NdotH = saturate( dot( N, H ) );
float NdotL = saturate( dot( N, L ) );
// ディフューズ BRDF
float Fd = Fr_DisneyDiffuse( NdotV, NdotL, LdotH, linearRoughness ) / PI;
// スペキュラ BRDF
float3 F = F_Schlick( f0, f90, LdotH );
float Vis = V_SmithGGXCorrelated( NdotV, NdotL, roughness );
float D = D_GGX( NdotH, roughness );
float Fr = D * F * Vis / PI;