diff --git a/assets/shaders/custom_stencil.wesl b/assets/shaders/custom_stencil.wesl index 9253a4b8d7f13..ac50adcd3a2fb 100644 --- a/assets/shaders/custom_stencil.wesl +++ b/assets/shaders/custom_stencil.wesl @@ -32,12 +32,13 @@ fn vertex(vertex: Vertex) -> VertexOutput { // This is how bevy computes the world position // The vertex.instance_index is very important. Especially if you are using batching and gpu preprocessing var world_from_local = mesh_functions::get_world_from_local(vertex.instance_index); - @if(VERTEX_POSITIONS_COMPRESSED) - let mesh_uniform = bevy_pbr::render::mesh_bindings::mesh[vertex.instance_index]; - @if(VERTEX_POSITIONS_COMPRESSED) - let vertex_position = bevy_render::utils::decompress_vertex_position(vertex.compressed_position, mesh_uniform.aabb_center, mesh_uniform.aabb_half_extents); - @else +@if(VERTEX_POSITIONS_COMPRESSED) { + let mesh_metadata = bevy_pbr::render::mesh_functions::get_metadata(vertex.instance_index); + let vertex_position = bevy_render::utils::decompress_vertex_position(vertex.compressed_position, mesh_metadata.aabb_center, mesh_metadata.aabb_half_extents); +} +@else { let vertex_position = vertex.position; +} out.world_position = mesh_functions::mesh_position_local_to_world(world_from_local, vec4(vertex_position, 1.0)); out.clip_position = position_world_to_clip(out.world_position.xyz); return out; diff --git a/assets/shaders/specialized_mesh_pipeline.wesl b/assets/shaders/specialized_mesh_pipeline.wesl index c563ff46aedf8..62041d654a439 100644 --- a/assets/shaders/specialized_mesh_pipeline.wesl +++ b/assets/shaders/specialized_mesh_pipeline.wesl @@ -19,6 +19,7 @@ struct Vertex { @else @location(0) position: vec3, // and color at location 1 + @if(VERTEX_COLORS) @location(1) color: vec4, }; @@ -26,6 +27,7 @@ struct Vertex { struct VertexOutput { @builtin(position) clip_position: vec4, @location(0) world_position: vec4, + @if(VERTEX_COLORS) @location(1) color: vec3, }; @@ -35,16 +37,17 @@ fn vertex(vertex: Vertex) -> VertexOutput { // This is how bevy computes the world position // The vertex.instance_index is very important. Especially if you are using batching and gpu preprocessing var world_from_local = mesh_functions::get_world_from_local(vertex.instance_index); - @if(VERTEX_POSITIONS_COMPRESSED) - let mesh_uniform = bevy_pbr::render::mesh_bindings::mesh[vertex.instance_index]; - @if(VERTEX_POSITIONS_COMPRESSED) - let vertex_position = bevy_render::utils::decompress_vertex_position(vertex.compressed_position, mesh_uniform.aabb_center, mesh_uniform.aabb_half_extents); - @else +@if(VERTEX_POSITIONS_COMPRESSED) { + let mesh_metadata = bevy_pbr::render::mesh_functions::get_metadata(vertex.instance_index); + let vertex_position = bevy_render::utils::decompress_vertex_position(vertex.compressed_position, mesh_metadata.aabb_center, mesh_metadata.aabb_half_extents); +} +@else { let vertex_position = vertex.position; +} out.world_position = mesh_functions::mesh_position_local_to_world(world_from_local, vec4(vertex_position, 1.0)); out.clip_position = position_world_to_clip(out.world_position.xyz); - // We just use the raw vertex color + @if(VERTEX_COLORS) out.color = vertex.color.rgb; return out; @@ -52,6 +55,14 @@ fn vertex(vertex: Vertex) -> VertexOutput { @fragment fn fragment(in: VertexOutput) -> @location(0) vec4 { + // We just use the raw vertex color if the mesh provides one, otherwise + // we fall back to a hardcoded color (e.g. for the rectangle mesh, + // which has no vertex color attribute). + @if(VERTEX_COLORS) + let color = in.color; + @else + let color = vec3(1.0, 1.0, 1.0); + // output the color directly - return vec4(in.color, 1.0); + return vec4(color, 1.0); } diff --git a/examples/shader_advanced/custom_render_phase.rs b/examples/shader_advanced/custom_render_phase.rs index 5474f3574b95e..b6284ee43d343 100644 --- a/examples/shader_advanced/custom_render_phase.rs +++ b/examples/shader_advanced/custom_render_phase.rs @@ -14,7 +14,7 @@ use std::ops::Range; use bevy::camera::Viewport; use bevy::core_pipeline::core_3d::TransparentSortingInfo3d; -use bevy::mesh::MeshAttributeCompressionFlags; +use bevy::mesh::{MeshAttributeCompressionFlags, MeshCompressionArgs}; use bevy::pbr::{self, MeshPipelineSystems, SetMeshViewEmptyBindGroup, ViewKeyCache}; use bevy::{ camera::MainPassResolutionOverride, @@ -94,6 +94,22 @@ fn setup( // The circle doesn't have it so it won't be rendered in our pass DrawStencil, )); + commands.spawn(( + Mesh3d( + meshes.add( + Sphere::new(0.5) + .mesh() + .build() + .compressed_mesh(&MeshCompressionArgs::regular()) + .unwrap(), + ), + ), + MeshMaterial3d(materials.add(Color::srgb_u8(124, 255, 144))), + Transform::from_xyz(2.0, 0.5, 0.0), + // This marker component is used to identify which mesh will be used in our custom pass + // The circle doesn't have it so it won't be rendered in our pass + DrawStencil, + )); // light commands.spawn(( PointLight { diff --git a/examples/shader_advanced/specialized_mesh_pipeline.rs b/examples/shader_advanced/specialized_mesh_pipeline.rs index e4efe37f8d1a2..4e7abc6df74f9 100644 --- a/examples/shader_advanced/specialized_mesh_pipeline.rs +++ b/examples/shader_advanced/specialized_mesh_pipeline.rs @@ -12,7 +12,10 @@ use bevy::{ core_pipeline::core_3d::{Opaque3d, Opaque3dBatchSetKey, Opaque3dBinKey, CORE_3D_DEPTH_FORMAT}, ecs::change_detection::Tick, math::{vec3, vec4}, - mesh::{Indices, MeshAttributeCompressionFlags, MeshVertexBufferLayoutRef, PrimitiveTopology}, + mesh::{ + Indices, MeshAttributeCompressionFlags, MeshCompressionArgs, MeshVertexBufferLayoutRef, + PrimitiveTopology, + }, pbr::{ DrawMesh, MeshPipeline, MeshPipelineKey, MeshPipelineSystems, MeshPipelineViewLayoutKey, RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup, SetMeshViewEmptyBindGroup, @@ -90,6 +93,24 @@ fn setup(mut commands: Commands, mut meshes: ResMut>) { Transform::from_xyz(x, y, 0.0), )); } + commands.spawn(( + // We use a marker component to identify the mesh that will be rendered + // with our specialized pipeline + CustomRenderedEntity, + // We need to add the mesh handle to the entity + Mesh3d( + meshes.add( + Rectangle::new(0.5, 0.5) + .mesh() + .build() + .with_removed_attribute(Mesh::ATTRIBUTE_NORMAL) + .with_removed_attribute(Mesh::ATTRIBUTE_UV_0) + .compressed_mesh(&MeshCompressionArgs::regular()) + .unwrap(), + ), + ), + Transform::from_xyz(0.0, -1.0 / 3.0, -1.0), + )); // Spawn the camera. commands.spawn(( @@ -212,6 +233,7 @@ impl SpecializedMeshPipeline for CustomMeshPipeline { vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0)); } if layout.0.contains(Mesh::ATTRIBUTE_COLOR) { + shader_defs.push("VERTEX_COLORS".into()); // Make sure this matches the shader location vertex_attributes.push(Mesh::ATTRIBUTE_COLOR.at_shader_location(1)); }