diff --git a/crates/bevy_pbr/src/pbr_material.rs b/crates/bevy_pbr/src/pbr_material.rs index 47c861c1557898..f66fc80e3f249a 100644 --- a/crates/bevy_pbr/src/pbr_material.rs +++ b/crates/bevy_pbr/src/pbr_material.rs @@ -152,11 +152,13 @@ pub struct StandardMaterial { /// - Vertex normals /// /// Tangents do not have to be stored in your model, - /// they can be generated using the [`Mesh::generate_tangents`] method. + /// they can be generated using the [`Mesh::generate_tangents`] or + /// [`Mesh::with_generated_tangents`] methods. /// If your material has a normal map, but still renders as a flat surface, /// make sure your meshes have their tangents set. /// /// [`Mesh::generate_tangents`]: bevy_render::mesh::Mesh::generate_tangents + /// [`Mesh::with_generated_tangents`]: bevy_render::mesh::Mesh::with_generated_tangents #[texture(9)] #[sampler(10)] #[dependency] diff --git a/crates/bevy_render/src/mesh/mesh/mod.rs b/crates/bevy_render/src/mesh/mesh/mod.rs index f40318e15d27b7..7f92c3bcd19f8c 100644 --- a/crates/bevy_render/src/mesh/mesh/mod.rs +++ b/crates/bevy_render/src/mesh/mesh/mod.rs @@ -49,32 +49,32 @@ pub const VERTEX_ATTRIBUTE_BUFFER_ID: u64 = 10; /// # use bevy_render::mesh::{Mesh, Indices}; /// # use bevy_render::render_resource::PrimitiveTopology; /// fn create_simple_parallelogram() -> Mesh { -/// // Create a new mesh, add 4 vertices, each with its own position attribute (coordinate in -/// // 3D space), for each of the corners of the parallelogram. -/// let mut mesh = Mesh::new(PrimitiveTopology::TriangleList); -/// mesh.insert_attribute( -/// Mesh::ATTRIBUTE_POSITION, -/// vec![[0.0, 0.0, 0.0], [1.0, 2.0, 0.0], [2.0, 2.0, 0.0], [1.0, 0.0, 0.0]] -/// ); -/// // Assign a UV coordinate to each vertex. -/// mesh.insert_attribute( -/// Mesh::ATTRIBUTE_UV_0, -/// vec![[0.0, 1.0], [0.5, 0.0], [1.0, 0.0], [0.5, 1.0]] -/// ); -/// // Assign normals (everything points outwards) -/// mesh.insert_attribute( -/// Mesh::ATTRIBUTE_NORMAL, -/// vec![[0.0, 0.0, 1.0], [0.0, 0.0, 1.0], [0.0, 0.0, 1.0], [0.0, 0.0, 1.0]] -/// ); -/// // After defining all the vertices and their attributes, build each triangle using the -/// // indices of the vertices that make it up in a counter-clockwise order. -/// mesh.set_indices(Some(Indices::U32(vec![ -/// // First triangle -/// 0, 3, 1, -/// // Second triangle -/// 1, 3, 2 -/// ]))); -/// mesh +/// // Create a new mesh using a triangle list topology, where each set of 3 vertices composes a triangle. +/// Mesh::new(PrimitiveTopology::TriangleList) +/// // Add 4 vertices, each with its own position attribute (coordinate in +/// // 3D space), for each of the corners of the parallelogram. +/// .with_inserted_attribute( +/// Mesh::ATTRIBUTE_POSITION, +/// vec![[0.0, 0.0, 0.0], [1.0, 2.0, 0.0], [2.0, 2.0, 0.0], [1.0, 0.0, 0.0]] +/// ) +/// // Assign a UV coordinate to each vertex. +/// .with_inserted_attribute( +/// Mesh::ATTRIBUTE_UV_0, +/// vec![[0.0, 1.0], [0.5, 0.0], [1.0, 0.0], [0.5, 1.0]] +/// ) +/// // Assign normals (everything points outwards) +/// .with_inserted_attribute( +/// Mesh::ATTRIBUTE_NORMAL, +/// vec![[0.0, 0.0, 1.0], [0.0, 0.0, 1.0], [0.0, 0.0, 1.0], [0.0, 0.0, 1.0]] +/// ) +/// // After defining all the vertices and their attributes, build each triangle using the +/// // indices of the vertices that make it up in a counter-clockwise order. +/// .with_indices(Some(Indices::U32(vec![ +/// // First triangle +/// 0, 3, 1, +/// // Second triangle +/// 1, 3, 2 +/// ]))) /// } /// ``` /// @@ -126,16 +126,18 @@ pub struct Mesh { } impl Mesh { - /// Where the vertex is located in space. Use in conjunction with [`Mesh::insert_attribute`]. + /// Where the vertex is located in space. Use in conjunction with [`Mesh::insert_attribute`] + /// or [`Mesh::with_inserted_attribute`]. pub const ATTRIBUTE_POSITION: MeshVertexAttribute = MeshVertexAttribute::new("Vertex_Position", 0, VertexFormat::Float32x3); /// The direction the vertex normal is facing in. - /// Use in conjunction with [`Mesh::insert_attribute`]. + /// Use in conjunction with [`Mesh::insert_attribute`] or [`Mesh::with_inserted_attribute`]. pub const ATTRIBUTE_NORMAL: MeshVertexAttribute = MeshVertexAttribute::new("Vertex_Normal", 1, VertexFormat::Float32x3); - /// Texture coordinates for the vertex. Use in conjunction with [`Mesh::insert_attribute`]. + /// Texture coordinates for the vertex. Use in conjunction with [`Mesh::insert_attribute`] + /// or [`Mesh::with_inserted_attribute`]. /// /// Values are generally between 0. and 1., with `StandardMaterial` and `ColorMaterial` /// `[0.,0.]` is the top left of the texture, and [1.,1.] the bottom-right. @@ -147,7 +149,7 @@ impl Mesh { MeshVertexAttribute::new("Vertex_Uv", 2, VertexFormat::Float32x2); /// Alternate texture coordinates for the vertex. Use in conjunction with - /// [`Mesh::insert_attribute`]. + /// [`Mesh::insert_attribute`] or [`Mesh::with_inserted_attribute`]. /// /// Typically, these are used for lightmaps, textures that provide /// precomputed illumination. @@ -155,19 +157,23 @@ impl Mesh { MeshVertexAttribute::new("Vertex_Uv_1", 3, VertexFormat::Float32x2); /// The direction of the vertex tangent. Used for normal mapping. - /// Usually generated with [`generate_tangents`](Mesh::generate_tangents). + /// Usually generated with [`generate_tangents`](Mesh::generate_tangents) or + /// [`with_generated_tangents`](Mesh::with_generated_tangents). pub const ATTRIBUTE_TANGENT: MeshVertexAttribute = MeshVertexAttribute::new("Vertex_Tangent", 4, VertexFormat::Float32x4); - /// Per vertex coloring. Use in conjunction with [`Mesh::insert_attribute`]. + /// Per vertex coloring. Use in conjunction with [`Mesh::insert_attribute`] + /// or [`Mesh::with_inserted_attribute`]. pub const ATTRIBUTE_COLOR: MeshVertexAttribute = MeshVertexAttribute::new("Vertex_Color", 5, VertexFormat::Float32x4); - /// Per vertex joint transform matrix weight. Use in conjunction with [`Mesh::insert_attribute`]. + /// Per vertex joint transform matrix weight. Use in conjunction with [`Mesh::insert_attribute`] + /// or [`Mesh::with_inserted_attribute`]. pub const ATTRIBUTE_JOINT_WEIGHT: MeshVertexAttribute = MeshVertexAttribute::new("Vertex_JointWeight", 6, VertexFormat::Float32x4); - /// Per vertex joint transform matrix index. Use in conjunction with [`Mesh::insert_attribute`]. + /// Per vertex joint transform matrix index. Use in conjunction with [`Mesh::insert_attribute`] + /// or [`Mesh::with_inserted_attribute`]. pub const ATTRIBUTE_JOINT_INDEX: MeshVertexAttribute = MeshVertexAttribute::new("Vertex_JointIndex", 7, VertexFormat::Uint16x4); @@ -224,6 +230,24 @@ impl Mesh { .insert(attribute.id, MeshAttributeData { attribute, values }); } + /// Consumes the mesh and returns a mesh with data set for a vertex attribute (position, normal etc.). + /// The name will often be one of the associated constants such as [`Mesh::ATTRIBUTE_POSITION`]. + /// + /// (Alternatively, you can use [`Mesh::insert_attribute`] to mutate an existing mesh in-place) + /// + /// # Panics + /// Panics when the format of the values does not match the attribute's format. + #[must_use] + #[inline] + pub fn with_inserted_attribute( + mut self, + attribute: MeshVertexAttribute, + values: impl Into, + ) -> Self { + self.insert_attribute(attribute, values); + self + } + /// Removes the data for a vertex attribute pub fn remove_attribute( &mut self, @@ -234,6 +258,15 @@ impl Mesh { .map(|data| data.values) } + /// Consumes the mesh and returns a mesh without the data for a vertex attribute + /// + /// (Alternatively, you can use [`Mesh::remove_attribute`] to mutate an existing mesh in-place) + #[must_use] + pub fn with_removed_attribute(mut self, attribute: impl Into) -> Self { + self.remove_attribute(attribute); + self + } + #[inline] pub fn contains_attribute(&self, id: impl Into) -> bool { self.attributes.contains_key(&id.into()) @@ -283,6 +316,18 @@ impl Mesh { self.indices = indices; } + /// Consumes the mesh and returns a mesh with the given vertex indices. They describe how triangles + /// are constructed out of the vertex attributes and are therefore only useful for the + /// [`PrimitiveTopology`] variants that use triangles. + /// + /// (Alternatively, you can use [`Mesh::set_indices`] to mutate an existing mesh in-place) + #[must_use] + #[inline] + pub fn with_indices(mut self, indices: Option) -> Self { + self.set_indices(indices); + self + } + /// Retrieves the vertex `indices` of the mesh. #[inline] pub fn indices(&self) -> Option<&Indices> { @@ -436,6 +481,18 @@ impl Mesh { } } + /// Consumes the mesh and returns a mesh with no shared vertices. + /// + /// This can dramatically increase the vertex count, so make sure this is what you want. + /// Does nothing if no [Indices] are set. + /// + /// (Alternatively, you can use [`Mesh::duplicate_vertices`] to mutate an existing mesh in-place) + #[must_use] + pub fn with_duplicated_vertices(mut self) -> Self { + self.duplicate_vertices(); + self + } + /// Calculates the [`Mesh::ATTRIBUTE_NORMAL`] of a mesh. /// /// # Panics @@ -465,6 +522,20 @@ impl Mesh { self.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals); } + /// Consumes the mesh and returns a mesh with calculated [`Mesh::ATTRIBUTE_NORMAL`]. + /// + /// (Alternatively, you can use [`Mesh::compute_flat_normals`] to mutate an existing mesh in-place) + /// + /// # Panics + /// Panics if [`Indices`] are set or [`Mesh::ATTRIBUTE_POSITION`] is not of type `float3` or + /// if the mesh has any other topology than [`PrimitiveTopology::TriangleList`]. + /// Consider calling [`Mesh::with_duplicated_vertices`] or export your mesh with normal attributes. + #[must_use] + pub fn with_computed_flat_normals(mut self) -> Self { + self.compute_flat_normals(); + self + } + /// Generate tangents for the mesh using the `mikktspace` algorithm. /// /// Sets the [`Mesh::ATTRIBUTE_TANGENT`] attribute if successful. @@ -475,6 +546,18 @@ impl Mesh { Ok(()) } + /// Consumes the mesh and returns a mesh with tangents generated using the `mikktspace` algorithm. + /// + /// The resulting mesh will have the [`Mesh::ATTRIBUTE_TANGENT`] attribute if successful. + /// + /// (Alternatively, you can use [`Mesh::generate_tangents`] to mutate an existing mesh in-place) + /// + /// Requires a [`PrimitiveTopology::TriangleList`] topology and the [`Mesh::ATTRIBUTE_POSITION`], [`Mesh::ATTRIBUTE_NORMAL`] and [`Mesh::ATTRIBUTE_UV_0`] attributes set. + pub fn with_generated_tangents(mut self) -> Result { + self.generate_tangents()?; + Ok(self) + } + /// Compute the Axis-Aligned Bounding Box of the mesh vertices in model space pub fn compute_aabb(&self) -> Option { let Some(VertexAttributeValues::Float32x3(values)) = @@ -498,11 +581,34 @@ impl Mesh { self.morph_targets = Some(morph_targets); } + /// Consumes the mesh and returns a mesh with the given [morph targets]. + /// + /// This requires a "morph target image". See [`MorphTargetImage`](crate::mesh::morph::MorphTargetImage) for info. + /// + /// (Alternatively, you can use [`Mesh::set_morph_targets`] to mutate an existing mesh in-place) + /// + /// [morph targets]: https://en.wikipedia.org/wiki/Morph_target_animation + #[must_use] + pub fn with_morph_targets(mut self, morph_targets: Handle) -> Self { + self.set_morph_targets(morph_targets); + self + } + /// Sets the names of each morph target. This should correspond to the order of the morph targets in `set_morph_targets`. pub fn set_morph_target_names(&mut self, names: Vec) { self.morph_target_names = Some(names); } + /// Consumes the mesh and returns a mesh with morph target names. + /// Names should correspond to the order of the morph targets in `set_morph_targets`. + /// + /// (Alternatively, you can use [`Mesh::set_morph_target_names`] to mutate an existing mesh in-place) + #[must_use] + pub fn with_morph_target_names(mut self, names: Vec) -> Self { + self.set_morph_target_names(names); + self + } + /// Gets a list of all morph target names, if they exist. pub fn morph_target_names(&self) -> Option<&[String]> { self.morph_target_names.as_deref() @@ -1123,7 +1229,7 @@ mod tests { #[test] #[should_panic] fn panic_invalid_format() { - let mut mesh = Mesh::new(PrimitiveTopology::TriangleList); - mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, vec![[0.0, 0.0, 0.0]]); + let _mesh = Mesh::new(PrimitiveTopology::TriangleList) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, vec![[0.0, 0.0, 0.0]]); } } diff --git a/crates/bevy_render/src/mesh/shape/capsule.rs b/crates/bevy_render/src/mesh/shape/capsule.rs index 327471bb5a5102..d438ed28bc3eeb 100644 --- a/crates/bevy_render/src/mesh/shape/capsule.rs +++ b/crates/bevy_render/src/mesh/shape/capsule.rs @@ -364,11 +364,10 @@ impl From for Mesh { assert_eq!(vs.len(), vert_len); assert_eq!(tris.len(), fs_len); - let mut mesh = Mesh::new(PrimitiveTopology::TriangleList); - mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, vs); - mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, vns); - mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, vts); - mesh.set_indices(Some(Indices::U32(tris))); - mesh + Mesh::new(PrimitiveTopology::TriangleList) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, vs) + .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, vns) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, vts) + .with_indices(Some(Indices::U32(tris))) } } diff --git a/crates/bevy_render/src/mesh/shape/cylinder.rs b/crates/bevy_render/src/mesh/shape/cylinder.rs index cac101caa19943..a4d517ac739523 100644 --- a/crates/bevy_render/src/mesh/shape/cylinder.rs +++ b/crates/bevy_render/src/mesh/shape/cylinder.rs @@ -118,11 +118,10 @@ impl From for Mesh { build_cap(true); build_cap(false); - let mut mesh = Mesh::new(PrimitiveTopology::TriangleList); - mesh.set_indices(Some(Indices::U32(indices))); - mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions); - mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals); - mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs); - mesh + Mesh::new(PrimitiveTopology::TriangleList) + .with_indices(Some(Indices::U32(indices))) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) + .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) } } diff --git a/crates/bevy_render/src/mesh/shape/icosphere.rs b/crates/bevy_render/src/mesh/shape/icosphere.rs index 852ae9eb126322..457ea0f82661dc 100644 --- a/crates/bevy_render/src/mesh/shape/icosphere.rs +++ b/crates/bevy_render/src/mesh/shape/icosphere.rs @@ -103,11 +103,10 @@ impl TryFrom for Mesh { let indices = Indices::U32(indices); - let mut mesh = Mesh::new(PrimitiveTopology::TriangleList); - mesh.set_indices(Some(indices)); - mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, points); - mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals); - mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs); - Ok(mesh) + Ok(Mesh::new(PrimitiveTopology::TriangleList) + .with_indices(Some(indices)) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, points) + .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs)) } } diff --git a/crates/bevy_render/src/mesh/shape/mod.rs b/crates/bevy_render/src/mesh/shape/mod.rs index 85a093d2774338..c9f6b9e1492bf9 100644 --- a/crates/bevy_render/src/mesh/shape/mod.rs +++ b/crates/bevy_render/src/mesh/shape/mod.rs @@ -120,12 +120,11 @@ impl From for Mesh { 20, 21, 22, 22, 23, 20, // bottom ]); - let mut mesh = Mesh::new(PrimitiveTopology::TriangleList); - mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions); - mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals); - mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs); - mesh.set_indices(Some(indices)); - mesh + Mesh::new(PrimitiveTopology::TriangleList) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) + .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) + .with_indices(Some(indices)) } } @@ -173,12 +172,11 @@ impl From for Mesh { let normals: Vec<_> = vertices.iter().map(|(_, n, _)| *n).collect(); let uvs: Vec<_> = vertices.iter().map(|(_, _, uv)| *uv).collect(); - let mut mesh = Mesh::new(PrimitiveTopology::TriangleList); - mesh.set_indices(Some(indices)); - mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions); - mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals); - mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs); - mesh + Mesh::new(PrimitiveTopology::TriangleList) + .with_indices(Some(indices)) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) + .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) } } @@ -255,12 +253,11 @@ impl From for Mesh { } } - let mut mesh = Mesh::new(PrimitiveTopology::TriangleList); - mesh.set_indices(Some(Indices::U32(indices))); - mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions); - mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals); - mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs); - mesh + Mesh::new(PrimitiveTopology::TriangleList) + .with_indices(Some(Indices::U32(indices))) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) + .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) } } diff --git a/crates/bevy_render/src/mesh/shape/regular_polygon.rs b/crates/bevy_render/src/mesh/shape/regular_polygon.rs index b37d8ad633d3cc..c2e86368b15f3c 100644 --- a/crates/bevy_render/src/mesh/shape/regular_polygon.rs +++ b/crates/bevy_render/src/mesh/shape/regular_polygon.rs @@ -53,12 +53,11 @@ impl From for Mesh { indices.extend_from_slice(&[0, i + 1, i]); } - let mut mesh = Mesh::new(PrimitiveTopology::TriangleList); - mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions); - mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals); - mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs); - mesh.set_indices(Some(Indices::U32(indices))); - mesh + Mesh::new(PrimitiveTopology::TriangleList) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) + .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) + .with_indices(Some(Indices::U32(indices))) } } diff --git a/crates/bevy_render/src/mesh/shape/torus.rs b/crates/bevy_render/src/mesh/shape/torus.rs index f22b3c7571114c..5254fcceebc013 100644 --- a/crates/bevy_render/src/mesh/shape/torus.rs +++ b/crates/bevy_render/src/mesh/shape/torus.rs @@ -84,11 +84,10 @@ impl From for Mesh { } } - let mut mesh = Mesh::new(PrimitiveTopology::TriangleList); - mesh.set_indices(Some(Indices::U32(indices))); - mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, positions); - mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals); - mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs); - mesh + Mesh::new(PrimitiveTopology::TriangleList) + .with_indices(Some(Indices::U32(indices))) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) + .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) } } diff --git a/crates/bevy_render/src/mesh/shape/uvsphere.rs b/crates/bevy_render/src/mesh/shape/uvsphere.rs index ccce754e564f2c..b6b89ebc401576 100644 --- a/crates/bevy_render/src/mesh/shape/uvsphere.rs +++ b/crates/bevy_render/src/mesh/shape/uvsphere.rs @@ -80,11 +80,10 @@ impl From for Mesh { } } - let mut mesh = Mesh::new(PrimitiveTopology::TriangleList); - mesh.set_indices(Some(Indices::U32(indices))); - mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, vertices); - mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals); - mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs); - mesh + Mesh::new(PrimitiveTopology::TriangleList) + .with_indices(Some(Indices::U32(indices))) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, vertices) + .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals) + .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs) } } diff --git a/examples/3d/generate_custom_mesh.rs b/examples/3d/generate_custom_mesh.rs index a4aa0250280776..a5be376f0719e9 100644 --- a/examples/3d/generate_custom_mesh.rs +++ b/examples/3d/generate_custom_mesh.rs @@ -118,11 +118,10 @@ fn input_handler( } } +#[rustfmt::skip] fn create_cube_mesh() -> Mesh { - let mut cube_mesh = Mesh::new(PrimitiveTopology::TriangleList); - - #[rustfmt::skip] - cube_mesh.insert_attribute( + Mesh::new(PrimitiveTopology::TriangleList) + .with_inserted_attribute( Mesh::ATTRIBUTE_POSITION, // Each array is an [x, y, z] coordinate in local space. // Meshes always rotate around their local [0, 0, 0] when a rotation is applied to their Transform. @@ -159,14 +158,12 @@ fn create_cube_mesh() -> Mesh { [0.5, 0.5, -0.5], [0.5, -0.5, -0.5], ], - ); - + ) // Set-up UV coordinated to point to the upper (V < 0.5), "dirt+grass" part of the texture. // Take a look at the custom image (assets/textures/array_texture.png) // so the UV coords will make more sense // Note: (0.0, 0.0) = Top-Left in UV mapping, (1.0, 1.0) = Bottom-Right in UV mapping - #[rustfmt::skip] - cube_mesh.insert_attribute( + .with_inserted_attribute( Mesh::ATTRIBUTE_UV_0, vec![ // Assigning the UV coords for the top side. @@ -175,21 +172,19 @@ fn create_cube_mesh() -> Mesh { [0.0, 0.45], [0.0, 0.25], [1.0, 0.25], [1.0, 0.45], // Assigning the UV coords for the right side. [1.0, 0.45], [0.0, 0.45], [0.0, 0.2], [1.0, 0.2], - // Assigning the UV coords for the left side. + // Assigning the UV coords for the left side. [1.0, 0.45], [0.0, 0.45], [0.0, 0.2], [1.0, 0.2], // Assigning the UV coords for the back side. [0.0, 0.45], [0.0, 0.2], [1.0, 0.2], [1.0, 0.45], // Assigning the UV coords for the forward side. [0.0, 0.45], [0.0, 0.2], [1.0, 0.2], [1.0, 0.45], ], - ); - + ) // For meshes with flat shading, normals are orthogonal (pointing out) from the direction of // the surface. // Normals are required for correct lighting calculations. // Each array represents a normalized vector, which length should be equal to 1.0. - #[rustfmt::skip] - cube_mesh.insert_attribute( + .with_inserted_attribute( Mesh::ATTRIBUTE_NORMAL, vec![ // Normals for the top side (towards +y) @@ -223,8 +218,7 @@ fn create_cube_mesh() -> Mesh { [0.0, 0.0, -1.0], [0.0, 0.0, -1.0], ], - ); - + ) // Create the triangles out of the 24 vertices we created. // To construct a square, we need 2 triangles, therefore 12 triangles in total. // To construct a triangle, we need the indices of its 3 defined vertices, adding them one @@ -232,17 +226,14 @@ fn create_cube_mesh() -> Mesh { // should appear counter-clockwise from the front of the triangle, in this case from outside the cube). // Read more about how to correctly build a mesh manually in the Bevy documentation of a Mesh, // further examples and the implementation of the built-in shapes. - #[rustfmt::skip] - cube_mesh.set_indices(Some(Indices::U32(vec![ + .with_indices(Some(Indices::U32(vec![ 0,3,1 , 1,3,2, // triangles making up the top (+y) facing side. - 4,5,7 , 5,6,7, // bottom (-y) + 4,5,7 , 5,6,7, // bottom (-y) 8,11,9 , 9,11,10, // right (+x) 12,13,15 , 13,14,15, // left (-x) 16,19,17 , 17,19,18, // back (+z) 20,21,23 , 21,22,23, // forward (-z) - ]))); - - cube_mesh + ]))) } // Function that changes the UV mapping of the mesh, to apply the other texture. diff --git a/examples/3d/lines.rs b/examples/3d/lines.rs index 9dc3caba87b828..4a71bd78ae932f 100644 --- a/examples/3d/lines.rs +++ b/examples/3d/lines.rs @@ -92,13 +92,13 @@ pub struct LineList { impl From for Mesh { fn from(line: LineList) -> Self { + let vertices: Vec<_> = line.lines.into_iter().flat_map(|(a, b)| [a, b]).collect(); + // This tells wgpu that the positions are list of lines // where every pair is a start and end point - let mut mesh = Mesh::new(PrimitiveTopology::LineList); - - let vertices: Vec<_> = line.lines.into_iter().flat_map(|(a, b)| [a, b]).collect(); - mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, vertices); - mesh + Mesh::new(PrimitiveTopology::LineList) + // Add the vertices positions as an attribute + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, vertices) } } @@ -112,9 +112,8 @@ impl From for Mesh { fn from(line: LineStrip) -> Self { // This tells wgpu that the positions are a list of points // where a line will be drawn between each consecutive point - let mut mesh = Mesh::new(PrimitiveTopology::LineStrip); - - mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, line.points); - mesh + Mesh::new(PrimitiveTopology::LineStrip) + // Add the point positions as an attribute + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, line.points) } } diff --git a/examples/3d/parallax_mapping.rs b/examples/3d/parallax_mapping.rs index f30ae3c42e4113..2061d5b65041b0 100644 --- a/examples/3d/parallax_mapping.rs +++ b/examples/3d/parallax_mapping.rs @@ -264,12 +264,6 @@ fn setup( ..default() }); - let mut cube: Mesh = shape::Cube { size: 1.0 }.into(); - - // NOTE: for normal maps and depth maps to work, the mesh - // needs tangents generated. - cube.generate_tangents().unwrap(); - let parallax_depth_scale = TargetDepth::default().0; let max_parallax_layer_count = TargetLayers::default().0.exp2(); let parallax_mapping_method = CurrentMethod::default(); @@ -287,16 +281,24 @@ fn setup( }); commands.spawn(( PbrBundle { - mesh: meshes.add(cube), + mesh: meshes.add( + // NOTE: for normal maps and depth maps to work, the mesh + // needs tangents generated. + Mesh::from(shape::Cube { size: 1.0 }) + .with_generated_tangents() + .unwrap(), + ), material: parallax_material.clone_weak(), ..default() }, Spin { speed: 0.3 }, )); - let mut background_cube: Mesh = shape::Cube { size: 40.0 }.into(); - background_cube.generate_tangents().unwrap(); - let background_cube = meshes.add(background_cube); + let background_cube = meshes.add( + Mesh::from(shape::Cube { size: 40.0 }) + .with_generated_tangents() + .unwrap(), + ); let background_cube_bundle = |translation| { ( diff --git a/examples/animation/custom_skinned_mesh.rs b/examples/animation/custom_skinned_mesh.rs index 62918473dfb9ef..7f349e28461000 100644 --- a/examples/animation/custom_skinned_mesh.rs +++ b/examples/animation/custom_skinned_mesh.rs @@ -52,68 +52,68 @@ fn setup( ])); // Create a mesh - let mut mesh = Mesh::new(PrimitiveTopology::TriangleList); - // Set mesh vertex positions - mesh.insert_attribute( - Mesh::ATTRIBUTE_POSITION, - vec![ - [0.0, 0.0, 0.0], - [1.0, 0.0, 0.0], - [0.0, 0.5, 0.0], - [1.0, 0.5, 0.0], - [0.0, 1.0, 0.0], - [1.0, 1.0, 0.0], - [0.0, 1.5, 0.0], - [1.0, 1.5, 0.0], - [0.0, 2.0, 0.0], - [1.0, 2.0, 0.0], - ], - ); - // Set mesh vertex normals - mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, vec![[0.0, 0.0, 1.0]; 10]); - // Set mesh vertex joint indices for mesh skinning. - // Each vertex gets 4 indices used to address the `JointTransforms` array in the vertex shader - // as well as `SkinnedMeshJoint` array in the `SkinnedMesh` component. - // This means that a maximum of 4 joints can affect a single vertex. - mesh.insert_attribute( - Mesh::ATTRIBUTE_JOINT_INDEX, - // Need to be explicit here as [u16; 4] could be either Uint16x4 or Unorm16x4. - VertexAttributeValues::Uint16x4(vec![ - [0, 0, 0, 0], - [0, 0, 0, 0], - [0, 1, 0, 0], - [0, 1, 0, 0], - [0, 1, 0, 0], - [0, 1, 0, 0], - [0, 1, 0, 0], - [0, 1, 0, 0], - [0, 1, 0, 0], - [0, 1, 0, 0], - ]), - ); - // Set mesh vertex joint weights for mesh skinning. - // Each vertex gets 4 joint weights corresponding to the 4 joint indices assigned to it. - // The sum of these weights should equal to 1. - mesh.insert_attribute( - Mesh::ATTRIBUTE_JOINT_WEIGHT, - vec![ - [1.00, 0.00, 0.0, 0.0], - [1.00, 0.00, 0.0, 0.0], - [0.75, 0.25, 0.0, 0.0], - [0.75, 0.25, 0.0, 0.0], - [0.50, 0.50, 0.0, 0.0], - [0.50, 0.50, 0.0, 0.0], - [0.25, 0.75, 0.0, 0.0], - [0.25, 0.75, 0.0, 0.0], - [0.00, 1.00, 0.0, 0.0], - [0.00, 1.00, 0.0, 0.0], - ], - ); - // Tell bevy to construct triangles from a list of vertex indices, - // where each 3 vertex indices form an triangle. - mesh.set_indices(Some(Indices::U16(vec![ - 0, 1, 3, 0, 3, 2, 2, 3, 5, 2, 5, 4, 4, 5, 7, 4, 7, 6, 6, 7, 9, 6, 9, 8, - ]))); + let mesh = Mesh::new(PrimitiveTopology::TriangleList) + // Set mesh vertex positions + .with_inserted_attribute( + Mesh::ATTRIBUTE_POSITION, + vec![ + [0.0, 0.0, 0.0], + [1.0, 0.0, 0.0], + [0.0, 0.5, 0.0], + [1.0, 0.5, 0.0], + [0.0, 1.0, 0.0], + [1.0, 1.0, 0.0], + [0.0, 1.5, 0.0], + [1.0, 1.5, 0.0], + [0.0, 2.0, 0.0], + [1.0, 2.0, 0.0], + ], + ) + // Set mesh vertex normals + .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, vec![[0.0, 0.0, 1.0]; 10]) + // Set mesh vertex joint indices for mesh skinning. + // Each vertex gets 4 indices used to address the `JointTransforms` array in the vertex shader + // as well as `SkinnedMeshJoint` array in the `SkinnedMesh` component. + // This means that a maximum of 4 joints can affect a single vertex. + .with_inserted_attribute( + Mesh::ATTRIBUTE_JOINT_INDEX, + // Need to be explicit here as [u16; 4] could be either Uint16x4 or Unorm16x4. + VertexAttributeValues::Uint16x4(vec![ + [0, 0, 0, 0], + [0, 0, 0, 0], + [0, 1, 0, 0], + [0, 1, 0, 0], + [0, 1, 0, 0], + [0, 1, 0, 0], + [0, 1, 0, 0], + [0, 1, 0, 0], + [0, 1, 0, 0], + [0, 1, 0, 0], + ]), + ) + // Set mesh vertex joint weights for mesh skinning. + // Each vertex gets 4 joint weights corresponding to the 4 joint indices assigned to it. + // The sum of these weights should equal to 1. + .with_inserted_attribute( + Mesh::ATTRIBUTE_JOINT_WEIGHT, + vec![ + [1.00, 0.00, 0.0, 0.0], + [1.00, 0.00, 0.0, 0.0], + [0.75, 0.25, 0.0, 0.0], + [0.75, 0.25, 0.0, 0.0], + [0.50, 0.50, 0.0, 0.0], + [0.50, 0.50, 0.0, 0.0], + [0.25, 0.75, 0.0, 0.0], + [0.25, 0.75, 0.0, 0.0], + [0.00, 1.00, 0.0, 0.0], + [0.00, 1.00, 0.0, 0.0], + ], + ) + // Tell bevy to construct triangles from a list of vertex indices, + // where each 3 vertex indices form an triangle. + .with_indices(Some(Indices::U16(vec![ + 0, 1, 3, 0, 3, 2, 2, 3, 5, 2, 5, 4, 4, 5, 7, 4, 7, 6, 6, 7, 9, 6, 9, 8, + ]))); let mesh = meshes.add(mesh); diff --git a/examples/shader/custom_vertex_attribute.rs b/examples/shader/custom_vertex_attribute.rs index c61c81b3b8ad05..0411af15a76348 100644 --- a/examples/shader/custom_vertex_attribute.rs +++ b/examples/shader/custom_vertex_attribute.rs @@ -31,12 +31,13 @@ fn setup( mut meshes: ResMut>, mut materials: ResMut>, ) { - let mut mesh = Mesh::from(shape::Cube { size: 1.0 }); - mesh.insert_attribute( - ATTRIBUTE_BLEND_COLOR, - // The cube mesh has 24 vertices (6 faces, 4 vertices per face), so we insert one BlendColor for each - vec![[1.0, 0.0, 0.0, 1.0]; 24], - ); + let mesh = Mesh::from(shape::Cube { size: 1.0 }) + // Sets the custom attribute + .with_inserted_attribute( + ATTRIBUTE_BLEND_COLOR, + // The cube mesh has 24 vertices (6 faces, 4 vertices per face), so we insert one BlendColor for each + vec![[1.0, 0.0, 0.0, 1.0]; 24], + ); // cube commands.spawn(MaterialMeshBundle {