UnityGame/Library/PackageCache/com.unity.rendering.light-transport/Runtime/Sampling/Common.hlsl
2024-10-27 10:53:47 +03:00

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