webgpu-pt

monte carlo path tracer
Contents

sky.wgsl

2.5 kB
 1const sun_angular_size = 1.0 * (PI / 180.0);
 2
 3fn dir_in_cone(u: vec2f) -> vec3<f32> {
 4    let sun_cos_theta_max = cos(0.255f * PI / 180f);
 5    let cos_theta = 1f - u.x * (1f - sun_cos_theta_max);
 6    let sin_theta = sqrt(1f - cos_theta * cos_theta);
 7    let phi = 2f * PI * u.y;
 8    let x = cos(phi) * sin_theta;
 9    let y = sin(phi) * sin_theta;
10    let z = cos_theta;
11    return vec3(x, y, z);
12}
13
14fn sample_sun_cone_dir(u: vec2f) -> vec3<f32> {
15    let v = dir_in_cone(u);
16    let onb = pixar_onb(normalize(uniforms.sun_direction));
17    return normalize(onb * v);
18}
19
20// https://www.jcgt.org/published/0006/01/01/paper-lowres.pdf
21fn pixar_onb(n: vec3f) -> mat3x3<f32> {
22    let s = select(- 1f, 1f, n.z >= 0f);
23    let a = - 1f / (s + n.z);
24    let b = n.x * n.y * a;
25    let u = vec3(1f + s * n.x * n.x * a, s * b, - s * n.x);
26    let v = vec3(b, s + n.y * n.y * a, - n.y);
27    return mat3x3(u, v, n);
28}
29
30// simplified approximation of preetham
31fn sky_glow(dir: vec3f, sun_dir: vec3f) -> vec3f {
32    let view_dir = normalize(dir);
33    let sun_dir_n = normalize(sun_dir);
34    let cos_theta = dot(view_dir, sun_dir_n);
35    if sun_dir_n.z <= 0.0 {
36        return vec3f(0.0);
37    }
38    // sun altitude still helps modulate overall warmth
39    let sun_altitude = clamp(sun_dir_n.z, 0.0, 1.0);
40    // more saturated warm tone for horizon, and deeper blue for zenith
41    let horizon_color = vec3f(1.1, 0.4, 0.2);
42    // rich orange
43    let zenith_color = vec3f(0.05, 0.2, 0.6);
44    // deep blue
45    // exaggerated curve to preserve saturation
46    let sky_color = mix(horizon_color, zenith_color, pow(sun_altitude, 0.1));
47    // rayleigh-like gradient with vertical bias
48    let rayleigh = sky_color * (0.6 + 0.4 * cos_theta * cos_theta);
49    // warm sun glow with stronger color (no gray falloff)
50    let mie = vec3f(1.3, 0.6, 0.3) * pow(max(cos_theta, 0.0), 12.0) * 0.6;
51    return clamp(rayleigh + mie, vec3f(0.0), vec3f(100.0));
52}
53
54fn sun_glow(dir: vec3f, sun_dir: vec3f) -> vec3f {
55    let view_dir = normalize(dir);
56    let sun_n = normalize(sun_dir);
57    let cos_theta = dot(view_dir, sun_n);
58    // angular radius (half the angular size)
59    let angular_radius = 0.5 * uniforms.sun_angular_size;
60    let inner = cos(angular_radius * 0.9);
61    let outer = cos(angular_radius * 1.1);
62    let sun_disk = smoothstep(outer, inner, max(cos_theta, 0.0));
63    // compute sun altitude (z-up): 0 = horizon, 1 = overhead
64    let sun_altitude = clamp(sun_n.z, 0.0, 1.0);
65    return uniforms.sun_radiance * /*tint*/
66    sun_disk;
67}