129 lines
3.3 KiB
HLSL
129 lines
3.3 KiB
HLSL
#ifndef _SAMPLING_SAMPLING_COMMON_HLSL_
|
|
#define _SAMPLING_SAMPLING_COMMON_HLSL_
|
|
|
|
#ifndef PI
|
|
#define PI 3.141592653589f
|
|
#endif
|
|
|
|
// Paper: Building an Orthonormal Basis, Revisited.
|
|
// Tom Duff, James Burgess, Per Christensen, Christophe Hery, Andrew Kensler, Max Liani, and Ryusuke Villemin (Pixar).
|
|
// https://graphics.pixar.com/library/OrthonormalB/paper.pdf
|
|
void OrthoBasisFromVector(float3 n, out float3 b1, out float3 b2)
|
|
{
|
|
float sign = n.z >= 0.0f ? 1.0f : -1.0f;
|
|
const float a = -1.0f / (sign + n.z);
|
|
const float b = n.x * n.y * a;
|
|
b1 = float3(1.0f + sign * n.x * n.x * a, sign * b, -sign * n.x);
|
|
b2 = float3(b, sign + n.y * n.y * a, -n.y);
|
|
}
|
|
|
|
float3x3 OrthoBasisFromVector(float3 n)
|
|
{
|
|
float3 t, b;
|
|
OrthoBasisFromVector(n, t, b);
|
|
return transpose(float3x3(t, b, n));
|
|
}
|
|
|
|
void SampleDiffuseBrdf(float2 u, float3 shadingNormal, out float3 wi)
|
|
{
|
|
wi = float3(0, 0, 0);
|
|
|
|
float a = sqrt(u.x);
|
|
float b = 2.0 * PI * u.y;
|
|
float3 localWi = float3(a * cos(b), a * sin(b), sqrt(1.0f - u.x));
|
|
|
|
float3x3 TBN = OrthoBasisFromVector(shadingNormal);
|
|
wi = mul(TBN, localWi);
|
|
}
|
|
|
|
bool SampleDiffuseBrdf(float2 u, float3 geometryNormal, float3 shadingNormal, float3 wo, out float3 wi, out float pdf)
|
|
{
|
|
pdf = 0.0f;
|
|
wi = 0.0f;
|
|
bool valid = true;
|
|
if (dot(geometryNormal, wo) <= 0.0f)
|
|
valid = false;
|
|
else
|
|
{
|
|
float a = sqrt(1.0f - u.x);
|
|
float b = 2.0 * PI * u.y;
|
|
float3 localWi = float3(a * cos(b), a * sin(b), sqrt(u.x));
|
|
|
|
float3x3 TBN = OrthoBasisFromVector(shadingNormal);
|
|
wi = mul(TBN, localWi);
|
|
|
|
pdf = localWi.z / PI;
|
|
}
|
|
return valid;
|
|
}
|
|
|
|
float3 MapSquareToSphere(float2 unitSquareCoords)
|
|
{
|
|
float theta = (2.0f * PI) * unitSquareCoords.x;
|
|
float sinTheta, cosTheta;
|
|
sincos(theta, sinTheta, cosTheta);
|
|
|
|
float cosPhi = 1.0f - 2.0f * unitSquareCoords.y;
|
|
float sinPhi = sqrt(max(0.0f, 1.0f - cosPhi * cosPhi));
|
|
|
|
return float3(sinPhi * cosTheta, sinPhi * sinTheta, cosPhi);
|
|
}
|
|
|
|
// An optimized version of the area-preserving square-to-disk map presented in "A Low Distortion Map Between Disk and Square". Copied from from http://psgraphics.blogspot.com/2011/01/improved-code-for-concentric-map.html.
|
|
float2 MapSquareToDisk(float2 rnd)
|
|
{
|
|
//Code flow makes sure that division by 0 and thus NaNs cannot happen.
|
|
float phi;
|
|
float r;
|
|
float a = rnd.x * 2.0f - 1.0f;
|
|
float b = rnd.y * 2.0f - 1.0f;
|
|
|
|
if (a * a > b * b)
|
|
{
|
|
r = a;
|
|
phi = (PI * 0.25f) * (b / a);
|
|
}
|
|
else
|
|
{
|
|
r = b;
|
|
if (b == 0.0f)
|
|
phi = PI * 0.5f;
|
|
else
|
|
phi = (PI * 0.5f) - (PI * 0.25f) * (a / b);
|
|
}
|
|
return float2(r * cos(phi), r * sin(phi));
|
|
}
|
|
|
|
float3 CosineSample(float2 u, float3 normal)
|
|
{
|
|
float a = sqrt(u.x);
|
|
float b = 2.0f * PI * u.y;
|
|
float3 localDir = float3(a * cos(b), a * sin(b), sqrt(1.0f - u.x));
|
|
float3x3 basis = OrthoBasisFromVector(normal);
|
|
return mul(basis, localDir);
|
|
}
|
|
|
|
float PowerHeuristic(float f, float b)
|
|
{
|
|
float q = (f * f) + (b * b);
|
|
return q > 0 ? (f * f) / q : 0;
|
|
}
|
|
|
|
float UintToFloat01(uint x)
|
|
{
|
|
return x * 2.3283064365386963e-10; // (1.f / (1ULL << 32));
|
|
}
|
|
|
|
int Log2Int(uint v)
|
|
{
|
|
return firstbithigh(v);
|
|
}
|
|
|
|
int Log2IntUp(uint v)
|
|
{
|
|
int n = Log2Int(v);
|
|
return v > (1u << n) ? n + 1 : n;
|
|
}
|
|
|
|
#endif
|