lambent 0.1.0

A ray / path tracer built on wgpu.
Documentation
import package::bindings::{ Reservoir, WorldMarcovChainState, };
import package::importance_sampling::shared::{ unpack_confidance, pack_confidance };

@group(0) @binding(0)
var<storage, read_write> eof_gi_reservoirs: array<Reservoir>;

override CONFIDENCE_CAP = 30u;

var<push_constant> offset: u32;

@compute
@workgroup_size(256, 1, 1)
fn process_gi_reservoirs(@builtin(global_invocation_id) id: vec3<u32>) {
    if (id.x + offset) >= arrayLength(&eof_gi_reservoirs) {
        return;
    }
    var reservoir = eof_gi_reservoirs[id.x + offset];
    // clamp reservoir max while also recalculating the reservoir.w
    var confidance_valid = unpack_confidance(reservoir.packed_confidance_valid);
    if confidance_valid.confidance > CONFIDENCE_CAP {
        let new_confidance = CONFIDENCE_CAP;
        let confidance_mutiplier = f32(CONFIDENCE_CAP) / f32(confidance_valid.confidance);
        confidance_valid.confidance = new_confidance;
        reservoir.w *= confidance_mutiplier;
        reservoir.packed_confidance_valid = pack_confidance(confidance_valid);
        eof_gi_reservoirs[id.x + offset] = reservoir;
    }
}

@group(0) @binding(1)
var<storage, read_write> eof_world_markov_chains: array<WorldMarcovChainState>;

fn div_ceil(num: u32, denom: u32) -> u32 {
    let divided = num / denom;
    let remainder = num % denom;
    if remainder != 0 {
        return divided + 1;
    } else {
        return divided;
    }
}

override SAMPLE_MULTIPLIER = 8u;
override SAMPLE_DIVISOR = 9u;

override SAM_MUL = min(SAMPLE_MULTIPLIER, SAMPLE_DIVISOR);

fn correct_radiance(idx: u32) {
    // Lower the number of samples in the radiance cache (maintaining the same radiance)
    // Note: we don't have to worry about locking because each invocation should only modify its own chain.
    let old_num_samples = atomicLoad(&eof_world_markov_chains[idx].num_samples);

    if old_num_samples == 0u {
        return;
    }

    let new_num_samples = div_ceil(old_num_samples * SAM_MUL, SAMPLE_DIVISOR);
    let radiance_multiplier = f32(new_num_samples) / f32(old_num_samples);

    // Correct radiance to account for less samples.
    let new_luminance_x = bitcast<f32>(atomicLoad(&eof_world_markov_chains[idx].luminance[0])) * radiance_multiplier;
    atomicStore(&eof_world_markov_chains[idx].luminance[0], bitcast<u32>(new_luminance_x));
    let new_luminance_y = bitcast<f32>(atomicLoad(&eof_world_markov_chains[idx].luminance[1])) * radiance_multiplier;
    atomicStore(&eof_world_markov_chains[idx].luminance[1], bitcast<u32>(new_luminance_y));
    let new_luminance_z = bitcast<f32>(atomicLoad(&eof_world_markov_chains[idx].luminance[2])) * radiance_multiplier;
    atomicStore(&eof_world_markov_chains[idx].luminance[2], bitcast<u32>(new_luminance_z));
    atomicStore(&eof_world_markov_chains[idx].num_samples, new_num_samples);
}

@compute
@workgroup_size(256, 1, 1)
fn process_world_markov_chains(@builtin(global_invocation_id) id: vec3<u32>) {
    let idx = id.x + offset;

    if idx >= arrayLength(&eof_world_markov_chains) {
        return;
    }

    if (eof_world_markov_chains[idx].timeout) == 0 {
        // reset the radiance cache, but since the markov chain is stored each time, instead of updated, we don't need to reset it.
        atomicStore(&eof_world_markov_chains[idx].secondary_hash, 0);
        atomicStore(&eof_world_markov_chains[idx].num_samples, 0);
        atomicStore(&eof_world_markov_chains[idx].luminance[0], 0);
        atomicStore(&eof_world_markov_chains[idx].luminance[1], 0);
        atomicStore(&eof_world_markov_chains[idx].luminance[2], 0);
        atomicStore(&eof_world_markov_chains[idx].lock, 0);
        return;
    }

    // Lower the number of samples in the radiance cache (maintaining same radiance) as well as in the markov chain.
    correct_radiance(idx);

    //let new_chain_num_samples = div_ceil(atomicLoad(&eof_world_markov_chains[idx].chain.num_samples) * SAM_MUL, SAMPLE_DIVISOR);
    //atomicStore(&eof_world_markov_chains[idx].chain.num_samples, new_chain_num_samples);
    eof_world_markov_chains[idx].timeout--;
}