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#import bevy_pbr::{
2 prepass_bindings,
3 mesh_bindings::mesh,
4 mesh_functions,
5 prepass_io::{Vertex, VertexOutput, FragmentOutput},
6 skinning,
7 morph,
8 morph::{morph_position, morph_normal, morph_tangent},
9 mesh_view_bindings::view,
10 view_transformations::position_world_to_clip,
13#ifdef DEFERRED_PREPASS
14#import bevy_pbr::rgb9e5
15#endif
17#ifdef MORPH_TARGETS
18// The instance_index parameter must match vertex_in.instance_index. This is a work around for a wgpu dx12 bug.
19// See https://github.com/gfx-rs/naga/issues/2416
20fn morph_vertex(vertex_in: Vertex, instance_index: u32) -> Vertex {
21 var vertex = vertex_in;
22 let first_vertex = mesh[instance_index].first_vertex_index;
23 let vertex_index = vertex.index - first_vertex;
25 let weight_count = morph::layer_count(instance_index);
26 for (var i: u32 = 0u; i < weight_count; i ++) {
27 let weight = morph::weight_at(i, instance_index);
28 if weight == 0.0 {
29 continue;
30 }
31 vertex.position += weight * morph_position(vertex_index, i, instance_index);
32#ifdef VERTEX_NORMALS
33 vertex.normal += weight * morph_normal(vertex_index, i, instance_index);
34#endif
35#ifdef VERTEX_TANGENTS
36 vertex.tangent += vec4(weight * morph_tangent(vertex_index, i, instance_index), 0.0);
37#endif
38 }
39 return vertex;
42// Returns the morphed position of the given vertex from the previous frame.
43//
44// This function is used for motion vector calculation, and, as such, it doesn't
45// bother morphing the normals and tangents.
46//
47// The instance_index parameter must match vertex_in.instance_index. This is a work around for a wgpu dx12 bug.
48// See https://github.com/gfx-rs/naga/issues/2416
49fn morph_prev_vertex(vertex_in: Vertex, instance_index: u32) -> Vertex {
50 var vertex = vertex_in;
51 let first_vertex = mesh[instance_index].first_vertex_index;
52 let vertex_index = vertex.index - first_vertex;
53 let weight_count = morph::layer_count(instance_index);
54 for (var i: u32 = 0u; i < weight_count; i ++) {
55 let weight = morph::prev_weight_at(i, instance_index);
56 if weight == 0.0 {
57 continue;
58 }
59 vertex.position += weight * morph_position(vertex_index, i, instance_index);
60 // Don't bother morphing normals and tangents; we don't need them for
61 // motion vector calculation.
62 }
63 return vertex;
65#endif // MORPH_TARGETS
67@vertex
68fn vertex(vertex_no_morph: Vertex) -> VertexOutput {
69 var out: VertexOutput;
71#ifdef MORPH_TARGETS
72 var vertex = morph_vertex(vertex_no_morph, vertex_no_morph.instance_index);
73#else
74 var vertex = vertex_no_morph;
75#endif
77 let mesh_world_from_local = mesh_functions::get_world_from_local(vertex_no_morph.instance_index);
79#ifdef SKINNED
80 // Use vertex_no_morph.instance_index instead of vertex.instance_index to work around a wgpu dx12 bug.
81 // See https://github.com/gfx-rs/naga/issues/2416
82 var world_from_local = skinning::skin_model(
83 vertex.joint_indices,
84 vertex.joint_weights,
85 vertex_no_morph.instance_index
86 );
87#else // SKINNED
88 var world_from_local = mesh_world_from_local;
89#endif // SKINNED
91 out.world_position = mesh_functions::mesh_position_local_to_world(world_from_local, vec4<f32>(vertex.position, 1.0));
92 out.position = position_world_to_clip(out.world_position.xyz);
93#ifdef UNCLIPPED_DEPTH_ORTHO_EMULATION
94 out.unclipped_depth = out.position.z;
95 out.position.z = min(out.position.z, 1.0); // Clamp depth to avoid clipping
96#endif // UNCLIPPED_DEPTH_ORTHO_EMULATION
98#ifdef VERTEX_UVS_A
99 out.uv = vertex.uv;
100#endif // VERTEX_UVS_A
102#ifdef VERTEX_UVS_B
103 out.uv_b = vertex.uv_b;
104#endif // VERTEX_UVS_B
106#ifdef NORMAL_PREPASS_OR_DEFERRED_PREPASS
107#ifdef VERTEX_NORMALS
108#ifdef SKINNED
109 out.world_normal = skinning::skin_normals(world_from_local, vertex.normal);
110#else // SKINNED
111 out.world_normal = mesh_functions::mesh_normal_local_to_world(
112 vertex.normal,
113 // Use vertex_no_morph.instance_index instead of vertex.instance_index to work around a wgpu dx12 bug.
114 // See https://github.com/gfx-rs/naga/issues/2416
115 vertex_no_morph.instance_index
116 );
117#endif // SKINNED
118#endif // VERTEX_NORMALS
120#ifdef VERTEX_TANGENTS
121 out.world_tangent = mesh_functions::mesh_tangent_local_to_world(
122 world_from_local,
123 vertex.tangent,
124 // Use vertex_no_morph.instance_index instead of vertex.instance_index to work around a wgpu dx12 bug.
125 // See https://github.com/gfx-rs/naga/issues/2416
126 vertex_no_morph.instance_index
127 );
128#endif // VERTEX_TANGENTS
129#endif // NORMAL_PREPASS_OR_DEFERRED_PREPASS
131#ifdef VERTEX_COLORS
132 out.color = vertex.color;
133#endif
135 // Compute the motion vector for TAA among other purposes. For this we need
136 // to know where the vertex was last frame.
137#ifdef MOTION_VECTOR_PREPASS
139 // Take morph targets into account.
140#ifdef MORPH_TARGETS
142#ifdef HAS_PREVIOUS_MORPH
143 let prev_vertex = morph_prev_vertex(vertex_no_morph, vertex_no_morph.instance_index);
144#else // HAS_PREVIOUS_MORPH
145 let prev_vertex = vertex_no_morph;
146#endif // HAS_PREVIOUS_MORPH
148#else // MORPH_TARGETS
149 let prev_vertex = vertex_no_morph;
150#endif // MORPH_TARGETS
152 // Take skinning into account.
153#ifdef SKINNED
155#ifdef HAS_PREVIOUS_SKIN
156 let prev_model = skinning::skin_prev_model(
157 prev_vertex.joint_indices,
158 prev_vertex.joint_weights,
159 vertex_no_morph.instance_index
160 );
161#else // HAS_PREVIOUS_SKIN
162 // Use vertex_no_morph.instance_index instead of prev_vertex.instance_index to work around a wgpu dx12 bug.
163 // See https://github.com/gfx-rs/naga/issues/2416
164 let prev_model = mesh_functions::get_previous_world_from_local(vertex_no_morph.instance_index);
165#endif // HAS_PREVIOUS_SKIN
167#else // SKINNED
168 // Use vertex_no_morph.instance_index instead of prev_vertex.instance_index to work around a wgpu dx12 bug.
169 // See https://github.com/gfx-rs/naga/issues/2416
170 let prev_model = mesh_functions::get_previous_world_from_local(vertex_no_morph.instance_index);
171#endif // SKINNED
173 out.previous_world_position = mesh_functions::mesh_position_local_to_world(
174 prev_model,
175 vec4<f32>(prev_vertex.position, 1.0)
176 );
177#endif // MOTION_VECTOR_PREPASS
179#ifdef VERTEX_OUTPUT_INSTANCE_INDEX
180 // Use vertex_no_morph.instance_index instead of vertex.instance_index to work around a wgpu dx12 bug.
181 // See https://github.com/gfx-rs/naga/issues/2416
182 out.instance_index = vertex_no_morph.instance_index;
183#endif
185#ifdef VISIBILITY_RANGE_DITHER
186 out.visibility_range_dither = mesh_functions::get_visibility_range_dither_level(
187 vertex_no_morph.instance_index, mesh_world_from_local[3]);
188#endif // VISIBILITY_RANGE_DITHER
190 return out;
193#ifdef PREPASS_FRAGMENT
194@fragment
195fn fragment(in: VertexOutput) -> FragmentOutput {
196 var out: FragmentOutput;
198#ifdef NORMAL_PREPASS
199 out.normal = vec4(in.world_normal * 0.5 + vec3(0.5), 1.0);
200#endif
202#ifdef UNCLIPPED_DEPTH_ORTHO_EMULATION
203 out.frag_depth = in.unclipped_depth;
204#endif // UNCLIPPED_DEPTH_ORTHO_EMULATION
206#ifdef MOTION_VECTOR_PREPASS
207 let clip_position_t = view.unjittered_clip_from_world * in.world_position;
208 let clip_position = clip_position_t.xy / clip_position_t.w;
209 let previous_clip_position_t = prepass_bindings::previous_view_uniforms.clip_from_world * in.previous_world_position;
210 let previous_clip_position = previous_clip_position_t.xy / previous_clip_position_t.w;
211 // These motion vectors are used as offsets to UV positions and are stored
212 // in the range -1,1 to allow offsetting from the one corner to the
213 // diagonally-opposite corner in UV coordinates, in either direction.
214 // A difference between diagonally-opposite corners of clip space is in the
215 // range -2,2, so this needs to be scaled by 0.5. And the V direction goes
216 // down where clip space y goes up, so y needs to be flipped.
217 out.motion_vector = (clip_position - previous_clip_position) * vec2(0.5, -0.5);
218#endif // MOTION_VECTOR_PREPASS
220#ifdef DEFERRED_PREPASS
221 // There isn't any material info available for this default prepass shader so we are just writing 
222 // emissive magenta out to the deferred gbuffer to be rendered by the first deferred lighting pass layer.
223 // This is here so if the default prepass fragment is used for deferred magenta will be rendered, and also
224 // as an example to show that a user could write to the deferred gbuffer if they were to start from this shader.
225 out.deferred = vec4(0u, bevy_pbr::rgb9e5::vec3_to_rgb9e5_(vec3(1.0, 0.0, 1.0)), 0u, 0u);
226 out.deferred_lighting_pass_id = 1u;
227#endif
229 return out;
231#endif // PREPASS_FRAGMENT
Contents