78 lines
2.4 KiB
GLSL
78 lines
2.4 KiB
GLSL
// Sampling utility functions
|
|
|
|
#ifndef SAMPLING_GLSL
|
|
#define SAMPLING_GLSL
|
|
|
|
// Uniform sphere sampling
|
|
vec3 random_in_unit_sphere(inout uint seed) {
|
|
float z = 1.0 - 2.0 * random_float(seed);
|
|
float r = sqrt(max(0.0, 1.0 - z * z));
|
|
float phi = 2.0 * PI * random_float(seed);
|
|
return vec3(r * cos(phi), r * sin(phi), z);
|
|
}
|
|
|
|
vec3 random_unit_vector(inout uint seed) {
|
|
return normalize(random_in_unit_sphere(seed));
|
|
}
|
|
|
|
// Cosine-weighted hemisphere sampling for Lambertian BRDF
|
|
// Matches pdf = cos(theta) / PI for faster convergence
|
|
vec3 sample_cosine_weighted(vec3 N, inout uint seed) {
|
|
// Malley method: uniform disk -> hemisphere
|
|
float r = sqrt(random_float(seed));
|
|
float phi = 2.0 * PI * random_float(seed);
|
|
float x = r * cos(phi);
|
|
float y = r * sin(phi);
|
|
float z = sqrt(max(0.0, 1.0 - x * x - y * y));
|
|
|
|
vec3 up = (abs(N.y) < 0.999) ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);
|
|
vec3 T = normalize(cross(up, N));
|
|
vec3 B = cross(N, T);
|
|
mat3 onb = mat3(T, B, N);
|
|
return onb * vec3(x, y, z);
|
|
}
|
|
|
|
// Build orthonormal basis from normal vector
|
|
mat3 build_onb(vec3 N) {
|
|
vec3 up = (abs(N.y) < 0.999) ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);
|
|
vec3 T = normalize(cross(up, N));
|
|
vec3 B = cross(N, T);
|
|
return mat3(T, B, N);
|
|
}
|
|
|
|
// GGX importance sampling: sample microfacet normal (half vector)
|
|
// Returns sampled half vector in world space
|
|
vec3 sample_ggx_half_vector(float roughness, vec3 N, inout uint seed) {
|
|
float a = roughness * roughness;
|
|
float a2 = a * a;
|
|
|
|
float u1 = random_float(seed);
|
|
float u2 = random_float(seed);
|
|
|
|
u1 = clamp(u1, 0.001, 0.999);
|
|
|
|
// Spherical coordinates from GGX distribution
|
|
float cos_theta = sqrt((1.0 - u1) / ((a2 - 1.0) * u1 + 1.0));
|
|
cos_theta = clamp(cos_theta, 0.0, 1.0);
|
|
float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta));
|
|
float phi = 2.0 * PI * u2;
|
|
|
|
// Convert to Cartesian in tangent space
|
|
vec3 H_tangent = vec3(sin_theta * cos(phi), sin_theta * sin(phi), cos_theta);
|
|
|
|
// Transform to world space
|
|
mat3 onb = build_onb(N);
|
|
return normalize(onb * H_tangent);
|
|
}
|
|
|
|
// GGX importance sampling PDF
|
|
float ggx_pdf(float NdotH, float roughness) {
|
|
float a = roughness * roughness;
|
|
float a2 = a * a;
|
|
float denom = NdotH * NdotH * (a2 - 1.0) + 1.0;
|
|
float D = a2 / (PI * denom * denom);
|
|
return D * NdotH;
|
|
}
|
|
|
|
#endif // SAMPLING_GLSL
|