|
|
|
|
|
|
L = 2.0 * dot(V, H) * H - V; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Special case where N == V. |
|
|
|
void ImportanceSampleGGXDirIsotropic(float2 u, |
|
|
|
float3 V, |
|
|
|
float3 N, |
|
|
|
float3 tangentX, |
|
|
|
float3 tangentY, |
|
|
|
float roughness, |
|
|
|
out float3 L, |
|
|
|
out float NdotH) |
|
|
|
{ |
|
|
|
// GGX NDF sampling |
|
|
|
float cosThetaH = sqrt((1.0 - u.x) / (1.0 + (roughness * roughness - 1.0) * u.x)); |
|
|
|
float sinThetaH = sqrt(saturate(1.0 - cosThetaH * cosThetaH)); |
|
|
|
float phiH = TWO_PI * u.y; |
|
|
|
|
|
|
|
// Transform from spherical into Cartesian. |
|
|
|
float3 localH = float3(sinThetaH * cos(phiH), sinThetaH * sin(phiH), cosThetaH); |
|
|
|
|
|
|
|
// localN == localV == float3(0.0, 0.0, 1.0). |
|
|
|
NdotH = localH.z; |
|
|
|
|
|
|
|
// Compute { L = reflect(-localV, H) }. |
|
|
|
float VdotH = NdotH; |
|
|
|
L = float3(0.0, 0.0, -1.0) + 2.0 * VdotH * localH; |
|
|
|
|
|
|
|
// Local to world |
|
|
|
L = tangentX * L.x + tangentY * L.y + N * L.z; |
|
|
|
} |
|
|
|
|
|
|
|
// ref: http://blog.selfshadow.com/publications/s2012-shading-course/burley/s2012_pbs_disney_brdf_notes_v3.pdf p26 |
|
|
|
void ImportanceSampleAnisoGGXDir( float2 u, |
|
|
|
float3 V, |
|
|
|
|
|
|
uint sampleCount, // Matches the size of the precomputed Fibonacci point set |
|
|
|
bool prefilter = true) // static bool |
|
|
|
{ |
|
|
|
float3 acc = float3(0.0, 0.0, 0.0); |
|
|
|
float accWeight = 0; |
|
|
|
float3 acc = float3(0.0, 0.0, 0.0); |
|
|
|
float accWeight = 0; |
|
|
|
|
|
|
|
float2 randNum = InitRandom(V.xy * 0.5 + 0.5); |
|
|
|
|
|
|
|
|
|
|
for (uint i = 0; i < sampleCount; ++i) |
|
|
|
{ |
|
|
|
float2 u = k_Fibonacci2dSeq55[i]; |
|
|
|
u = frac(u + randNum); |
|
|
|
float2 u = k_Fibonacci2dSeq55[i]; |
|
|
|
u = frac(u + randNum); |
|
|
|
float3 H; |
|
|
|
ImportanceSampleGGXDir(u, V, N, tangentX, tangentY, roughness, H, L); |
|
|
|
float NdotH; |
|
|
|
ImportanceSampleGGXDirIsotropic(u, V, N, tangentX, tangentY, roughness, L, NdotH); |
|
|
|
float NdotL = saturate(dot(N,L)); |
|
|
|
float NdotL = saturate(dot(N, L)); |
|
|
|
|
|
|
|
float mipLevel; |
|
|
|
|
|
|
|
|
|
|
// - OmegaS : Solid angle associated to a sample |
|
|
|
// - OmegaP : Solid angle associated to a pixel of the cubemap |
|
|
|
|
|
|
|
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 |
|
|
|
// invOmegaP is precomputed on CPU and provide as a parameter of the function |
|
|
|