|
|
|
|
|
|
|
|
|
|
void ImportanceSampleCosDir(float2 u, |
|
|
|
float3x3 localToWorld, |
|
|
|
out float3 L) |
|
|
|
out float3 L, |
|
|
|
out float NdotL) |
|
|
|
float cosTheta = sqrt(saturate(1.0 - u.x)); |
|
|
|
float cosTheta = sqrt(1.0 - u.x); |
|
|
|
L = SphericalToCartesian(phi, sinTheta, cosTheta); |
|
|
|
L = mul(L, localToWorld); |
|
|
|
float3 localL = SphericalToCartesian(phi, sinTheta, cosTheta); |
|
|
|
|
|
|
|
NdotL = localL.z; |
|
|
|
|
|
|
|
L = mul(localL, localToWorld); |
|
|
|
} |
|
|
|
|
|
|
|
void ImportanceSampleGGXDir(float2 u, |
|
|
|
|
|
|
out float3 L, |
|
|
|
out float NdotL, |
|
|
|
out float NdotH, |
|
|
|
out float VdotH, |
|
|
|
bool VeqN = false) |
|
|
|
|
|
|
VdotH = saturate(dot(localV, localH)); |
|
|
|
} |
|
|
|
|
|
|
|
// Compute { L = reflect(-localV, localH) } |
|
|
|
L = -localV + 2.0 * VdotH * localH; |
|
|
|
// Compute { localL = reflect(-localV, localH) } |
|
|
|
float3 localL = -localV + 2.0 * VdotH * localH; |
|
|
|
|
|
|
|
NdotL = localL.z; |
|
|
|
L = mul(L, localToWorld); |
|
|
|
L = mul(localL, localToWorld); |
|
|
|
} |
|
|
|
|
|
|
|
// ref: http://blog.selfshadow.com/publications/s2012-shading-course/burley/s2012_pbs_disney_brdf_notes_v3.pdf p26 |
|
|
|
|
|
|
out float NdotL, |
|
|
|
out float weightOverPdf) |
|
|
|
{ |
|
|
|
ImportanceSampleCosDir(u, localToWorld, L); |
|
|
|
|
|
|
|
NdotL = saturate(dot(localToWorld[2], L)); |
|
|
|
ImportanceSampleCosDir(u, localToWorld, L, NdotL); |
|
|
|
|
|
|
|
// Importance sampling weight for each sample |
|
|
|
// pdf = N.L / PI |
|
|
|
|
|
|
out float NdotL, |
|
|
|
out float weightOverPdf) |
|
|
|
{ |
|
|
|
float3 H; |
|
|
|
float NdotH; |
|
|
|
ImportanceSampleGGXDir(u, V, localToWorld, roughness, L, NdotH, VdotH); |
|
|
|
|
|
|
|
NdotL = saturate(dot(localToWorld[2], L)); |
|
|
|
float NdotH; |
|
|
|
ImportanceSampleGGXDir(u, V, localToWorld, roughness, L, NdotL, NdotH, VdotH); |
|
|
|
|
|
|
|
// Importance sampling weight for each sample |
|
|
|
// pdf = D(H) * (N.H) / (4 * (L.H)) |
|
|
|
|
|
|
// 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 |
|
|
|
|
|
|
|
// For anisotropy we must not saturate these values |
|
|
|
float TdotL = saturate(dot(tangentX, L)); |
|
|
|
float BdotL = saturate(dot(tangentY, L)); |
|
|
|
float TdotL = dot(tangentX, L); |
|
|
|
float BdotL = dot(tangentY, L); |
|
|
|
|
|
|
|
float Vis = V_SmithJointGGXAniso(TdotV, BdotV, NdotV, TdotL, BdotL, NdotL, roughnessT, roughnessB); |
|
|
|
weightOverPdf = 4.0 * Vis * NdotL * VdotH / NdotH; |
|
|
|
|
|
|
// 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 = GetShiftedNdotV(N, V, false); // This fix some rare artifact at edge. |
|
|
|
float NdotV = saturate(dot(N, V)); |
|
|
|
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); |
|
|
|
|
|
|
u.x = lerp(u.x, 0.0, bias); |
|
|
|
|
|
|
|
float3 L; |
|
|
|
float NdotH, VdotH; |
|
|
|
ImportanceSampleGGXDir(u, V, localToWorld, roughness, L, NdotH, VdotH, true); |
|
|
|
|
|
|
|
float NdotL = saturate(dot(N, L)); |
|
|
|
float NdotL, NdotH, VdotH; |
|
|
|
ImportanceSampleGGXDir(u, V, localToWorld, roughness, L, NdotL, NdotH, VdotH, true); |
|
|
|
|
|
|
|
float mipLevel; |
|
|
|
|
|
|
|