3#define_import_path bevy_solari::world_cache 5#import bevy_pbr::utils::{rand_f, rand_vec2f} 6#import bevy_render::maths::orthonormalize 7#import bevy_solari::realtime_bindings::{ 11 world_cache_geometry_data, 12 world_cache_luminance_deltas, 15 world_cache_active_cell_indices, 16 world_cache_active_cells_count, 17 WorldCacheGeometryData, 21const WORLD_CACHE_MAX_TEMPORAL_SAMPLES: f32 = 32.0; 23const WORLD_CACHE_DIRECT_LIGHT_SAMPLE_COUNT: u32 = 32u; 25const WORLD_CACHE_MAX_GI_RAY_DISTANCE: f32 = 50.0; 27const WORLD_CACHE_CELL_UPDATES_SOFT_CAP: u32 = 40000u; 30const WORLD_CACHE_CELL_LIFETIME: u32 = 10u; 32const WORLD_CACHE_MAX_SEARCH_STEPS: u32 = 3u; 35const WORLD_CACHE_POSITION_BASE_CELL_SIZE: f32 = 0.15; 37const WORLD_CACHE_POSITION_LOD_SCALE: f32 = 15.0; 40const WORLD_CACHE_EMPTY_CELL: u32 = 0u; 42#ifndef WORLD_CACHE_NON_ATOMIC_LIFE_BUFFER 43fn query_world_cache(world_position_in: vec3<f32>, world_normal: vec3<f32>, view_position: vec3<f32>, ray_t: f32, cell_lifetime: u32, rng: ptr<function, u32>) -> vec3<f32> { 44 var world_position = world_position_in; 45 var cell_size = get_cell_size(world_position, view_position, rng); 47#ifdef WORLD_CACHE_FIRST_BOUNCE_LIGHT_LEAK_PREVENTION 48 if ray_t < cell_size { 50 cell_size = WORLD_CACHE_POSITION_BASE_CELL_SIZE; 54#ifndef NO_JITTER_WORLD_CACHE 57 let TBN = orthonormalize(world_normal); 58 let offset = (rand_vec2f(rng) * 2.0 - 1.0) * cell_size * 0.5; 59 world_position += offset.x * TBN[0] + offset.y * TBN[1]; 60 cell_size = get_cell_size(world_position, view_position, rng); 63 let world_position_quantized = bitcast<vec3<u32>>(quantize_position(world_position, cell_size)); 64 let world_normal_quantized = bitcast<vec3<u32>>(quantize_normal(world_normal)); 65 var key = compute_key(world_position_quantized, world_normal_quantized); 66 let checksum = compute_checksum(world_position_quantized, world_normal_quantized); 68 for (var i = 0u; i < WORLD_CACHE_MAX_SEARCH_STEPS; i++) { 69 let existing_checksum = atomicCompareExchangeWeak(&world_cache_checksums[key], WORLD_CACHE_EMPTY_CELL, checksum).old_value; 72 if existing_checksum == checksum || existing_checksum == WORLD_CACHE_EMPTY_CELL { 73#ifndef WORLD_CACHE_QUERY_ATOMIC_MAX_LIFETIME 74 atomicStore(&world_cache_life[key], cell_lifetime); 76 atomicMax(&world_cache_life[key], cell_lifetime); 80 if existing_checksum == checksum { 82 return world_cache_radiance[key].rgb; 83 } else if existing_checksum == WORLD_CACHE_EMPTY_CELL { 85 world_cache_geometry_data[key].world_position = world_position; 86 world_cache_geometry_data[key].world_normal = world_normal; 98fn get_cell_size(world_position: vec3<f32>, view_position: vec3<f32>, rng: ptr<function, u32>) -> f32 { 99 let camera_distance = distance(view_position, world_position) / WORLD_CACHE_POSITION_LOD_SCALE; 100 let lod_f = log2(1.0 + camera_distance); 101 let lod_fract = fract(lod_f); 102 let lod = floor(lod_f) + select(0.0, 1.0, rand_f(rng) < lod_fract * lod_fract * lod_fract); 103 return WORLD_CACHE_POSITION_BASE_CELL_SIZE * exp2(lod); 106fn quantize_position(world_position: vec3<f32>, quantization_factor: f32) -> vec3<f32> { 107 return floor(world_position / quantization_factor + 0.0001); 110fn quantize_normal(world_normal: vec3<f32>) -> vec3<f32> { 111 return floor(world_normal * 2.0 + 0.0001); 115fn compute_key(world_position: vec3<u32>, world_normal: vec3<u32>) -> u32 { 116 var key = pcg_hash(world_position.x); 117 key = pcg_hash(key + world_position.y); 118 key = pcg_hash(key + world_position.z); 119 key = pcg_hash(key + world_normal.x); 120 key = pcg_hash(key + world_normal.y); 121 key = pcg_hash(key + world_normal.z); 122 return wrap_key(key); 125fn compute_checksum(world_position: vec3<u32>, world_normal: vec3<u32>) -> u32 { 126 var key = iqint_hash(world_position.x); 127 key = iqint_hash(key + world_position.y); 128 key = iqint_hash(key + world_position.z); 129 key = iqint_hash(key + world_normal.x); 130 key = iqint_hash(key + world_normal.y); 131 key = iqint_hash(key + world_normal.z); 135fn pcg_hash(input: u32) -> u32 { 136 let state = input * 747796405u + 2891336453u; 137 let word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; 138 return (word >> 22u) ^ word; 141fn iqint_hash(input: u32) -> u32 { 142 let n = (input << 13u) ^ input; 143 return n * (n * n * 15731u + 789221u) + 1376312589u; 146fn wrap_key(key: u32) -> u32 { 147 return key & (#{WORLD_CACHE_SIZE} - 1u);