Skip to main content

PROBE_WGSL

Constant PROBE_WGSL 

Source
pub const PROBE_WGSL: &str = r#"
override use_probes: bool = true;
struct ProbeLocal {
    min_spacing: vec4f,
    dims: vec4u,
}
struct ProbeGridInfo {
    min_spacing: vec4f,
    dims: vec4u,
    fallback: vec4f,
    blend: vec4f,
    shade: vec4f,
    locals: array<ProbeLocal, 4>,
}
@group(3) @binding(6) var<storage, read> probe_lower: array<u32>;
@group(3) @binding(7) var<storage, read> probe_upper: array<u32>;
@group(3) @binding(8) var<uniform> probe_grid: ProbeGridInfo;

fn probe_word(anchor: u32, index: u32) -> u32 {
    if (anchor == 0u) { return probe_lower[index]; }
    return probe_upper[index];
}

fn probe_block(anchor: u32, offset: u32) -> array<u32, 18> {
    var block: array<u32, 18>;
    if (anchor == 0u) {
        for (var k = 0u; k < 18u; k++) { block[k] = probe_lower[offset + k]; }
    } else {
        for (var k = 0u; k < 18u; k++) { block[k] = probe_upper[offset + k]; }
    }
    return block;
}

fn probe_index(xyz: vec3u, dims: vec4u) -> u32 {
    return (xyz.z * dims.y + xyz.y) * dims.x + xyz.x;
}

