您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
195 行
5.6 KiB
195 行
5.6 KiB
#ifndef UNITY_SAMPLING_INCLUDED
|
|
#define UNITY_SAMPLING_INCLUDED
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Sample generator
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Ref: http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
|
|
uint ReverseBits32(uint bits)
|
|
{
|
|
#if 1 // Shader model 5
|
|
return reversebits(bits);
|
|
#else
|
|
bits = (bits << 16) | (bits >> 16);
|
|
bits = ((bits & 0x00ff00ff) << 8) | ((bits & 0xff00ff00) >> 8);
|
|
bits = ((bits & 0x0f0f0f0f) << 4) | ((bits & 0xf0f0f0f0) >> 4);
|
|
bits = ((bits & 0x33333333) << 2) | ((bits & 0xcccccccc) >> 2);
|
|
bits = ((bits & 0x55555555) << 1) | ((bits & 0xaaaaaaaa) >> 1);
|
|
return bits;
|
|
#endif
|
|
}
|
|
|
|
float RadicalInverse_VdC(uint bits)
|
|
{
|
|
return float(ReverseBits32(bits)) * 2.3283064365386963e-10; // 0x100000000
|
|
}
|
|
|
|
float2 Hammersley2d(uint i, uint maxSampleCount)
|
|
{
|
|
return float2(float(i) / float(maxSampleCount), RadicalInverse_VdC(i));
|
|
}
|
|
|
|
float Hash(uint s)
|
|
{
|
|
s = s ^ 2747636419u;
|
|
s = s * 2654435769u;
|
|
s = s ^ (s >> 16);
|
|
s = s * 2654435769u;
|
|
s = s ^ (s >> 16);
|
|
s = s * 2654435769u;
|
|
return float(s) / 4294967295.0;
|
|
}
|
|
|
|
float2 InitRandom(float2 input)
|
|
{
|
|
float2 r;
|
|
r.x = Hash(uint(input.x * 4294967295.0));
|
|
r.y = Hash(uint(input.y * 4294967295.0));
|
|
|
|
return r;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Sampling function
|
|
// Reference : http://www.cs.virginia.edu/~jdl/bib/globillum/mis/shirley96.pdf + PBRT
|
|
// Caution: Our light point backward (-Z), these sampling function follow this convention
|
|
//-----------------------------------------------------------------------------
|
|
|
|
float3 UniformSampleSphere(float u1, float u2)
|
|
{
|
|
float phi = TWO_PI * u2;
|
|
float cosTheta = 1.0 - 2.0 * u1;
|
|
float sinTheta = sqrt(max(0.0, 1.0 - cosTheta * cosTheta));
|
|
|
|
return float3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta); // Light point backward (-Z)
|
|
}
|
|
|
|
float3 UniformSampleHemisphere(float u1, float u2)
|
|
{
|
|
float phi = TWO_PI * u2;
|
|
float cosTheta = u1;
|
|
float sinTheta = sqrt(max(0.0, 1.0 - cosTheta * cosTheta));
|
|
|
|
return float3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta); // Light point backward (-Z)
|
|
}
|
|
|
|
float3 UniformSampleDisk(float u1, float u2)
|
|
{
|
|
float r = sqrt(u1);
|
|
float phi = TWO_PI * u2;
|
|
|
|
return float3(r * cos(phi), r * sin(phi), 0); // Generate in XY plane as light point backward (-Z)
|
|
}
|
|
|
|
void SampleSphere( float2 u,
|
|
float4x4 localToWorld,
|
|
float radius,
|
|
out float lightPdf,
|
|
out float3 P,
|
|
out float3 Ns)
|
|
{
|
|
float u1 = u.x;
|
|
float u2 = u.y;
|
|
|
|
Ns = UniformSampleSphere(u1, u2);
|
|
|
|
// Transform from unit sphere to world space
|
|
P = radius * Ns + localToWorld[3].xyz;
|
|
|
|
// pdf is inverse of area
|
|
lightPdf = 1.0 / (FOUR_PI * radius * radius);
|
|
}
|
|
|
|
void SampleHemisphere( float2 u,
|
|
float4x4 localToWorld,
|
|
float radius,
|
|
out float lightPdf,
|
|
out float3 P,
|
|
out float3 Ns)
|
|
{
|
|
float u1 = u.x;
|
|
float u2 = u.y;
|
|
|
|
// Random point at hemisphere surface
|
|
Ns = -UniformSampleHemisphere(u1, u2); // We want the y down hemisphere
|
|
P = radius * Ns;
|
|
|
|
// Transform to world space
|
|
P = mul(float4(P, 1.0), localToWorld).xyz;
|
|
Ns = mul(Ns, (float3x3)(localToWorld));
|
|
|
|
// pdf is inverse of area
|
|
lightPdf = 1.0 / (TWO_PI * radius * radius);
|
|
}
|
|
|
|
// Note: The cylinder has no end caps (i.e. no disk on the side)
|
|
void SampleCylinder(float2 u,
|
|
float4x4 localToWorld,
|
|
float radius,
|
|
float width,
|
|
out float lightPdf,
|
|
out float3 P,
|
|
out float3 Ns)
|
|
{
|
|
float u1 = u.x;
|
|
float u2 = u.y;
|
|
|
|
// Random point at cylinder surface
|
|
float t = (u1 - 0.5) * width;
|
|
float theta = 2.0 * PI * u2;
|
|
float cosTheta = cos(theta);
|
|
float sinTheta = sin(theta);
|
|
|
|
// Cylinder are align on the right axis
|
|
P = float3(t, radius * cosTheta, radius * sinTheta);
|
|
Ns = normalize(float3(0.0, cosTheta, sinTheta));
|
|
|
|
// Transform to world space
|
|
P = mul(float4(P, 1.0), localToWorld).xyz;
|
|
Ns = mul(Ns, (float3x3)(localToWorld));
|
|
|
|
// pdf is inverse of area
|
|
lightPdf = 1.0 / (TWO_PI * radius * width);
|
|
}
|
|
|
|
void SampleRectangle( float2 u,
|
|
float4x4 localToWorld,
|
|
float width,
|
|
float height,
|
|
out float lightPdf,
|
|
out float3 P,
|
|
out float3 Ns)
|
|
{
|
|
// Random point at rectangle surface
|
|
P = float3((u.x - 0.5) * width, (u.y - 0.5) * height, 0);
|
|
Ns = float3(0, 0, -1); // Light point backward (-Z)
|
|
|
|
// Transform to world space
|
|
P = mul(float4(P, 1.0), localToWorld).xyz;
|
|
Ns = mul(Ns, (float3x3)(localToWorld));
|
|
|
|
// pdf is inverse of area
|
|
lightPdf = 1.0 / (width * height);
|
|
}
|
|
|
|
void SampleDisk(float2 u,
|
|
float4x4 localToWorld,
|
|
float radius,
|
|
out float lightPdf,
|
|
out float3 P,
|
|
out float3 Ns)
|
|
{
|
|
// Random point at disk surface
|
|
P = UniformSampleDisk(u.x, u.y) * radius;
|
|
Ns = float3(0.0, 0.0, -1.0); // Light point backward (-Z)
|
|
|
|
// Transform to world space
|
|
P = mul(float4(P, 1.0), localToWorld).xyz;
|
|
Ns = mul(Ns, (float3x3)(localToWorld));
|
|
|
|
// pdf is inverse of area
|
|
lightPdf = 1.0 / (PI * radius * radius);
|
|
}
|
|
|
|
#endif // UNITY_SAMPLING_INCLUDED
|