eriseven
12/27/2017 - 11:09 AM

ImportanceSample.hlsl


uint BitReverse(uint x)
{
    x = ((x & 0x55555555) <<  1) | ((x & 0xaaaaaaaa) >>  1);
    x = ((x & 0x33333333) <<  2) | ((x & 0xcccccccc) >>  2);
    x = ((x & 0x0f0f0f0f) <<  4) | ((x & 0xf0f0f0f0) >>  4);
    x = ((x & 0x00ff00ff) <<  8) | ((x & 0xff00ff00) >>  8);
    x = ((x & 0x0000ffff) << 16) | ((x & 0xffff0000) >> 16);
    return x;
}

float2 Hammersley(uint SampleIdx, uint SampleCnt)
{
    float u = float(SampleIdx) / float(SampleCnt);
    float v = float(BitReverse(SampleIdx)) * 2.3283064365386963e-10;
    return float2(u, v);
}

float3 SphericalToCartesian(float PhiAngle, float CosTheta, float SinTheta)
{
    return float3(SinTheta * cos(PhiAngle), SinTheta * sin(PhiAngle), CosTheta);
}

float Ndf_GGX(float a2, float NoH)
{
    const float denom = (NoH * a2 - NoH) * NoH + 1.0;
    const float denSq = denom * denom;
    return a2 * ONE_OVER_PI * rcp(denSq);
}

float Pdf_GGX(float a2, float NoH, float VoH)
{
    // pdf == D(H) * N.H / (4.0 * L.H)
    // L.H == V.H
    return Ndf_GGX(a2, NoH) * NoH * rcp(VoH) * 0.25;
}

float Pdf_Blinn(float CosTheta, float n)
{
    float D = (n + 2.0) * rcp(2.0 * PI) * pow(CosTheta, n);
    return D * CosTheta;
}

float3 ImportanceSampleBlinn(float2 E, float Roughness)
{
    const float m = Roughness * Roughness;
    const float n = 2.0 * rcp(m * m) - 2.0;
    const float PhiAngle = TWO_PI * E.x;
    const float CosTheta = pow(1.0 - E.y, 1.0 * rcp(n + 1.0));
    const float SinTheta = sqrt(1.0 - CosTheta * CosTheta);
    return float4(SphericalToCartesian(PhiAngle, CosTheta));
}

float3 ImportanceSampleCos(float2 E)
{
    const float PhiAngle = TWO_PI * E.x;
    const float CosTheta = sqrt(1.0 - E.y);
    const float SinTheta = sqrt(E.y);
    return SphericalToCartesian(PhiAngle, CosTheta, SinTheta);
}

float3 ImportanceSampleGGX(float2 E, float Roughness)
{
    const float a1 = Roughness * Roughness;
    const float a2 = a1 * a1;
    const float PhiAngle = TWO_PI * E.x;
    const float CosThetaSq = (1.0 - E.y) * rcp(1.0 + (a2 - 1.0) * E.y);
    const float CosTheta = sqrt(CosThetaSq);
    const float SinTheta = sqrt(1.0 - CosThetaSq);
    return SphericalToCartesian(PhiAngle, CosTheta, SinTheta);
}

float3 TangentToWorld(float3 H, float3 TangentX, float TangentY)
{
    return TangentX * H.x + TangentY * H.y + N * H.z;
}

void ExtractTangent(float3 N, out float3 TangentX, out float3 TangentY)
{
    float3 UpVector = abs(N.z) < 0.999 ? float3(0.0, 0.0, 1.0) : float3(1.0, 0.0, 0.0);
    TangentX = normalize( cross( UpVector, N ) );
    TangentY = cross( N, TangentX );
}

float3 AdjustNormal(float3 H, float N)
{
    float3 TangentX;
    float3 TangentY;
    ExtractTangent(N, TangentX, TangentY);
    return TangentToWorld(H, TangentX, TangentY);
}