17#import bevy_pbr::mesh_preprocess_types::{ 18 IndirectParametersCpuMetadata, IndirectParametersGpuMetadata, MeshInput 20#import bevy_pbr::mesh_types::{Mesh, MESH_FLAGS_NO_FRUSTUM_CULLING_BIT} 21#import bevy_pbr::mesh_view_bindings::view 22#import bevy_pbr::occlusion_culling 23#import bevy_pbr::prepass_bindings::previous_view_uniforms 24#import bevy_pbr::view_transformations::{ 25 position_world_to_ndc, position_world_to_view, ndc_to_uv, view_z_to_depth_ndc, 26 position_world_to_prev_ndc, position_world_to_prev_view, prev_view_z_to_depth_ndc 28#import bevy_render::maths 29#import bevy_render::view::View 34struct MeshCullingData { 37 aabb_center: vec4<f32>, 40 aabb_half_extents: vec4<f32>, 44struct PreprocessWorkItem { 51 output_or_indirect_parameters_index: u32, 56struct LatePreprocessWorkItemIndirectParameters { 60 dispatch_x: atomic<u32>, 66 work_item_count: atomic<u32>, 79 late_preprocess_work_item_indirect_offset: u32, 83@group(0) @binding(3) var<storage> current_input: array<MeshInput>; 85@group(0) @binding(4) var<storage> previous_input: array<MeshInput>; 89@group(0) @binding(5) var<storage> work_items: array<PreprocessWorkItem>; 91@group(0) @binding(6) var<storage, read_write> output: array<Mesh>; 95@group(0) @binding(7) var<storage> indirect_parameters_cpu_metadata: 96 array<IndirectParametersCpuMetadata>; 98@group(0) @binding(8) var<storage, read_write> indirect_parameters_gpu_metadata: 99 array<IndirectParametersGpuMetadata>; 102#ifdef FRUSTUM_CULLING 106@group(0) @binding(9) var<storage> mesh_culling_data: array<MeshCullingData>; 107#endif // FRUSTUM_CULLING 109#ifdef OCCLUSION_CULLING 110@group(0) @binding(10) var depth_pyramid: texture_2d<f32>; 113@group(0) @binding(11) var<storage, read_write> late_preprocess_work_items: 114 array<PreprocessWorkItem>; 117@group(0) @binding(12) var<storage, read_write> late_preprocess_work_item_indirect_parameters: 118 array<LatePreprocessWorkItemIndirectParameters>; 120var<push_constant> push_constants: PushConstants; 121#endif // OCCLUSION_CULLING 123#ifdef FRUSTUM_CULLING 127fn view_frustum_intersects_obb( 128 world_from_local: mat4x4<f32>, 129 aabb_center: vec4<f32>, 130 aabb_half_extents: vec3<f32>, 133 for (var i = 0; i < 5; i += 1) { 135 let plane_normal = view.frustum[i]; 136 let relative_radius = dot( 139 dot(plane_normal.xyz, world_from_local[0].xyz), 140 dot(plane_normal.xyz, world_from_local[1].xyz), 141 dot(plane_normal.xyz, world_from_local[2].xyz), 148 if (!maths::sphere_intersects_plane_half_space( 149 plane_normal, aabb_center, relative_radius)) { 160fn main(@builtin(global_invocation_id) global_invocation_id: vec3<u32>) { 163 let instance_index = global_invocation_id.x; 166 if (instance_index >= atomicLoad(&late_preprocess_work_item_indirect_parameters[ 167 push_constants.late_preprocess_work_item_indirect_offset].work_item_count)) { 171 if (instance_index >= arrayLength(&work_items)) { 177 let input_index = work_items[instance_index].input_index; 179 let indirect_parameters_index = work_items[instance_index].output_or_indirect_parameters_index; 186 if (instance_index == 0u) { 187 indirect_parameters_gpu_metadata[indirect_parameters_index].mesh_index = input_index; 188 } else if (work_items[instance_index - 1].output_or_indirect_parameters_index != indirect_parameters_index) { 189 indirect_parameters_gpu_metadata[indirect_parameters_index].mesh_index = input_index; 194 let mesh_output_index = work_items[instance_index].output_or_indirect_parameters_index; 198 let world_from_local_affine_transpose = current_input[input_index].world_from_local; 199 let world_from_local = maths::affine3_to_square(world_from_local_affine_transpose); 202#ifdef FRUSTUM_CULLING 203 if ((current_input[input_index].flags & MESH_FLAGS_NO_FRUSTUM_CULLING_BIT) == 0u) { 204 let aabb_center = mesh_culling_data[input_index].aabb_center.xyz; 205 let aabb_half_extents = mesh_culling_data[input_index].aabb_half_extents.xyz; 208 let model_center = world_from_local * vec4(aabb_center, 1.0); 209 if (!view_frustum_intersects_obb(world_from_local, model_center, aabb_half_extents)) { 220 let timestamp = current_input[input_index].timestamp; 221 let mesh_changed_this_frame = timestamp == view.frame_count; 224 let previous_input_index = current_input[input_index].previous_input_index; 225 var previous_world_from_local_affine_transpose: mat3x4<f32>; 226 if (mesh_changed_this_frame && previous_input_index != 0xffffffffu) { 227 previous_world_from_local_affine_transpose = 228 previous_input[previous_input_index].world_from_local; 230 previous_world_from_local_affine_transpose = world_from_local_affine_transpose; 232 let previous_world_from_local = 233 maths::affine3_to_square(previous_world_from_local_affine_transpose); 241#ifdef OCCLUSION_CULLING 242 let aabb_center = mesh_culling_data[input_index].aabb_center.xyz; 243 let aabb_half_extents = mesh_culling_data[input_index].aabb_half_extents.xyz; 246 let infinity = bitcast<f32>(0x7f800000u); 247 let neg_infinity = bitcast<f32>(0xff800000u); 248 var aabb = vec4(infinity, infinity, neg_infinity, neg_infinity); 249 var max_depth_view = neg_infinity; 253 for (var i = 0u; i < 8u; i += 1u) { 254 let local_pos = aabb_center + select( 257 vec3((i & 1) != 0, (i & 2) != 0, (i & 4) != 0) 258 ) * aabb_half_extents; 263 let prev_world_pos = (previous_world_from_local * vec4(local_pos, 1.0)).xyz; 264 let view_pos = position_world_to_prev_view(prev_world_pos); 265 let ndc_pos = position_world_to_prev_ndc(prev_world_pos); 269 let world_pos = (world_from_local * vec4(local_pos, 1.0)).xyz; 270 let view_pos = position_world_to_view(world_pos); 271 let ndc_pos = position_world_to_ndc(world_pos); 274 let uv_pos = ndc_to_uv(ndc_pos.xy); 277 aabb = vec4(min(aabb.xy, uv_pos), max(aabb.zw, uv_pos)); 278 max_depth_view = max(max_depth_view, view_pos.z); 283 max_depth_view = min(-previous_view_uniforms.clip_from_view[3][2], max_depth_view); 285 max_depth_view = min(-view.clip_from_view[3][2], max_depth_view); 290 let aabb_pixel_size = occlusion_culling::get_aabb_size_in_pixels(aabb, depth_pyramid); 291 let occluder_depth_ndc = 292 occlusion_culling::get_occluder_depth(aabb, aabb_pixel_size, depth_pyramid); 295 let max_depth_ndc = prev_view_z_to_depth_ndc(max_depth_view); 297 let max_depth_ndc = view_z_to_depth_ndc(max_depth_view); 301 if (max_depth_ndc < occluder_depth_ndc) { 307 let output_work_item_index = atomicAdd(&late_preprocess_work_item_indirect_parameters[ 308 push_constants.late_preprocess_work_item_indirect_offset].work_item_count, 1u); 309 if (output_work_item_index % 64u == 0u) { 314 atomicAdd(&late_preprocess_work_item_indirect_parameters[ 315 push_constants.late_preprocess_work_item_indirect_offset].dispatch_x, 1u); 319 late_preprocess_work_items[output_work_item_index].input_index = input_index; 320 late_preprocess_work_items[output_work_item_index].output_or_indirect_parameters_index = 321 indirect_parameters_index; 326#endif // OCCLUSION_CULLING 329 let local_from_world_transpose = transpose(maths::inverse_affine3(transpose( 330 world_from_local_affine_transpose))); 333 let local_from_world_transpose_a = mat2x4<f32>( 334 vec4<f32>(local_from_world_transpose[0].xyz, local_from_world_transpose[1].x), 335 vec4<f32>(local_from_world_transpose[1].yz, local_from_world_transpose[2].xy)); 336 let local_from_world_transpose_b = local_from_world_transpose[2].z; 344 let batch_output_index = atomicLoad( 345 &indirect_parameters_gpu_metadata[indirect_parameters_index].early_instance_count 347 &indirect_parameters_gpu_metadata[indirect_parameters_index].late_instance_count, 351 let batch_output_index = atomicAdd( 352 &indirect_parameters_gpu_metadata[indirect_parameters_index].early_instance_count, 357 let mesh_output_index = 358 indirect_parameters_cpu_metadata[indirect_parameters_index].base_output_index + 364 output[mesh_output_index].world_from_local = world_from_local_affine_transpose; 365 output[mesh_output_index].previous_world_from_local = 366 previous_world_from_local_affine_transpose; 367 output[mesh_output_index].local_from_world_transpose_a = local_from_world_transpose_a; 368 output[mesh_output_index].local_from_world_transpose_b = local_from_world_transpose_b; 369 output[mesh_output_index].flags = current_input[input_index].flags; 370 output[mesh_output_index].lightmap_uv_rect = current_input[input_index].lightmap_uv_rect; 371 output[mesh_output_index].first_vertex_index = current_input[input_index].first_vertex_index; 372 output[mesh_output_index].current_skin_index = current_input[input_index].current_skin_index; 373 output[mesh_output_index].material_and_lightmap_bind_group_slot = 374 current_input[input_index].material_and_lightmap_bind_group_slot; 375 output[mesh_output_index].tag = current_input[input_index].tag;