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.
1import package::render::{
2 mesh_view_bindings::{
3 view,
4 visibility_ranges,
5 VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE
6 },
7 mesh_bindings::{mesh, metadata},
8 mesh_types::{MESH_FLAGS_SIGN_DETERMINANT_MODEL_3X3_BIT},
9 view_transformations::position_world_to_clip,
10};
11import bevy_render::maths::{affine3_to_square, mat2x4_f32_to_mat3x3_unpack};
12import bevy_render::mesh::metadata_types::MeshMetadata;
14@if(!MESHLET_MESH_MATERIAL_PASS)
15fn get_world_from_local(instance_index: u32) -> mat4x4<f32> {
16 return affine3_to_square(mesh[instance_index].world_from_local);
19@if(!MESHLET_MESH_MATERIAL_PASS)
20fn get_previous_world_from_local(instance_index: u32) -> mat4x4<f32> {
21 return affine3_to_square(mesh[instance_index].previous_world_from_local);
24@if(!MESHLET_MESH_MATERIAL_PASS)
25fn get_local_from_world(instance_index: u32) -> mat4x4<f32> {
26 // the model matrix is translation * rotation * scale
27 // the inverse is then scale^-1 * rotation ^-1 * translation^-1
28 // the 3x3 matrix only contains the information for the rotation and scale
29 let inverse_model_3x3 = transpose(mat2x4_f32_to_mat3x3_unpack(
30 mesh[instance_index].local_from_world_transpose_a,
31 mesh[instance_index].local_from_world_transpose_b,
32 ));
33 // construct scale^-1 * rotation^-1 from the 3x3
34 let inverse_model_4x4_no_trans = mat4x4<f32>(
35 vec4(inverse_model_3x3[0], 0.0),
36 vec4(inverse_model_3x3[1], 0.0),
37 vec4(inverse_model_3x3[2], 0.0),
38 vec4(0.0,0.0,0.0,1.0)
39 );
40 // we can get translation^-1 by negating the translation of the model
41 let model = get_world_from_local(instance_index);
42 let inverse_model_4x4_only_trans = mat4x4<f32>(
43 vec4(1.0,0.0,0.0,0.0),
44 vec4(0.0,1.0,0.0,0.0),
45 vec4(0.0,0.0,1.0,0.0),
46 vec4(-model[3].xyz, 1.0)
47 );
49 return inverse_model_4x4_no_trans * inverse_model_4x4_only_trans;
52fn mesh_position_local_to_world(world_from_local: mat4x4<f32>, vertex_position: vec4<f32>) -> vec4<f32> {
53 return world_from_local * vertex_position;
56/// NOTE: The intermediate world_position assignment is important
57/// for precision purposes when using the 'equals' depth comparison
58/// function.
59fn mesh_position_local_to_clip(world_from_local: mat4x4<f32>, vertex_position: vec4<f32>) -> vec4<f32> {
60 let world_position = mesh_position_local_to_world(world_from_local, vertex_position);
61 return position_world_to_clip(world_position.xyz);
64@if(!MESHLET_MESH_MATERIAL_PASS)
65fn mesh_normal_local_to_world(vertex_normal: vec3<f32>, instance_index: u32) -> vec3<f32> {
66 // NOTE: The mikktspace method of normal mapping requires that the world normal 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 normals 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_normal != vec3<f32>(0.0)) {
74 return normalize(
75 mat2x4_f32_to_mat3x3_unpack(
76 mesh[instance_index].local_from_world_transpose_a,
77 mesh[instance_index].local_from_world_transpose_b,
78 ) * vertex_normal
79 );
80 } else {
81 return vertex_normal;
82 }
85/// Calculates the sign of the determinant of the 3x3 model matrix based on a
86/// mesh flag
87fn sign_determinant_model_3x3m(mesh_flags: u32) -> f32 {
88 // bool(u32) is false if 0u else true
89 // f32(bool) is 1.0 if true else 0.0
90 // * 2.0 - 1.0 remaps 0.0 or 1.0 to -1.0 or 1.0 respectively
91 return f32(bool(mesh_flags & MESH_FLAGS_SIGN_DETERMINANT_MODEL_3X3_BIT)) * 2.0 - 1.0;
94@if(!MESHLET_MESH_MATERIAL_PASS)
95fn mesh_tangent_local_to_world(world_from_local: mat4x4<f32>, vertex_tangent: vec4<f32>, instance_index: u32) -> vec4<f32> {
96 // NOTE: The mikktspace method of normal mapping requires that the world tangent is
97 // re-normalized in the vertex shader to match the way mikktspace bakes vertex tangents
98 // and normal maps so that the exact inverse process is applied when shading. Blender, Unity,
99 // Unreal Engine, Godot, and more all use the mikktspace method.
100 // We only skip normalization for invalid tangents so that they don't become NaN.
101 // Do not change this code unless you really know what you are doing.
102 // http://www.mikktspace.com/
103 if any(vertex_tangent != vec4<f32>(0.0)) {
104 return vec4<f32>(
105 normalize(
106 mat3x3<f32>(
107 world_from_local[0].xyz,
108 world_from_local[1].xyz,
109 world_from_local[2].xyz,
110 ) * vertex_tangent.xyz
111 ),
112 // NOTE: Multiplying by the sign of the determinant of the 3x3 model matrix accounts for
113 // situations such as negative scaling.
114 vertex_tangent.w * sign_determinant_model_3x3m(mesh[instance_index].flags)
115 );
116 } else {
117 return vertex_tangent;
118 }
121/// Returns an appropriate dither level for the current mesh instance.
122///
123/// This looks up the LOD range in the `visibility_ranges` table and compares the
124/// camera distance to determine the dithering level.
125@if(VISIBILITY_RANGE_DITHER)
126fn get_visibility_range_dither_level(instance_index: u32, world_position: vec4<f32>) -> i32 {
127@if(AVAILABLE_STORAGE_BUFFER_BINDINGS__GE_6)
128 // If we're using a storage buffer, then the length is variable.
129 let visibility_buffer_array_len = arrayLength(&visibility_ranges);
130@else // AVAILABLE_STORAGE_BUFFER_BINDINGS >= 6
131 // If we're using a uniform buffer, then the length is constant
132 let visibility_buffer_array_len = VISIBILITY_RANGE_UNIFORM_BUFFER_SIZE;
134 let visibility_buffer_index = mesh[instance_index].flags & 0xffffu;
135 if (visibility_buffer_index > visibility_buffer_array_len) {
136 return -16;
137 }
139 let lod_range = visibility_ranges[visibility_buffer_index];
140 let camera_distance = length(view.lod_view_world_position.xyz - world_position.xyz);
142 // This encodes the following mapping:
143 //
144 // `lod_range.` x y z w camera distance
145 // ←───────┼────────┼────────┼────────┼────────→
146 // Dither Level -16 -16 0 0 16 16 Dither Level
147 let offset = select(-16, 0, camera_distance >= lod_range.z);
148 let bounds = select(lod_range.xy, lod_range.zw, camera_distance >= lod_range.z);
149 let level = i32(round((camera_distance - bounds.x) / (bounds.y - bounds.x) * 16.0));
150 return offset + clamp(level, 0, 16);
154@if(!MESHLET_MESH_MATERIAL_PASS)
155fn get_tag(instance_index: u32) -> u32 {
156 return mesh[instance_index].tag;
159@if(!MESHLET_MESH_MATERIAL_PASS)
160fn get_metadata(instance_index: u32) -> MeshMetadata {
161@if(METADATA_USE_UNIFORM_BUFFERS)
162 return metadata;
163@else
164 return metadata[mesh[instance_index].metadata_index];
Contents