#import bevy_pbr::{ prepass_bindings, mesh_functions, prepass_io::{Vertex, VertexOutput, FragmentOutput}, skinning, morph, mesh_view_bindings::{view, previous_view_proj}, } #import bevy_render::instance_index::get_instance_index #ifdef DEFERRED_PREPASS #import bevy_pbr::rgb9e5 #endif #ifdef MORPH_TARGETS fn morph_vertex(vertex_in: Vertex) -> Vertex { var vertex = vertex_in; let weight_count = morph::layer_count(); for (var i: u32 = 0u; i < weight_count; i ++) { let weight = morph::weight_at(i); if weight == 0.0 { continue; } vertex.position += weight * morph::morph(vertex.index, morph::position_offset, i); #ifdef VERTEX_NORMALS vertex.normal += weight * morph::morph(vertex.index, morph::normal_offset, i); #endif #ifdef VERTEX_TANGENTS vertex.tangent += vec4(weight * morph::morph(vertex.index, morph::tangent_offset, i), 0.0); #endif } return vertex; } #endif @vertex fn vertex(vertex_no_morph: Vertex) -> VertexOutput { var out: VertexOutput; #ifdef MORPH_TARGETS var vertex = morph::morph_vertex(vertex_no_morph); #else var vertex = vertex_no_morph; #endif #ifdef SKINNED var model = skinning::skin_model(vertex.joint_indices, vertex.joint_weights); #else // SKINNED // Use vertex_no_morph.instance_index instead of vertex.instance_index to work around a wgpu dx12 bug. // See https://github.com/gfx-rs/naga/issues/2416 var model = mesh_functions::get_model_matrix(vertex_no_morph.instance_index); #endif // SKINNED out.position = mesh_functions::mesh_position_local_to_clip(model, vec4(vertex.position, 1.0)); #ifdef DEPTH_CLAMP_ORTHO out.clip_position_unclamped = out.position; out.position.z = min(out.position.z, 1.0); #endif // DEPTH_CLAMP_ORTHO #ifdef VERTEX_UVS out.uv = vertex.uv; #endif // VERTEX_UVS #ifdef NORMAL_PREPASS_OR_DEFERRED_PREPASS #ifdef SKINNED out.world_normal = skinning::skin_normals(model, vertex.normal); #else // SKINNED out.world_normal = mesh_functions::mesh_normal_local_to_world( vertex.normal, // Use vertex_no_morph.instance_index instead of vertex.instance_index to work around a wgpu dx12 bug. // See https://github.com/gfx-rs/naga/issues/2416 get_instance_index(vertex_no_morph.instance_index) ); #endif // SKINNED #ifdef VERTEX_TANGENTS out.world_tangent = mesh_functions::mesh_tangent_local_to_world( model, vertex.tangent, // Use vertex_no_morph.instance_index instead of vertex.instance_index to work around a wgpu dx12 bug. // See https://github.com/gfx-rs/naga/issues/2416 get_instance_index(vertex_no_morph.instance_index) ); #endif // VERTEX_TANGENTS #endif // NORMAL_PREPASS_OR_DEFERRED_PREPASS #ifdef VERTEX_COLORS out.color = vertex.color; #endif #ifdef MOTION_VECTOR_PREPASS_OR_DEFERRED_PREPASS out.world_position = mesh_functions::mesh_position_local_to_world(model, vec4(vertex.position, 1.0)); #endif // MOTION_VECTOR_PREPASS_OR_DEFERRED_PREPASS #ifdef MOTION_VECTOR_PREPASS // Use vertex_no_morph.instance_index instead of vertex.instance_index to work around a wgpu dx12 bug. // See https://github.com/gfx-rs/naga/issues/2416 out.previous_world_position = mesh_functions::mesh_position_local_to_world( mesh_functions::get_previous_model_matrix(vertex_no_morph.instance_index), vec4(vertex.position, 1.0) ); #endif // MOTION_VECTOR_PREPASS #ifdef VERTEX_OUTPUT_INSTANCE_INDEX // Use vertex_no_morph.instance_index instead of vertex.instance_index to work around a wgpu dx12 bug. // See https://github.com/gfx-rs/naga/issues/2416 out.instance_index = get_instance_index(vertex_no_morph.instance_index); #endif return out; } #ifdef PREPASS_FRAGMENT @fragment fn fragment(in: VertexOutput) -> FragmentOutput { var out: FragmentOutput; #ifdef NORMAL_PREPASS out.normal = vec4(in.world_normal * 0.5 + vec3(0.5), 1.0); #endif #ifdef DEPTH_CLAMP_ORTHO out.frag_depth = in.clip_position_unclamped.z; #endif // DEPTH_CLAMP_ORTHO #ifdef MOTION_VECTOR_PREPASS let clip_position_t = view.unjittered_view_proj * in.world_position; let clip_position = clip_position_t.xy / clip_position_t.w; let previous_clip_position_t = prepass_bindings::previous_view_proj * in.previous_world_position; let previous_clip_position = previous_clip_position_t.xy / previous_clip_position_t.w; // These motion vectors are used as offsets to UV positions and are stored // in the range -1,1 to allow offsetting from the one corner to the // diagonally-opposite corner in UV coordinates, in either direction. // A difference between diagonally-opposite corners of clip space is in the // range -2,2, so this needs to be scaled by 0.5. And the V direction goes // down where clip space y goes up, so y needs to be flipped. out.motion_vector = (clip_position - previous_clip_position) * vec2(0.5, -0.5); #endif // MOTION_VECTOR_PREPASS #ifdef DEFERRED_PREPASS // There isn't any material info available for this default prepass shader so we are just writing  // emissive magenta out to the deferred gbuffer to be rendered by the first deferred lighting pass layer. // The is here so if the default prepass fragment is used for deferred magenta will be rendered, and also // as an example to show that a user could write to the deferred gbuffer if they were to start from this shader. out.deferred = vec4(0u, bevy_pbr::rgb9e5::vec3_to_rgb9e5_(vec3(1.0, 0.0, 1.0)), 0u, 0u); out.deferred_lighting_pass_id = 1u; #endif return out; } #endif // PREPASS_FRAGMENT