diff --git a/Cargo.toml b/Cargo.toml index 3f5c13b5109b7..6978b897dccf4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -196,6 +196,10 @@ path = "examples/3d/parenting.rs" name = "pbr" path = "examples/3d/pbr.rs" +[[example]] +name = "render_to_texture" +path = "examples/3d/render_to_texture.rs" + [[example]] name = "shadow_biases" path = "examples/3d/shadow_biases.rs" @@ -212,10 +216,6 @@ path = "examples/3d/spherical_area_lights.rs" name = "texture" path = "examples/3d/texture.rs" -[[example]] -name = "render_to_texture" -path = "examples/3d/render_to_texture.rs" - [[example]] name = "two_passes" path = "examples/3d/two_passes.rs" @@ -224,6 +224,10 @@ path = "examples/3d/two_passes.rs" name = "update_gltf_scene" path = "examples/3d/update_gltf_scene.rs" +[[example]] +name = "vertex_colors" +path = "examples/3d/vertex_colors.rs" + [[example]] name = "wireframe" path = "examples/3d/wireframe.rs" diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index 2b95f3e5541b4..9233d619a8dda 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -269,12 +269,12 @@ async fn load_gltf<'a, 'b>( mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs); } - // if let Some(vertex_attribute) = reader - // .read_colors(0) - // .map(|v| VertexAttributeValues::Float32x4(v.into_rgba_f32().collect())) - // { - // mesh.insert_attribute(Mesh::ATTRIBUTE_COLOR, vertex_attribute); - // } + if let Some(vertex_attribute) = reader + .read_colors(0) + .map(|v| VertexAttributeValues::Float32x4(v.into_rgba_f32().collect())) + { + mesh.insert_attribute(Mesh::ATTRIBUTE_COLOR, vertex_attribute); + } if let Some(iter) = reader.read_joints(0) { let vertex_attribute = VertexAttributeValues::Uint16x4(iter.into_u16().collect()); diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 7cff3f9d9fca8..356f260518ff8 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -560,6 +560,11 @@ impl SpecializedMeshPipeline for MeshPipeline { vertex_attributes.push(Mesh::ATTRIBUTE_TANGENT.at_shader_location(3)); } + if layout.contains(Mesh::ATTRIBUTE_COLOR) { + shader_defs.push(String::from("VERTEX_COLORS")); + vertex_attributes.push(Mesh::ATTRIBUTE_COLOR.at_shader_location(4)); + } + // TODO: consider exposing this in shaders in a more generally useful way, such as: // # if AVAILABLE_STORAGE_BUFFER_BINDINGS == 3 // /* use storage buffers here */ @@ -577,8 +582,8 @@ impl SpecializedMeshPipeline for MeshPipeline { && layout.contains(Mesh::ATTRIBUTE_JOINT_WEIGHT) { shader_defs.push(String::from("SKINNED")); - vertex_attributes.push(Mesh::ATTRIBUTE_JOINT_INDEX.at_shader_location(4)); - vertex_attributes.push(Mesh::ATTRIBUTE_JOINT_WEIGHT.at_shader_location(5)); + vertex_attributes.push(Mesh::ATTRIBUTE_JOINT_INDEX.at_shader_location(5)); + vertex_attributes.push(Mesh::ATTRIBUTE_JOINT_WEIGHT.at_shader_location(6)); bind_group_layout.push(self.skinned_mesh_layout.clone()); } else { bind_group_layout.push(self.mesh_layout.clone()); diff --git a/crates/bevy_pbr/src/render/mesh.wgsl b/crates/bevy_pbr/src/render/mesh.wgsl index ffa26f4b94769..2adaab7c086a7 100644 --- a/crates/bevy_pbr/src/render/mesh.wgsl +++ b/crates/bevy_pbr/src/render/mesh.wgsl @@ -8,9 +8,12 @@ struct Vertex { #ifdef VERTEX_TANGENTS [[location(3)]] tangent: vec4; #endif +#ifdef VERTEX_COLORS + [[location(4)]] color: vec4; +#endif #ifdef SKINNED - [[location(4)]] joint_indices: vec4; - [[location(5)]] joint_weights: vec4; + [[location(5)]] joint_indices: vec4; + [[location(6)]] joint_weights: vec4; #endif }; @@ -22,6 +25,9 @@ struct VertexOutput { #ifdef VERTEX_TANGENTS [[location(3)]] world_tangent: vec4; #endif +#ifdef VERTEX_COLORS + [[location(4)]] color: vec4; +#endif }; [[group(2), binding(0)]] @@ -60,6 +66,9 @@ fn vertex(vertex: Vertex) -> VertexOutput { ); #endif #endif +#ifdef VERTEX_COLORS + out.color = vertex.color; +#endif out.uv = vertex.uv; out.clip_position = view.view_proj * out.world_position; @@ -74,9 +83,16 @@ struct FragmentInput { #ifdef VERTEX_TANGENTS [[location(3)]] world_tangent: vec4; #endif +#ifdef VERTEX_COLORS + [[location(4)]] color: vec4; +#endif }; [[stage(fragment)]] fn fragment(in: FragmentInput) -> [[location(0)]] vec4 { +#ifdef VERTEX_COLORS + return in.color; +#else return vec4(1.0, 0.0, 1.0, 1.0); -} \ No newline at end of file +#endif +} diff --git a/crates/bevy_pbr/src/render/pbr.wgsl b/crates/bevy_pbr/src/render/pbr.wgsl index 8e365cdd3885b..ee38107169ec6 100644 --- a/crates/bevy_pbr/src/render/pbr.wgsl +++ b/crates/bevy_pbr/src/render/pbr.wgsl @@ -465,11 +465,17 @@ struct FragmentInput { #ifdef VERTEX_TANGENTS [[location(3)]] world_tangent: vec4; #endif +#ifdef VERTEX_COLORS + [[location(4)]] color: vec4; +#endif }; [[stage(fragment)]] fn fragment(in: FragmentInput) -> [[location(0)]] vec4 { var output_color: vec4 = material.base_color; + #ifdef VERTEX_COLORS + output_color = output_color * in.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/crates/bevy_render/src/mesh/mesh/mod.rs b/crates/bevy_render/src/mesh/mesh/mod.rs index 73488a60af884..5a4f86ced97d4 100644 --- a/crates/bevy_render/src/mesh/mesh/mod.rs +++ b/crates/bevy_render/src/mesh/mesh/mod.rs @@ -73,7 +73,7 @@ impl Mesh { /// Per vertex coloring. Use in conjunction with [`Mesh::insert_attribute`] pub const ATTRIBUTE_COLOR: MeshVertexAttribute = - MeshVertexAttribute::new("Vertex_Color", 4, VertexFormat::Uint32); + MeshVertexAttribute::new("Vertex_Color", 4, VertexFormat::Float32x4); /// Per vertex joint transform matrix weight. Use in conjunction with [`Mesh::insert_attribute`] pub const ATTRIBUTE_JOINT_WEIGHT: MeshVertexAttribute = diff --git a/crates/bevy_sprite/src/mesh2d/mesh.rs b/crates/bevy_sprite/src/mesh2d/mesh.rs index 4a804372b978a..097374c6391b4 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -295,6 +295,11 @@ impl SpecializedMeshPipeline for Mesh2dPipeline { vertex_attributes.push(Mesh::ATTRIBUTE_TANGENT.at_shader_location(3)); } + if layout.contains(Mesh::ATTRIBUTE_COLOR) { + shader_defs.push(String::from("VERTEX_COLORS")); + vertex_attributes.push(Mesh::ATTRIBUTE_COLOR.at_shader_location(4)); + } + #[cfg(feature = "webgl")] shader_defs.push(String::from("NO_ARRAY_TEXTURES_SUPPORT")); diff --git a/examples/2d/mesh2d_manual.rs b/examples/2d/mesh2d_manual.rs index e4cc86d886164..a3e7fff3a8113 100644 --- a/examples/2d/mesh2d_manual.rs +++ b/examples/2d/mesh2d_manual.rs @@ -4,7 +4,7 @@ use bevy::{ prelude::*, reflect::TypeUuid, render::{ - mesh::Indices, + mesh::{Indices, MeshVertexAttribute}, render_asset::RenderAssets, render_phase::{AddRenderCommand, DrawFunctions, RenderPhase, SetItemPipeline}, render_resource::{ @@ -72,7 +72,10 @@ fn star( // And a RGB color attribute as well let mut v_color: Vec = vec![Color::BLACK.as_linear_rgba_u32()]; v_color.extend_from_slice(&[Color::YELLOW.as_linear_rgba_u32(); 10]); - star.insert_attribute(Mesh::ATTRIBUTE_COLOR, v_color); + star.insert_attribute( + MeshVertexAttribute::new("Vertex_Color", 1, VertexFormat::Uint32), + v_color, + ); // Now, we specify the indices of the vertex that are going to compose the // triangles in our star. Vertices in triangles have to be specified in CCW diff --git a/examples/3d/vertex_colors.rs b/examples/3d/vertex_colors.rs new file mode 100644 index 0000000000000..4050230ae765a --- /dev/null +++ b/examples/3d/vertex_colors.rs @@ -0,0 +1,59 @@ +use bevy::{prelude::*, render::mesh::VertexAttributeValues}; + +fn main() { + App::new() + .insert_resource(Msaa { samples: 4 }) + .add_plugins(DefaultPlugins) + .add_startup_system(setup) + .run(); +} + +/// set up a simple 3D scene +fn setup( + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + // plane + commands.spawn_bundle(PbrBundle { + mesh: meshes.add(Mesh::from(shape::Plane { size: 5.0 })), + material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()), + ..default() + }); + // cube + // Assign vertex colors based on vertex positions + let mut colorful_cube = Mesh::from(shape::Cube { size: 1.0 }); + if let Some(VertexAttributeValues::Float32x3(positions)) = + colorful_cube.attribute(Mesh::ATTRIBUTE_POSITION) + { + let colors: Vec<[f32; 4]> = positions + .iter() + .map(|[r, g, b]| [(1. - *r) / 2., (1. - *g) / 2., (1. - *b) / 2., 1.]) + .collect(); + colorful_cube.insert_attribute(Mesh::ATTRIBUTE_COLOR, colors); + } + commands.spawn_bundle(PbrBundle { + mesh: meshes.add(colorful_cube), + // This is the default color, but note that vertex colors are + // multiplied by the base color, so you'll likely want this to be + // white if using vertex colors. + material: materials.add(Color::rgb(1., 1., 1.).into()), + transform: Transform::from_xyz(0.0, 0.5, 0.0), + ..default() + }); + // light + commands.spawn_bundle(PointLightBundle { + point_light: PointLight { + intensity: 1500.0, + shadows_enabled: true, + ..default() + }, + transform: Transform::from_xyz(4.0, 8.0, 4.0), + ..default() + }); + // camera + commands.spawn_bundle(PerspectiveCameraBundle { + transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), + ..default() + }); +} diff --git a/examples/README.md b/examples/README.md index 000b0ce4ae858..cea3d7f251b4b 100644 --- a/examples/README.md +++ b/examples/README.md @@ -115,6 +115,7 @@ Example | File | Description `spherical_area_lights` | [`3d/spherical_area_lights.rs`](./3d/spherical_area_lights.rs) | Demonstrates how point light radius values affect light behavior. `texture` | [`3d/texture.rs`](./3d/texture.rs) | Shows configuration of texture materials `update_gltf_scene` | [`3d/update_gltf_scene.rs`](./3d/update_gltf_scene.rs) | Update a scene from a gltf file, either by spawning the scene as a child of another entity, or by accessing the entities of the scene +`vertex_colors` | [`3d/vertex_colors.rs`](./3d/vertex_colors.rs) | Shows the use of vertex colors `wireframe` | [`3d/wireframe.rs`](./3d/wireframe.rs) | Showcases wireframe rendering ## Animation