|
|
|
|
|
|
// weightOverPdf = F(H) * G(V, L) * (L.H) / ((N.H) * (N.V)) |
|
|
|
// weightOverPdf = F(H) * 4 * (N.L) * V(V, L) * (L.H) / (N.H) with V(V, L) = G(V, L) / (4 * (N.L) * (N.V)) |
|
|
|
// Remind (L.H) == (V.H) |
|
|
|
// F is apply outside the function |
|
|
|
// F is apply outside the function |
|
|
|
float TdotV = dot(tangentX, V); |
|
|
|
float BdotV = dot(tangentY, V); |
|
|
|
float TdotL = saturate(dot(tangentX, L)); |
|
|
|
|
|
|
// Ref: Listing 18 in "Moving Frostbite to PBR" + https://knarkowicz.wordpress.com/2014/12/27/analytical-dfg-term-for-ibl/ |
|
|
|
float4 IntegrateGGXAndDisneyFGD(float3 V, float3 N, float roughness, uint sampleCount) |
|
|
|
{ |
|
|
|
float NdotV = saturate(dot(N, V)); |
|
|
|
float NdotV = GetShiftedNdotV(N, V, false); |
|
|
|
float4 acc = float4(0.0, 0.0, 0.0, 0.0); |
|
|
|
// Add some jittering on Hammersley2d |
|
|
|
float2 randNum = InitRandom(V.xy * 0.5 + 0.5); |
|
|
|
|
|
|
} |
|
|
|
else // Prefiltered BRDF importance sampling |
|
|
|
{ |
|
|
|
float NdotH = saturate(dot(N, H)); |
|
|
|
// Note: since L and V are symmetric around H, LdotH == VdotH |
|
|
|
float LdotH = saturate(dot(L, H)); |
|
|
|
|
|
|
|
// Use pre - filtered importance sampling (i.e use lower mipmap |
|
|
|
// level for fetching sample with low probability in order |
|
|
|
// to reduce the variance ). |
|
|
|
// ( Reference : GPU Gem3: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html) |
|
|
|
// Use lower MIP-map levels for fetching samples with low probabilities |
|
|
|
// in order to reduce the variance. |
|
|
|
// Ref: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html |
|
|
|
// |
|
|
|
// pdf = D * NdotH * jacobian, where jacobian = 1.0 / (4* LdotH). |
|
|
|
// Since we pre - integrate the result for normal direction , |
|
|
|
// N == V and then NdotH == LdotH . This is why the BRDF pdf |
|
|
|
// can be simplifed from : |
|
|
|
// pdf = D * NdotH /(4* LdotH ) to pdf = D / 4; |
|
|
|
// Since L and V are symmetric around H, LdotH == VdotH. |
|
|
|
// Since we pre-integrate the result for the normal direction, |
|
|
|
// N == V and then NdotH == LdotH. Therefore, the BRDF's pdf |
|
|
|
// can be simplified: |
|
|
|
// pdf = D * NdotH / (4 * LdotH) = D * 0.25; |
|
|
|
float pdf = D_GGXNoPI(NdotH, roughness) * NdotH / (4.0 * LdotH); // TODO: Check if divide PI is required here |
|
|
|
float omegaS = 1.0 / (sampleCount * pdf); // Solid angle associated to a sample |
|
|
|
float NdotH = saturate(dot(N, H)); |
|
|
|
float pdf = D_GGX(NdotH, roughness) * 0.25; |
|
|
|
float omegaS = 1.0 / (sampleCount * pdf); // Solid angle associated with the sample |
|
|
|
// float omegaP = FOUR_PI / (6.0f * cubemapWidth * cubemapWidth); // Solid angle associated to a pixel of the cubemap |
|
|
|
// Clamp is not necessary as the hardware will do it. |
|
|
|
// mipLevel = Clamp(0.5f * log2(omegaS * invOmegaP), 0, mipmapcount); |
|
|
|
mipLevel = 0.5 * log2(omegaS * invOmegaP); // Clamp is not necessary as the hardware will do it. |
|
|
|
// float omegaP = FOUR_PI / (6.0f * cubemapWidth * cubemapWidth); // Solid angle associated with the pixel of the cubemap |
|
|
|
mipLevel = 0.5 * log2(omegaS * invOmegaP) + 1.0; // Clamp is not necessary as the hardware will do it |
|
|
|
} |
|
|
|
|
|
|
|
if (NdotL > 0.0f) |
|
|
|