ambient_sky 0.2.0

Ambient sky. Host-only.
Documentation
const atmo_radius = 6471e3;
const planet_radius = 6371e3;

struct Node {
    density: f32,
    origin: vec3<f32>,
    size: f32,
    children: array<u32, 8>,
};

struct CloudBuffer {
    clouds: array<Node>,
};

@group(MATERIAL_BIND_GROUP)
@binding(0)
var<storage> cloud_buffer: CloudBuffer;

fn sphere_intersect(pos: vec3<f32>, dir: vec3<f32>, r: f32) -> vec2<f32> {
    let a = dot(dir, dir);
    let b = 2.0 * dot(dir, pos);
    let c = dot(pos, pos) - (r * r);
    let d = (b * b) - 4.0 * a * c;

    if d < 0. {
        return vec2<f32>(1e5, -1e5);
    }

    return vec2<f32>(
        max((-b - sqrt(d)) / (2.0 * a), 0.0),
        (-b + sqrt(d)) / (2.0 * a),
    );
}

const DISTANCE_THRESHOLD: f32 = 0.1;

fn cube_intersect(origin: f32, size: f32, ray_o: vec3<f32>, dir: vec3<f32>) -> f32 {
    let origin = ray_o - origin;
    let inv_dir = vec3<f32>(1. / dir.x, 1. / dir.y, 1. / dir.z);
    let t1 = (-size - origin) * inv_dir;
    let t2 = (size - origin) * inv_dir;

    var tmin = min(t1, t2);
    var tmax = max(t1, t2);

    let bestMin = max(tmin.x, max(tmin.y, tmin.z));
    let bestMax = min(tmax.x, min(tmax.y, tmax.z));

    return f32(bestMax > 0.) * (bestMax - bestMin);
}

// Returns the distance along the ray, or < 0
fn node_ray(node: Node, origin: vec3<f32>, dir: vec3<f32>) -> f32 {
    return 1.0;
}

fn scattering(depth: f32, pos: vec3<f32>, dir: vec3<f32>) -> vec3<f32> {
    let orig = pos + vec3<f32>(0.0, 0.0, planet_radius);
    // Get atmosphere intersection
    let ray_l = sphere_intersect(orig, dir, atmo_radius);

    let dist = ray_l.y - ray_l.x;

    let dir = normalize(dir);

    let steps = 16;
    let step_len = dist / f32(steps);

    let light_dir = global_params.sun_direction.xyz;
    let u = dot(dir, light_dir);
    let g = 0.76;
    let uu = u * u;
    let gg = g * g;

    let beta_ray = vec3<f32>(5.5e-6, 13.0e-6, 22.4e-6);
    // let beta_ray = vec3<f32>(3.8e-6, 5.5e-7, 16.1e-6);
    let beta_mie = vec3<f32>(21e-6);

    let allow_mie = depth >= ray_l.y || depth > global_params.camera_far * 0.9;
    // How likely is light from the sun to scatter to us
    let phase_ray = max(3.0 / (16.0 * PI) * (1.0 + uu), 0.);
    // 3 / (16pi) * cos2()
    var phase_mie = max((3.0 / (8.0 * PI)) * ((1.0 - gg) * (1.0 + uu)) / ((2.0 + gg) * pow(1.0 + gg - 2.0 * g * u, 1.5)), 0.);
    phase_mie = phase_mie * f32(allow_mie);

    // Accumulation of scattered light
    var total_ray = vec3<f32>(0.);
    var total_mie = vec3<f32>(0.);

    // Optical depth
    var rayleigh = 0.0;
    var mie = 0.0;

    let Hr = 8e3;
    let Hm = 1.2e3;

    var pos_i = 0.0;

    // Primary ray
    for (var i = 0; i < steps; i = i + 1) {
        let p = orig + dir * pos_i;

        let height = length(p) - planet_radius;
        let hr = exp(-height / Hr) * step_len;
        let hm = exp(-height / Hm) * step_len;

        // Accumulate density along viewing ray
        rayleigh = rayleigh + max(hr, 0.);
        mie = mie + max(hm, 0.);

        // Distance from ray sample to the atmosphere towards the sun
        let ray = sphere_intersect(p, light_dir, atmo_radius);

        // if (dist < 0.0) { return vec3<f32>(1., 0., 0.); }

        // Cast ray into the sun
        let sun_steps = 8;
        let sun_len = ray.y / f32(sun_steps);
        // Density along light ray
        var l_r = 0.0;
        var l_m = 0.0;

        var pos_l = ray_l.x;

        for (var j = 0; j < sun_steps; j = j + 1) {
            // let l_pos = p + light_dir * f32(j) * sun_len;
            let p = p + light_dir * pos_l;

            let height_l = length(p) - planet_radius;
            let h_ray = exp(-height_l / Hr) * sun_len;
            let h_mie = exp(-height_l / Hm) * sun_len;

            l_r = l_r + max(h_ray, 0.);
            l_m = l_m + max(h_mie, 0.);

            pos_l = pos_l + sun_len;
        }

        // Add the results of light integration by using the accumulated density
        // and beta coeff
        let tau = beta_ray * (rayleigh + l_r) + beta_mie * (mie + l_m);

        let attn = exp(-tau);

        total_ray = total_ray + attn * hr;
        total_mie = total_mie + attn * hm;

        // Travel forward
        pos_i = pos_i + step_len;
    }

    let result = (total_ray * beta_ray * phase_ray + total_mie * beta_mie * phase_mie) * 20.0;

    return result;
}

fn get_sky_color(
    depth: f32,
    origin: vec3<f32>,
    forward: vec3<f32>,
) -> vec3<f32> {
    let spot_rad = 1.0 - dot(forward, global_params.sun_direction.xyz);
    let d = 2000.0;
    let g = 3.0;
    let spot = exp(-pow(d * spot_rad, g));


    return scattering(depth, origin, forward) + global_params.sun_diffuse.rgb * spot;
}