1#define_import_path bevy_pbr::mesh_functions3#import bevy_pbr::{4 mesh_view_bindings::{5 view,6 visibility_ranges,7 VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE8 },9 mesh_bindings::mesh,10 mesh_types::MESH_FLAGS_SIGN_DETERMINANT_MODEL_3X3_BIT,11 view_transformations::position_world_to_clip,12}13#import bevy_render::maths::{affine3_to_square, mat2x4_f32_to_mat3x3_unpack}16fn get_world_from_local(instance_index: u32) -> mat4x4<f32> {17 return affine3_to_square(mesh[instance_index].world_from_local);18}20fn get_previous_world_from_local(instance_index: u32) -> mat4x4<f32> {21 return affine3_to_square(mesh[instance_index].previous_world_from_local);22}24fn mesh_position_local_to_world(world_from_local: mat4x4<f32>, vertex_position: vec4<f32>) -> vec4<f32> {25 return world_from_local * vertex_position;26}28// NOTE: The intermediate world_position assignment is important29// for precision purposes when using the 'equals' depth comparison30// function.31fn mesh_position_local_to_clip(world_from_local: mat4x4<f32>, vertex_position: vec4<f32>) -> vec4<f32> {32 let world_position = mesh_position_local_to_world(world_from_local, vertex_position);33 return position_world_to_clip(world_position.xyz);34}36fn mesh_normal_local_to_world(vertex_normal: vec3<f32>, instance_index: u32) -> vec3<f32> {37 // NOTE: The mikktspace method of normal mapping requires that the world normal is38 // re-normalized in the vertex shader to match the way mikktspace bakes vertex tangents39 // and normal maps so that the exact inverse process is applied when shading. Blender, Unity,40 // Unreal Engine, Godot, and more all use the mikktspace method.41 // We only skip normalization for invalid normals so that they don't become NaN.42 // Do not change this code unless you really know what you are doing.43 // http://www.mikktspace.com/44 if any(vertex_normal != vec3<f32>(0.0)) {45 return normalize(46 mat2x4_f32_to_mat3x3_unpack(47 mesh[instance_index].local_from_world_transpose_a,48 mesh[instance_index].local_from_world_transpose_b,49 ) * vertex_normal50 );51 } else {52 return vertex_normal;53 }54}56// Calculates the sign of the determinant of the 3x3 model matrix based on a57// mesh flag58fn sign_determinant_model_3x3m(mesh_flags: u32) -> f32 {59 // bool(u32) is false if 0u else true60 // f32(bool) is 1.0 if true else 0.061 // * 2.0 - 1.0 remaps 0.0 or 1.0 to -1.0 or 1.0 respectively62 return f32(bool(mesh_flags & MESH_FLAGS_SIGN_DETERMINANT_MODEL_3X3_BIT)) * 2.0 - 1.0;63}65fn mesh_tangent_local_to_world(world_from_local: mat4x4<f32>, vertex_tangent: vec4<f32>, instance_index: u32) -> vec4<f32> {66 // NOTE: The mikktspace method of normal mapping requires that the world tangent is67 // re-normalized in the vertex shader to match the way mikktspace bakes vertex tangents68 // and normal maps so that the exact inverse process is applied when shading. Blender, Unity,69 // Unreal Engine, Godot, and more all use the mikktspace method.70 // We only skip normalization for invalid tangents so that they don't become NaN.71 // Do not change this code unless you really know what you are doing.72 // http://www.mikktspace.com/73 if any(vertex_tangent != vec4<f32>(0.0)) {74 return vec4<f32>(75 normalize(76 mat3x3<f32>(77 world_from_local[0].xyz,78 world_from_local[1].xyz,79 world_from_local[2].xyz,80 ) * vertex_tangent.xyz81 ),82 // NOTE: Multiplying by the sign of the determinant of the 3x3 model matrix accounts for83 // situations such as negative scaling.84 vertex_tangent.w * sign_determinant_model_3x3m(mesh[instance_index].flags)85 );86 } else {87 return vertex_tangent;88 }89}91// Returns an appropriate dither level for the current mesh instance.92//93// This looks up the LOD range in the `visibility_ranges` table and compares the94// camera distance to determine the dithering level.95#ifdef VISIBILITY_RANGE_DITHER96fn get_visibility_range_dither_level(instance_index: u32, world_position: vec4<f32>) -> i32 {97#if AVAILABLE_STORAGE_BUFFER_BINDINGS >= 698 // If we're using a storage buffer, then the length is variable.99 let visibility_buffer_array_len = arrayLength(&visibility_ranges);100#else // AVAILABLE_STORAGE_BUFFER_BINDINGS >= 6101 // If we're using a uniform buffer, then the length is constant102 let visibility_buffer_array_len = VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE;103#endif // AVAILABLE_STORAGE_BUFFER_BINDINGS >= 6105 let visibility_buffer_index = mesh[instance_index].flags & 0xffffu;106 if (visibility_buffer_index > visibility_buffer_array_len) {107 return -16;108 }110 let lod_range = visibility_ranges[visibility_buffer_index];111 let camera_distance = length(view.world_position.xyz - world_position.xyz);113 // This encodes the following mapping:114 //115 // `lod_range.` x y z w camera distance116 // ←───────┼────────┼────────┼────────┼────────→117 // LOD level -16 -16 0 0 16 16 LOD level118 let offset = select(-16, 0, camera_distance >= lod_range.z);119 let bounds = select(lod_range.xy, lod_range.zw, camera_distance >= lod_range.z);120 let level = i32(round((camera_distance - bounds.x) / (bounds.y - bounds.x) * 16.0));121 return offset + clamp(level, 0, 16);122}123#endif