GGX
https://www.jianshu.com/p/9e6253897e39
Decima의 대략적인 구현도 UE4의 방식을 따르는데, 선택한 광원의 위치가 더 이상 반사광에 가장 가까운 지점이 아니라 N⋅H를 가장 크게 할 수 있는 지점(N이 가까울수록, H는 GGX 하이라이트 분포에 있거나, R이 L에 가까울수록 조명이 BRDF에 더 많이 기여하므로 Disney BRDF Explorer에서 GGX 분포를 직접 확인할 수 있습니다.)
Decima는 다음과 같은 방법으로 빛의 방향을 선택합니다.
B, L_c, T를 좌표계로 하고 이 원판에서 N⋅H가 최대점에 도달하도록 phiφ를 찾는다.
는 보편적으로 , 으로 변환됩니다.
그리고 (분수에 근 부호가 포함되어 있으므로 이것을 선택하고 직접에대한GGX적NDF계산을 한다)
f(x)=gx4+hx3+ix2+jx2+kax4+bx3+cx2+dx2+e,x=tan2ϕ
함수의 근은 뉴턴 반복으로 찾을 수 있으므로 는 여러 반복 후에 근 값으로 수렴할 수 있습니다. 이떄 x=f(x) 에 대해 뉴턴 iteration을 수행하고
여기서 사용시 GGX에서 제공하는 계산식에 각별히 주의가 필요합니다 변경된 NdotH를 제외하고 NdotL에서 L과 H는 NdotV, VdotL, LdotH 모두 초기 L=normalize(point-hitPoint)L=normalize (point-hitPoint ) 방향, Point가 Normal에 수직이면 실패하지만 여전히 더 나은 결과를 얻을 수 있습니다.
//https://agraphicsguy.wordpress.com/2015/11/01/sampling-microfacet-brdf/
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;
}
댓글
댓글 쓰기