fn sample_probe_volume(position: vec3f, n: vec3f, point: vec3f, anchor: u32, origin: vec4f, dims: vec4u, words: u32, toward: vec3f, seen: ptr<function, f32>) -> vec4f {
    let last = vec3f(dims.xyz - vec3u(1u));
    let surface = (position - origin.xyz) / origin.w;
    let shifted = (point - origin.xyz) / origin.w;
    let surface_out = any(surface < vec3f(0.0)) || any(surface > last);
    let shifted_out = any(shifted < vec3f(0.0)) || any(shifted > last);
    if (surface_out && shifted_out) { return vec4f(0.0); }
    let coord = clamp(shifted, vec3f(0.0), last);
    let base = min(vec3u(floor(coord)), max(dims.xyz, vec3u(2u)) - vec3u(2u));
    var t = clamp(coord - vec3f(base), vec3f(0.0), vec3f(1.0));
    for (var axis = 0u; axis < 3u; axis++) {
        if (dims[axis] == 1u) { t[axis] = 0.0; }
    }
    let version_two = dims.w == 2u;
    var color = vec3f(0.0);
    var toward_luma = 0.0;
    var total = 0.0;
    for (var corner = 0u; corner < 8u; corner++) {
        var xyz = base;
        var weight = 1.0;
        for (var axis = 0u; axis < 3u; axis++) {
            let high = (corner & (1u << axis)) != 0u;
            if (high && dims[axis] > 1u) { xyz[axis] += 1u; }
            weight *= select(1.0 - t[axis], t[axis], high);
        }
        weight = max(weight - probe_grid.blend.z, 0.0);
        if (weight == 0.0) { continue; }
        let offset = words + probe_index(xyz, dims) * select(15u, 20u, version_two);
        var center = origin.xyz + vec3f(xyz) * origin.w;
        if (version_two) {
            let last = probe_word(anchor, offset + 19u);
            if (((last >> 16u) & 1u) == 0u) { continue; }
            center += vec3f(unpack2x16float(probe_word(anchor, offset + 18u)), unpack2x16float(last).x) * origin.w;
            let toward_probe = center - position + n * 0.0001;
            let facing = clamp((dot(toward_probe / max(length(toward_probe), 0.000001), n) + 1.0) * 0.5, 0.0, 1.0);
            weight *= facing * facing * facing;
            if (weight == 0.0) { continue; }
            let block = probe_block(anchor, offset);
            let toward_point = point - center;
            let distance = length(toward_point);
            let direction = toward_point / max(distance, 0.000001);
            var irradiance = vec3f(0.0);
            var toward_irradiance = 0.0;
            var mean = 0.0;
            var second = 0.0;
            for (var axis = 0u; axis < 3u; axis++) {
                let normal_component = n[axis];
                let up = normal_component >= 0.0;
                let rg = unpack2x16float(select(block[axis * 4u + 2u], block[axis * 4u], up));
                let b = unpack2x16float(select(block[axis * 4u + 3u], block[axis * 4u + 1u], up)).x;
                irradiance += vec3f(rg, b) * normal_component * normal_component;
                let toward_component = toward[axis];
                let toward_up = toward_component >= 0.0;
                let toward_rg = unpack2x16float(select(block[axis * 4u + 2u], block[axis * 4u], toward_up));
                let toward_b = unpack2x16float(select(block[axis * 4u + 3u], block[axis * 4u + 1u], toward_up)).x;
                toward_irradiance += dot(vec3f(toward_rg, toward_b), vec3f(0.2126, 0.7152, 0.0722)) * toward_component * toward_component;
                let ray_component = direction[axis];
                let pair = unpack2x16float(block[12u + axis]);
                let depth = select(pair.y, pair.x, ray_component >= 0.0);
                let ray_weight = ray_component * ray_component;
                let squared = unpack2x16float(block[15u + axis]);
                mean += ray_weight * depth * origin.w;
                second += ray_weight * select(squared.y, squared.x, ray_component >= 0.0) * origin.w * origin.w;
            }
            let variance = max(second - mean * mean, origin.w * origin.w * 0.01);
            let delta = max(distance - mean - origin.w * 0.1, 0.0);
            let chance = variance / (variance + delta * delta);
            weight *= chance * chance;
            color += irradiance * weight;
            toward_luma += toward_irradiance * weight;
            total += weight;
            continue;
        }
        let toward_probe = center - position + n * 0.0001;
        let facing = clamp((dot(toward_probe / max(length(toward_probe), 0.000001), n) + 1.0) * 0.5, 0.0, 1.0);
        weight *= facing * facing * facing;
        if (weight == 0.0) { continue; }
        let toward_point = point - center;
        let distance = length(toward_point);
        let direction = toward_point / max(distance, 0.000001);
        var irradiance = vec3f(0.0);
        var toward_irradiance = 0.0;
        var visibility = 0.0;
        for (var axis = 0u; axis < 3u; axis++) {
            let normal_component = n[axis];
            let normal_lobe = axis * 2u + select(1u, 0u, normal_component >= 0.0);
            let rg = unpack2x16float(probe_word(anchor, offset + normal_lobe * 2u));
            let b = unpack2x16float(probe_word(anchor, offset + normal_lobe * 2u + 1u)).x;
            irradiance += vec3f(rg, b) * normal_component * normal_component;
            let toward_component = toward[axis];
            if (toward_component != 0.0) {
                let toward_lobe = axis * 2u + select(1u, 0u, toward_component >= 0.0);
                let toward_rg = unpack2x16float(probe_word(anchor, offset + toward_lobe * 2u));
                let toward_b = unpack2x16float(probe_word(anchor, offset + toward_lobe * 2u + 1u)).x;
                toward_irradiance += dot(vec3f(toward_rg, toward_b), vec3f(0.2126, 0.7152, 0.0722)) * toward_component * toward_component;
            }
            let ray_component = direction[axis];
            let pair = unpack2x16float(probe_word(anchor, offset + 12u + axis));
            let depth = select(pair.y, pair.x, ray_component >= 0.0);
            let ray_weight = ray_component * ray_component;
            let reach = depth + origin.w * 0.25;
            visibility += ray_weight * clamp((reach - distance) / origin.w, 0.0, 1.0);
        }
        weight *= select(1.0, visibility, distance > 0.000001);
        color += irradiance * weight;
        toward_luma += toward_irradiance * weight;
        total += weight;
    }
    if (total <= 0.000001) { return vec4f(0.0); }
    *seen = toward_luma / total;
    return vec4f(color / total, 1.0);
}

