diff --git a/Cargo.toml b/Cargo.toml index 6b5267be70da8..4350d48298779 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -201,6 +201,10 @@ path = "examples/3d/pbr.rs" name = "pbr_pipelined" path = "examples/3d/pbr_pipelined.rs" +[[example]] +name = "pbr_colors_pipelined" +path = "examples/3d/pbr_colors_pipelined.rs" + [[example]] name = "render_to_texture" path = "examples/3d/render_to_texture.rs" diff --git a/examples/3d/pbr_colors_pipelined.rs b/examples/3d/pbr_colors_pipelined.rs new file mode 100644 index 0000000000000..34a3929f09f76 --- /dev/null +++ b/examples/3d/pbr_colors_pipelined.rs @@ -0,0 +1,83 @@ +use bevy::{ + math::Vec3, + pbr2::{PbrBundle, PointLightBundle, StandardMaterial}, + prelude::{App, Assets, Commands, ResMut, Transform}, + render2::{ + camera::PerspectiveCameraBundle, + mesh::{shape, Mesh, VertexAttributeValues}, + }, + PipelinedDefaultPlugins, +}; + +/// This example illustrates how to use the vertex colors attribute. +fn main() { + App::new() + .add_plugins(PipelinedDefaultPlugins) + .add_startup_system(setup) + .run(); +} + +fn setup( + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + // create a generic cube + let mut cube_with_colors = Mesh::from(shape::Cube { size: 2.0 }); + + // set some nice nice colors! + cube_with_colors.set_attribute( + Mesh::ATTRIBUTE_COLOR, + // NOTE: the attribute count has to be consistent across all attributes, otherwise bevy + // will panic. + VertexAttributeValues::from(vec![ + // top + [0.79, 0.73, 0.07, 1.], + [0.74, 0.14, 0.29, 1.], + [0.08, 0.55, 0.74, 1.], + [0.20, 0.27, 0.29, 1.], + // bottom + [0.79, 0.73, 0.07, 1.], + [0.74, 0.14, 0.29, 1.], + [0.08, 0.55, 0.74, 1.], + [0.20, 0.27, 0.29, 1.], + // right + [0.79, 0.73, 0.07, 1.], + [0.74, 0.14, 0.29, 1.], + [0.08, 0.55, 0.74, 1.], + [0.20, 0.27, 0.29, 1.], + // left + [0.79, 0.73, 0.07, 1.], + [0.74, 0.14, 0.29, 1.], + [0.08, 0.55, 0.74, 1.], + [0.20, 0.27, 0.29, 1.], + // front + [0.79, 0.73, 0.07, 1.], + [0.74, 0.14, 0.29, 1.], + [0.08, 0.55, 0.74, 1.], + [0.20, 0.27, 0.29, 1.], + // back + [0.79, 0.73, 0.07, 1.], + [0.74, 0.14, 0.29, 1.], + [0.08, 0.55, 0.74, 1.], + [0.20, 0.27, 0.29, 1.], + ]), + ); + // cube + commands.spawn_bundle(PbrBundle { + mesh: meshes.add(cube_with_colors), // use our cube with vertex colors + material: materials.add(Default::default()), + transform: Transform::from_xyz(0.0, 0.0, 0.0), + ..Default::default() + }); + // light + commands.spawn_bundle(PointLightBundle { + transform: Transform::from_xyz(4.0, 8.0, 4.0), + ..Default::default() + }); + // camera + commands.spawn_bundle(PerspectiveCameraBundle { + transform: Transform::from_xyz(3.0, 5.0, -8.0).looking_at(Vec3::ZERO, Vec3::Y), + ..Default::default() + }); +} diff --git a/pipelined/bevy_pbr2/src/render/mesh.rs b/pipelined/bevy_pbr2/src/render/mesh.rs index 567745f919e0f..a805922ee784c 100644 --- a/pipelined/bevy_pbr2/src/render/mesh.rs +++ b/pipelined/bevy_pbr2/src/render/mesh.rs @@ -329,6 +329,7 @@ bitflags::bitflags! { const NONE = 0; const VERTEX_TANGENTS = (1 << 0); const TRANSPARENT_MAIN_PASS = (1 << 1); + const VERTEX_COLORS = (1 << 2); const MSAA_RESERVED_BITS = MeshPipelineKey::MSAA_MASK_BITS << MeshPipelineKey::MSAA_SHIFT_BITS; } } @@ -351,66 +352,69 @@ impl SpecializedPipeline for MeshPipeline { type Key = MeshPipelineKey; fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor { - let (vertex_array_stride, vertex_attributes) = - if key.contains(MeshPipelineKey::VERTEX_TANGENTS) { - ( - 48, - vec![ - // Position (GOTCHA! Vertex_Position isn't first in the buffer due to how Mesh sorts attributes (alphabetically)) - VertexAttribute { - format: VertexFormat::Float32x3, - offset: 12, - shader_location: 0, - }, - // Normal - VertexAttribute { - format: VertexFormat::Float32x3, - offset: 0, - shader_location: 1, - }, - // Uv (GOTCHA! uv is no longer third in the buffer due to how Mesh sorts attributes (alphabetically)) - VertexAttribute { - format: VertexFormat::Float32x2, - offset: 40, - shader_location: 2, - }, - // Tangent - VertexAttribute { - format: VertexFormat::Float32x4, - offset: 24, - shader_location: 3, - }, - ], - ) - } else { - ( - 32, - vec![ - // Position (GOTCHA! Vertex_Position isn't first in the buffer due to how Mesh sorts attributes (alphabetically)) - VertexAttribute { - format: VertexFormat::Float32x3, - offset: 12, - shader_location: 0, - }, - // Normal - VertexAttribute { - format: VertexFormat::Float32x3, - offset: 0, - shader_location: 1, - }, - // Uv - VertexAttribute { - format: VertexFormat::Float32x2, - offset: 24, - shader_location: 2, - }, - ], - ) - }; + let mut vertex_attributes: Vec = vec![]; + let mut offset = 0; + + // Mesh attributes are sorted alphabetically in the buffer, so add them in the correct + // order. + + // colors: will be at location 3 or 4 depending on wether Vertex_Tangents are used + if key.contains(MeshPipelineKey::VERTEX_COLORS) { + vertex_attributes.push(VertexAttribute { + format: VertexFormat::Float32x4, + offset, + shader_location: if key.contains(MeshPipelineKey::VERTEX_TANGENTS) { + 4 + } else { + 3 + }, + }); + offset += 16; + } + + // normals + vertex_attributes.push(VertexAttribute { + format: VertexFormat::Float32x3, + offset, + shader_location: 1, + }); + offset += 12; + + // positions + vertex_attributes.push(VertexAttribute { + format: VertexFormat::Float32x3, + offset, + shader_location: 0, + }); + offset += 12; + + // tangents + if key.contains(MeshPipelineKey::VERTEX_TANGENTS) { + vertex_attributes.push(VertexAttribute { + format: VertexFormat::Float32x4, + offset, + shader_location: 3, + }); + offset += 16; + } + + // uvs + vertex_attributes.push(VertexAttribute { + format: VertexFormat::Float32x2, + offset, + shader_location: 2, + }); + offset += 8; + + let vertex_array_stride = offset; + let mut shader_defs = Vec::new(); if key.contains(MeshPipelineKey::VERTEX_TANGENTS) { shader_defs.push(String::from("VERTEX_TANGENTS")); } + if key.contains(MeshPipelineKey::VERTEX_COLORS) { + shader_defs.push(String::from("VERTEX_COLORS")); + } let (label, blend, depth_write_enabled); if key.contains(MeshPipelineKey::TRANSPARENT_MAIN_PASS) { diff --git a/pipelined/bevy_pbr2/src/render/mesh.wgsl b/pipelined/bevy_pbr2/src/render/mesh.wgsl index 0bb20aeea0e62..8a4f6e3ec4f72 100644 --- a/pipelined/bevy_pbr2/src/render/mesh.wgsl +++ b/pipelined/bevy_pbr2/src/render/mesh.wgsl @@ -8,6 +8,14 @@ struct Vertex { #ifdef VERTEX_TANGENTS [[location(3)]] tangent: vec4; #endif +#ifdef VERTEX_COLORS +#ifdef VERTEX_TANGENTS + [[location(4)]] color: vec4; +#endif +#ifndef VERTEX_TANGENTS + [[location(3)]] color: vec4; +#endif +#endif }; struct VertexOutput { @@ -18,6 +26,14 @@ struct VertexOutput { #ifdef VERTEX_TANGENTS [[location(3)]] world_tangent: vec4; #endif +#ifdef VERTEX_COLORS +#ifdef VERTEX_TANGENTS + [[location(4)]] world_color: vec4; +#endif +#ifndef VERTEX_TANGENTS + [[location(3)]] world_color: vec4; +#endif +#endif }; [[group(2), binding(0)]] @@ -45,6 +61,9 @@ fn vertex(vertex: Vertex) -> VertexOutput { ) * vertex.tangent.xyz, vertex.tangent.w ); +#endif +#ifdef VERTEX_COLORS + out.world_color = vertex.color; #endif return out; } @@ -57,9 +76,17 @@ struct FragmentInput { #ifdef VERTEX_TANGENTS [[location(3)]] world_tangent: vec4; #endif +#ifdef VERTEX_COLORS +#ifdef VERTEX_TANGENTS + [[location(4)]] world_color: vec4; +#endif +#ifndef VERTEX_TANGENTS + [[location(3)]] world_color: vec4; +#endif +#endif }; [[stage(fragment)]] fn fragment(in: FragmentInput) -> [[location(0)]] vec4 { return vec4(1.0, 0.0, 1.0, 1.0); -} \ No newline at end of file +} diff --git a/pipelined/bevy_pbr2/src/render/mod.rs b/pipelined/bevy_pbr2/src/render/mod.rs index 348f7db955280..077520ab77996 100644 --- a/pipelined/bevy_pbr2/src/render/mod.rs +++ b/pipelined/bevy_pbr2/src/render/mod.rs @@ -260,6 +260,9 @@ pub fn queue_meshes( if mesh.has_tangents { pbr_key.mesh_key |= MeshPipelineKey::VERTEX_TANGENTS; } + if mesh.has_colors { + pbr_key.mesh_key |= MeshPipelineKey::VERTEX_COLORS; + } } if let AlphaMode::Blend = material.alpha_mode { diff --git a/pipelined/bevy_pbr2/src/render/pbr.wgsl b/pipelined/bevy_pbr2/src/render/pbr.wgsl index bb5515657a1f4..cff79388cee49 100644 --- a/pipelined/bevy_pbr2/src/render/pbr.wgsl +++ b/pipelined/bevy_pbr2/src/render/pbr.wgsl @@ -396,11 +396,23 @@ struct FragmentInput { #ifdef VERTEX_TANGENTS [[location(3)]] world_tangent: vec4; #endif +#ifdef VERTEX_COLORS +#ifdef VERTEX_TANGENTS + [[location(4)]] world_color: vec4; +#endif +#ifndef VERTEX_TANGENTS + [[location(3)]] world_color: vec4; +#endif +#endif }; [[stage(fragment)]] fn fragment(in: FragmentInput) -> [[location(0)]] vec4 { var output_color: vec4 = material.base_color; + +#ifdef VERTEX_COLORS + output_color = in.world_color; +#endif if ((material.flags & STANDARD_MATERIAL_FLAGS_BASE_COLOR_TEXTURE_BIT) != 0u) { output_color = output_color * textureSample(base_color_texture, base_color_sampler, in.uv); } diff --git a/pipelined/bevy_render2/src/mesh/mesh/mod.rs b/pipelined/bevy_render2/src/mesh/mesh/mod.rs index 57614f378e34a..cd88263aa2dcf 100644 --- a/pipelined/bevy_render2/src/mesh/mesh/mod.rs +++ b/pipelined/bevy_render2/src/mesh/mesh/mod.rs @@ -593,6 +593,7 @@ pub struct GpuMesh { pub vertex_buffer: Buffer, pub index_info: Option, pub has_tangents: bool, + pub has_colors: bool, } /// The index info of a [`GpuMesh`]. @@ -640,6 +641,7 @@ impl RenderAsset for Mesh { vertex_buffer, index_info, has_tangents: mesh.attributes.contains_key(Mesh::ATTRIBUTE_TANGENT), + has_colors: mesh.attributes.contains_key(Mesh::ATTRIBUTE_COLOR), }) } }