#import bevy_pbr::{ pbr_types, pbr_functions::alpha_discard, pbr_fragment::pbr_input_from_standard_material, decal::clustered::apply_decal_base_color, mesh_functions, view_transformations::position_world_to_clip } #ifdef PREPASS_PIPELINE #import bevy_pbr::{ prepass_io::{VertexOutput, FragmentOutput}, pbr_deferred_functions::deferred_output, } #else #import bevy_pbr::{ forward_io::{VertexOutput, FragmentOutput}, pbr_functions, pbr_functions::{apply_pbr_lighting, main_pass_post_lighting_processing}, pbr_types::STANDARD_MATERIAL_FLAGS_UNLIT_BIT, } #endif #ifdef MESHLET_MESH_MATERIAL_PASS #import bevy_pbr::meshlet_visibility_buffer_resolve::resolve_vertex_output #endif #ifdef OIT_ENABLED #import bevy_core_pipeline::oit::oit_draw #endif // OIT_ENABLED #ifdef FORWARD_DECAL #import bevy_pbr::decal::forward::get_forward_decal_info #endif struct Vertex { @builtin(instance_index) instance_index: u32, @location(0) position: vec3, @location(1) normal: vec3, // @location(2) cell_kind: u32 @location(5) color: vec4, }; struct FlatVertexOutput { // This is `clip position` when the struct is used as a vertex stage output // and `frag coord` when used as a fragment stage input @builtin(position) position: vec4, @location(0) world_position: vec4, @location(1) @interpolate(flat) world_normal: vec3, // @location(2) @interpolate(flat) cell_kind: u32 @location(5) @interpolate(flat) color: vec4, @location(6) @interpolate(flat) instance_index: u32, } // struct FragmentOutput { // @location(0) color: vec4, // } @vertex fn vertex(vert: Vertex) -> FlatVertexOutput { var out: FlatVertexOutput; let mesh_world_from_local = mesh_functions::get_world_from_local(vert.instance_index); out.world_normal = mesh_functions::mesh_normal_local_to_world( vert.normal, vert.instance_index ); out.world_position = mesh_functions::mesh_position_local_to_world(mesh_world_from_local, vec4(vert.position, 1.0)); out.position = position_world_to_clip(out.world_position.xyz); // out.cell_kind = vert.cell_kind; out.instance_index = vert.instance_index; out.color = vert.color; return out; } @fragment fn fragment( vertex_output: FlatVertexOutput, @builtin(front_facing) is_front: bool ) -> FragmentOutput { var in: VertexOutput; in.instance_index = vertex_output.instance_index; in.position = vertex_output.position; in.world_normal = vertex_output.world_normal; in.color = vertex_output.color; // generate a PbrInput struct from the StandardMaterial bindings var pbr_input = pbr_input_from_standard_material(in, is_front); // alpha discard pbr_input.material.base_color = alpha_discard(pbr_input.material, pbr_input.material.base_color); // // clustered decals // pbr_input.material.base_color = apply_decal_base_color( // in.world_position.xyz, // in.position.xy, // pbr_input.material.base_color // ); #ifdef PREPASS_PIPELINE // write the gbuffer, lighting pass id, and optionally normal and motion_vector textures let out = deferred_output(in, pbr_input); #else // in forward mode, we calculate the lit color immediately, and then apply some post-lighting effects here. // in deferred mode the lit color and these effects will be calculated in the deferred lighting shader var out: FragmentOutput; if (pbr_input.material.flags & STANDARD_MATERIAL_FLAGS_UNLIT_BIT) == 0u { out.color = apply_pbr_lighting(pbr_input); } else { out.color = pbr_input.material.base_color; } // apply in-shader post processing (fog, alpha-premultiply, and also tonemapping, debanding if the camera is non-hdr) // note this does not include fullscreen postprocessing effects like bloom. out.color = main_pass_post_lighting_processing(pbr_input, out.color); #endif #ifdef OIT_ENABLED let alpha_mode = pbr_input.material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS; if alpha_mode != pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_OPAQUE { // The fragments will only be drawn during the oit resolve pass. oit_draw(in.position, out.color); discard; } #endif // OIT_ENABLED #ifdef FORWARD_DECAL out.color.a = min(forward_decal_info.alpha, out.color.a); #endif return out; }