lambent 0.1.0

A ray / path tracer built on wgpu.
Documentation
override SAMPLES = 5u;

struct MarcovChainState {
    light_source: vec3<f32>,
    mean_cosine: f32,
    weight_sum: f32,
    num_samples: u32,
    score: f32,
}

struct AtomicMarcovChainState {
    light_source: array<atomic<u32>, 3>,
    mean_cosine: atomic<u32>,
    weight_sum: atomic<u32>,
    num_samples: atomic<u32>,
    score: atomic<u32>,
}

// To overflow a f32 with this many samples would require an average (not peak) brightness of 
// > 1,267,650,530,739,316,831,303,078,052,785.5 (~1 nonillion), at that point, there is probably
// a bug somewhere else that we should be worrying about.
//
// Note: at this point, f32 will be off by up to 8 when casting, due to a step size of 16. The
// error is about 0.000006%. This is probably unnoticable.
const MAX_NUM_SAMPLES: u32 = 0xFFFFFFF;
//const MAX_NUM_SAMPLES: u32 = 2;

const STATE_LOCKED: u32 = 1;
const STATE_UNLOCKED: u32 = 0;

const INVALID_KEY: u32 = 0;

struct WorldMarcovChainState {
    secondary_hash: atomic<u32>,
    num_samples: atomic<u32>,
    luminance: array<atomic<u32>, 3>,
    lock: atomic<u32>,
    chain: AtomicMarcovChainState,
    timeout: u32,
}

struct Camera {
    // this way we can have any fov easily.
    projection_inverse: mat4x4<f32>,
    view_inverse: mat4x4<f32>,
}

struct Material {
    tex_pos_1: u32,
    tex_pos_2: u32,
    tex_pos_3: u32,
    tex_pos_recolour: u32,
    tex_idx_diffuse_emission: u32,
    tex_idx_attributes_ty: u32,
    emission_scale: f32,
    refractive_index: u32,
}

struct MaterialsIdx {
    materials: array<u32>,
}

struct CompressedInfo {
    arr: array<f32, 9>,
}

@group(0) @binding(0)
var<storage> materials: array<Material>;
@group(0) @binding(1)
var<storage> material_idx: binding_array<MaterialsIdx>;

@if(vertex_return)
@group(0) @binding(2)
var acc_struct: acceleration_structure<vertex_return>;

@if(vertex_return)
alias ray_query_maybe_vertex_return = ray_query<vertex_return>;

@if(!vertex_return)
@group(0) @binding(2)
var acc_struct: acceleration_structure;

@if(!vertex_return)
struct Vertices {
    geometry_stride: vec4<u32>,
    vertices: array<vec3<f32>>,
}

@if(!vertex_return)
@group(0) @binding(3)
var<storage> vertices: binding_array<Vertices>;

@if(!vertex_return)
struct Indices {
    indices: array<u32>,
}

@if(!vertex_return)
@group(0) @binding(4)
var<storage> indices: binding_array<Indices>;

@if(!vertex_return)
fn get_vertices(intersection: RayIntersection) -> array<vec3<f32>, 3> {
    let instance_idx = intersection.instance_index;
    let vertex_index = (vertices[instance_idx].geometry_stride.x * intersection.geometry_index) + (intersection.primitive_index * 3);
    let index_1 = select(indices[instance_idx].indices[vertex_index], vertex_index, arrayLength(&indices[instance_idx].indices) == 1);
    let index_2 = select(indices[instance_idx].indices[vertex_index + 1], vertex_index + 1, arrayLength(&indices[instance_idx].indices) == 1);
    let index_3 = select(indices[instance_idx].indices[vertex_index + 2], vertex_index + 2, arrayLength(&indices[instance_idx].indices) == 1);
    return array<vec3<f32>, 3>(vertices[instance_idx].vertices[index_1], vertices[instance_idx].vertices[index_2], vertices[instance_idx].vertices[index_3]);
}

@if(!vertex_return)
alias ray_query_maybe_vertex_return = ray_query;

@group(1) @binding(0)
var<uniform> camera: Camera;
@group(1) @binding(1)
var output: texture_storage_2d<rgba32float, write>;
@group(1) @binding(2)
var output_normal: texture_storage_2d<rgba32float, write>;
@group(1) @binding(3)
var output_albedo: texture_storage_2d<rgba32float, write>;
@group(1) @binding(4)
var bg: texture_cube<f32>;
@group(1) @binding(5)
var<storage, read_write> gi_reservoirs: array<Reservoir>;
@group(1) @binding(6)
var<storage> old_gi_reservoirs: array<Reservoir>;
@group(1) @binding(7)
var<storage, read_write> info: array<CompressedInfo>;
@group(1) @binding(8)
var<storage, read_write> markov_chains: array<MarcovChainState>;
@group(1) @binding(9)
var<storage> old_markov_chains: array<MarcovChainState>;
@group(1) @binding(10)
var<storage, read_write> world_markov_chains: array<WorldMarcovChainState>;
@group(1) @binding(11)
var<storage> old_world_markov_chains: array<WorldMarcovChainState>;

@group(2) @binding(0)
var sam:sampler;
@group(2) @binding(1)
var tex_diffuse: binding_array<texture_2d<f32>>;
@group(2) @binding(2)
var tex_emission: binding_array<texture_2d<f32>>;
@group(2) @binding(3)
// r: roughness
var tex_attributes: binding_array<texture_2d<f32>>;
@group(2) @binding(4)
var tex_recolour: texture_2d<f32>;

fn unpack_2xu16(u:u32) -> vec2<u32> {
    let u1 = u & 0xFFFFu;
    let u2 = (u & 0xFFFF0000u) >> 16u;
    return vec2<u32>(u1, u2);
}

struct Reservoir {
    visible_point: vec3<f32>,   // 0 16 12
    visible_normal: u32,        // 12 4 4
    sample_point: vec3<f32>,    // 16 16 12
    sample_normal: u32,         // 28 4 4
    out_radiance: vec3<f32>,    // 32 16 12
    ty: u32,                    // 44 4 4
    roughness: f32,             // 48 4 4
    pdf:f32,                    // 52 4 4
    w: f32,                     // 56 4 4
    packed_confidance_valid: u32,    // 60 4 4
    W: f32,                     // 64 4 4
}