fn probe_local_fade(point: vec3f, local: ProbeLocal) -> f32 {
    let far = local.min_spacing.xyz + vec3f(local.dims.xyz - vec3u(1u)) * local.min_spacing.w;
    let inside = min(point - local.min_spacing.xyz, far - point);
    return clamp(min(inside.x, min(inside.y, inside.z)) / local.min_spacing.w, 0.0, 1.0);
}

fn sample_probe_anchor(position: vec3f, normal: vec3f, anchor: u32) -> vec3f {
    var unused = 0.0;
    return sample_probe_anchor_toward(position, normal, vec3f(0.0), anchor, &unused);
}

fn sample_probe_anchor_toward(position: vec3f, normal: vec3f, toward: vec3f, anchor: u32, seen: ptr<function, f32>) -> vec3f {
    let normal_length = length(normal);
    if (normal_length < 0.000001 || normal_length != normal_length || normal_length > 1e20 || any(position != position) || any(abs(position) > vec3f(1e20))) { return probe_grid.fallback.xyz; }
    let n = normal / normal_length;
    let point = position + n * 0.006;
    var local = vec4f(0.0);
    var local_seen = 0.0;
    var fade = 0.0;
    let count = min(u32(probe_grid.blend.w), 4u);
    for (var k = 0u; k < count; k++) {
        let inner = probe_local_fade(point, probe_grid.locals[k]);
        if (inner <= 0.0) { continue; }
        let sampled = sample_probe_volume(position, n, point, anchor, probe_grid.locals[k].min_spacing, vec4u(probe_grid.locals[k].dims.xyz, 2u), probe_grid.locals[k].dims.w, toward, &local_seen);
        if (sampled.w > 0.0) {
            local = sampled;
            fade = inner;
            break;
        }
    }
    if (fade >= 1.0) {
        *seen = local_seen;
        return local.xyz;
    }
    var main_seen = 0.0;
    let main = sample_probe_volume(position, n, point, anchor, probe_grid.min_spacing, probe_grid.dims, 0u, toward, &main_seen);
    if (main.w <= 0.0) {
        if (fade > 0.0) {
            *seen = local_seen;
            return local.xyz;
        }
        return probe_grid.fallback.xyz;
    }
    if (fade <= 0.0) {
        *seen = main_seen;
        return main.xyz;
    }
    *seen = mix(main_seen, local_seen, fade);
    return mix(main.xyz, local.xyz, fade);
}

fn probe_reflection_occlusion(grid: vec3f, reference: vec3f) -> f32 {
    let threshold = probe_grid.shade.x;
    if (threshold <= 0.0 || grid.x < 0.0) { return 1.0; }
    let open = dot(reference, vec3f(0.2126, 0.7152, 0.0722)) * threshold;
    if (!(open > 0.000001)) { return 1.0; }
    return clamp(dot(grid, vec3f(0.2126, 0.7152, 0.0722)) / open, 0.0, 1.0);
}

fn sample_live_irradiance(position: vec3f, normal: vec3f) -> vec3f {
    if (!use_probes || probe_grid.blend.y < 0.5) { return probe_grid.fallback.xyz; }
    let lower = sample_probe_anchor(position, normal, 0u);
    if (probe_grid.blend.x <= 0.0) { return lower; }
    let upper = sample_probe_anchor(position, normal, 1u);
    return mix(lower, upper, probe_grid.blend.x);
}

fn sample_live_irradiance_toward(position: vec3f, normal: vec3f, toward: vec3f, seen: ptr<function, f32>) -> vec3f {
    if (!use_probes || probe_grid.blend.y < 0.5) { return probe_grid.fallback.xyz; }
    var lower_seen = -1.0;
    let lower = sample_probe_anchor_toward(position, normal, toward, 0u, &lower_seen);
    if (probe_grid.blend.x <= 0.0) {
        *seen = lower_seen;
        return lower;
    }
    var upper_seen = -1.0;
    let upper = sample_probe_anchor_toward(position, normal, toward, 1u, &upper_seen);
    if (lower_seen >= 0.0 && upper_seen >= 0.0) {
        *seen = mix(lower_seen, upper_seen, probe_grid.blend.x);
    }
    return mix(lower, upper, probe_grid.blend.x);
}
"#;