Search across packages, versions, files, declarations, and comments. Use multiple terms to narrow results (AND), and add @vertex, @fragment, or @compute to filter by shader stage.
1#define_import_path bevy_pbr::mesh_functions
3#import bevy_pbr::{
4 mesh_view_bindings::{
5 view,
6 visibility_ranges,
7 VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE
8 },
9 mesh_bindings::mesh,
10 mesh_types::MESH_FLAGS_SIGN_DETERMINANT_MODEL_3X3_BIT,
11 view_transformations::position_world_to_clip,
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);
20fn get_previous_world_from_local(instance_index: u32) -> mat4x4<f32> {
21 return affine3_to_square(mesh[instance_index].previous_world_from_local);
24fn mesh_position_local_to_world(world_from_local: mat4x4<f32>, vertex_position: vec4<f32>) -> vec4<f32> {
25 return world_from_local * vertex_position;
28// NOTE: The intermediate world_position assignment is important
29// for precision purposes when using the 'equals' depth comparison
30// 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);
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 is
38 // re-normalized in the vertex shader to match the way mikktspace bakes vertex tangents
39 // 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_normal
50 );
51 } else {
52 return vertex_normal;
53 }
56// Calculates the sign of the determinant of the 3x3 model matrix based on a
57// mesh flag
58fn sign_determinant_model_3x3m(mesh_flags: u32) -> f32 {
59 // bool(u32) is false if 0u else true
60 // f32(bool) is 1.0 if true else 0.0
61 // * 2.0 - 1.0 remaps 0.0 or 1.0 to -1.0 or 1.0 respectively
62 return f32(bool(mesh_flags & MESH_FLAGS_SIGN_DETERMINANT_MODEL_3X3_BIT)) * 2.0 - 1.0;
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 is
67 // re-normalized in the vertex shader to match the way mikktspace bakes vertex tangents
68 // 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.xyz
81 ),
82 // NOTE: Multiplying by the sign of the determinant of the 3x3 model matrix accounts for
83 // 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 }
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 the
94// camera distance to determine the dithering level.
95#ifdef VISIBILITY_RANGE_DITHER
96fn get_visibility_range_dither_level(instance_index: u32, world_position: vec4<f32>) -> i32 {
97#if AVAILABLE_STORAGE_BUFFER_BINDINGS >= 6
98 // 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 >= 6
101 // If we're using a uniform buffer, then the length is constant
102 let visibility_buffer_array_len = VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE;
103#endif // AVAILABLE_STORAGE_BUFFER_BINDINGS >= 6
105 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 distance
116 // ←───────┼────────┼────────┼────────┼────────→
117 // LOD level -16 -16 0 0 16 16 LOD level
118 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);
123#endif
Contents