1#import bevy_pbr::meshlet_bindings::{ 4 meshlet_view_instance_visibility, 5 meshlet_instance_aabbs, 6 meshlet_instance_bvh_root_nodes, 7 meshlet_bvh_cull_count_write, 8 meshlet_bvh_cull_dispatch, 9 meshlet_bvh_cull_queue, 10 meshlet_second_pass_instance_count, 11 meshlet_second_pass_instance_dispatch, 12 meshlet_second_pass_instance_candidates, 14#import bevy_pbr::meshlet_cull_shared::{ 16 should_occlusion_cull_aabb, 19fn instance_count() -> u32 { 20#ifdef MESHLET_FIRST_CULLING_PASS 21 return constants.scene_instance_count; 23 return meshlet_second_pass_instance_count; 27fn map_instance_id(id: u32) -> u32 { 28#ifdef MESHLET_FIRST_CULLING_PASS 31 return meshlet_second_pass_instance_candidates[id]; 35fn should_cull_instance(instance_id: u32) -> bool { 36 let index = instance_id >> 5u; 37 let bit_offset = instance_id & 31u; 38 let packed_visibility = meshlet_view_instance_visibility[index]; 39 return bool(extractBits(packed_visibility, bit_offset, 1u)); 43@workgroup_size(128, 1, 1) 44fn cull_instances(@builtin(global_invocation_id) global_invocation_id: vec3<u32>) { 46 let dispatch_id = global_invocation_id.x; 47 if dispatch_id >= instance_count() { return; } 49 let instance_id = map_instance_id(dispatch_id); 50 let aabb = meshlet_instance_aabbs[instance_id]; 53#ifdef MESHLET_FIRST_CULLING_PASS 54 if should_cull_instance(instance_id) || !aabb_in_frustum(aabb, instance_id) { return; } 59 if should_occlusion_cull_aabb(aabb, instance_id) { 60#ifdef MESHLET_FIRST_CULLING_PASS 61 let id = atomicAdd(&meshlet_second_pass_instance_count, 1u); 62 meshlet_second_pass_instance_candidates[id] = instance_id; 63 if ((id & 127u) == 0u) { 64 atomicAdd(&meshlet_second_pass_instance_dispatch.x, 1u); 71 let root_node = meshlet_instance_bvh_root_nodes[instance_id]; 72 let id = atomicAdd(&meshlet_bvh_cull_count_write, 1u); 73 meshlet_bvh_cull_queue[id] = InstancedOffset(instance_id, root_node); 74 if ((id & 15u) == 0u) { 75 atomicAdd(&meshlet_bvh_cull_dispatch.x, 1u);