Skip to content

Commit

Permalink
Improve Mesh documentation (#9061)
Browse files Browse the repository at this point in the history
# Objective

This PR continues #8885

It aims to improve the `Mesh` documentation in the following ways:
- Put everything at the "top level" instead of the "impl".
- Explain better what is a Mesh, how it can be created, and that it can
be edited.
- Explain it can be used with a `Material`, and mention
`StandardMaterial`, `PbrBundle`, `ColorMaterial`, and
`ColorMesh2dBundle` since those cover most cases
- Mention the glTF/Bevy vocabulary discrepancy for "Mesh"
- Add an image for the example
- Various nitpicky modifications

## Note

- The image I added is 90.3ko which I think is small enough?
- Since rustdoc doesn't allow cross-reference not in dependencies of a
subcrate [yet](rust-lang/rust#74481), I have a
lot of backtick references that are not links :(
- Since rustdoc doesn't allow linking to code in the crate (?) I put
link to github directly.
- Since rustdoc doesn't allow embed images in doc
[yet](rust-lang/rust#32104), maybe
[soon](rust-lang/rfcs#3397), I had to put only a
link to the image. I don't think it's worth adding
[embed_doc_image](https://docs.rs/embed-doc-image/latest/embed_doc_image/)
as a dependency for this.
  • Loading branch information
Selene-Amanita authored and cart committed Aug 10, 2023
1 parent 6430b56 commit 1f4b281
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 44 deletions.
Binary file added assets/docs/Mesh.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions crates/bevy_asset/src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use std::path::Path;

/// A loader for an asset source.
///
/// Types implementing this trait are used by the asset server to load assets into their respective
/// asset storages.
/// Types implementing this trait are used by the [`AssetServer`] to load assets
/// into their respective asset storages.
pub trait AssetLoader: Send + Sync + 'static {
/// Processes the asset in an asynchronous closure.
fn load<'a>(
Expand Down
3 changes: 2 additions & 1 deletion crates/bevy_gltf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ impl Plugin for GltfPlugin {
}
}

/// Representation of a loaded glTF file.
/// Representation of a loaded glTF file
/// (file loaded via the `AssetServer` with the extension `.glb` or `.gltf`).
#[derive(Debug, TypeUuid, TypePath)]
#[uuid = "5c7d5f8a-f7b0-4e45-a09e-406c0372fea2"]
pub struct Gltf {
Expand Down
118 changes: 77 additions & 41 deletions crates/bevy_render/src/mesh/mesh/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,24 @@ use wgpu::{
pub const INDEX_BUFFER_ASSET_INDEX: u64 = 0;
pub const VERTEX_ATTRIBUTE_BUFFER_ID: u64 = 10;

// TODO: allow values to be unloaded after been submitting to the GPU to conserve memory
#[derive(Debug, TypeUuid, TypePath, Clone)]
#[uuid = "8ecbac0f-f545-4473-ad43-e1f4243af51e"]
pub struct Mesh {
primitive_topology: PrimitiveTopology,
/// `std::collections::BTreeMap` with all defined vertex attributes (Positions, Normals, ...)
/// for this mesh. Attribute ids to attribute values.
/// Uses a BTreeMap because, unlike HashMap, it has a defined iteration order,
/// which allows easy stable VertexBuffers (i.e. same buffer order)
attributes: BTreeMap<MeshVertexAttributeId, MeshAttributeData>,
indices: Option<Indices>,
morph_targets: Option<Handle<Image>>,
morph_target_names: Option<Vec<String>>,
}

/// Contains geometry in the form of a mesh.
/// A 3D object made out of vertices representing triangles, lines, or points,
/// with "attribute" values for each vertex.
///
/// Meshes can be automatically generated by a bevy `AssetLoader` (generally by loading a `Gltf` file),
/// or by converting a primitive [`shape`](crate::mesh::shape) using [`into`](std::convert::Into).
/// It is also possible to create one manually.
/// They can be edited after creation.
///
/// Often meshes are automatically generated by bevy's asset loaders or primitives, such as
/// [`shape::Cube`](crate::mesh::shape::Cube) or [`shape::Box`](crate::mesh::shape::Box), but you can also construct
/// one yourself.
/// Meshes can be rendered with a `Material`, like `StandardMaterial` in `PbrBundle`
/// or `ColorMaterial` in `ColorMesh2dBundle`.
///
/// Example of constructing a mesh (to be rendered with a `StandardMaterial`):
/// A [`Mesh`] in Bevy is equivalent to a "primitive" in the glTF format, for a
/// glTF Mesh representation, see `GltfMesh`.
///
/// ## Manual creation
///
/// The following function will construct a flat mesh, to be rendered with a
/// `StandardMaterial` or `ColorMaterial`:
/// ```
/// # use bevy_render::mesh::{Mesh, Indices};
/// # use bevy_render::render_resource::PrimitiveTopology;
Expand Down Expand Up @@ -78,50 +74,90 @@ pub struct Mesh {
/// 1, 3, 2
/// ])));
/// mesh
/// // For further visualization, explanation, and examples see the built-in Bevy examples
/// // and the implementation of the built-in shapes.
/// }
/// ```
/// Common points of confusion:
/// - UV maps in Bevy are "flipped", (0.0, 0.0) = Top-Left (not Bot-Left like `OpenGL`)
/// - It is normal for multiple vertices to have the same position
/// attribute - it's a common technique in 3D modelling for complex UV mapping or other calculations.
///
/// To render correctly with `StandardMaterial` a mesh needs to have properly defined:
/// - [`UVs`](Mesh::ATTRIBUTE_UV_0): Bevy needs to know how to map a texture onto the mesh.
/// - [`Normals`](Mesh::ATTRIBUTE_NORMAL): Bevy needs to know how light interacts with your mesh. ([0.0, 0.0, 1.0] is very
/// common for simple meshes because simple meshes are smooth, and they don't require complex light calculations.)
/// - Vertex winding order -
/// the default behavior is with `StandardMaterial.cull_mode` = Some([`Face::Front`](crate::render_resource::Face::Front)) which means
/// that by default Bevy would *only* render the front of each triangle, and the front
/// is the side of the triangle in which the vertices appear in a *counter-clockwise* order.
/// You can see how it looks like [here](https://github.com/bevyengine/bevy/blob/main/assets/dovs/Mesh.png),
/// used in a `PbrBundle` with a square bevy logo texture, with added axis, points,
/// lines and text for clarity.
///
/// ## Other examples
///
/// For further visualization, explanation, and examples, see the built-in Bevy examples,
/// and the [implementation of the built-in shapes](https://github.com/bevyengine/bevy/tree/main/crates/bevy_render/src/mesh/shape).
/// In particular, [generate_custom_mesh](https://github.com/bevyengine/bevy/blob/main/examples/3d/generate_custom_mesh.rs)
/// teaches you to access modify a Mesh's attributes after creating it.
///
/// ## Common points of confusion
///
/// - UV maps in Bevy start at the top-left, see [`ATTRIBUTE_UV_0`](Mesh::ATTRIBUTE_UV_0),
/// other APIs can have other conventions, `OpenGL` starts at bottom-left.
/// - It is possible and sometimes useful for multiple vertices to have the same
/// [position attribute](Mesh::ATTRIBUTE_POSITION) value,
/// it's a common technique in 3D modelling for complex UV mapping or other calculations.
///
/// ## Use with `StandardMaterial`
///
/// To render correctly with `StandardMaterial`, a mesh needs to have properly defined:
/// - [`UVs`](Mesh::ATTRIBUTE_UV_0): Bevy needs to know how to map a texture onto the mesh
/// (also true for `ColorMaterial`).
/// - [`Normals`](Mesh::ATTRIBUTE_NORMAL): Bevy needs to know how light interacts with your mesh.
/// [0.0, 0.0, 1.0] is very common for simple flat meshes on the XY plane,
/// because simple meshes are smooth and they don't require complex light calculations.
/// - Vertex winding order: by default, `StandardMaterial.cull_mode` is [`Some(Face::Back)`](crate::render_resource::Face),
/// which means that Bevy would *only* render the "front" of each triangle, which
/// is the side of the triangle from where the vertices appear in a *counter-clockwise* order.
///
// TODO: allow values to be unloaded after been submitting to the GPU to conserve memory
#[derive(Debug, TypeUuid, TypePath, Clone)]
#[uuid = "8ecbac0f-f545-4473-ad43-e1f4243af51e"]
pub struct Mesh {
primitive_topology: PrimitiveTopology,
/// `std::collections::BTreeMap` with all defined vertex attributes (Positions, Normals, ...)
/// for this mesh. Attribute ids to attribute values.
/// Uses a BTreeMap because, unlike HashMap, it has a defined iteration order,
/// which allows easy stable VertexBuffers (i.e. same buffer order)
attributes: BTreeMap<MeshVertexAttributeId, MeshAttributeData>,
indices: Option<Indices>,
morph_targets: Option<Handle<Image>>,
morph_target_names: Option<Vec<String>>,
}

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`].
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`].
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`].
///
/// 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.
/// You usually want to only use values in that range, values outside will be
/// clamped per pixel not for the vertex, "stretching" the borders of the texture.
/// This behavior can be useful in some cases, usually when the borders have only
/// one color, for example a logo, and you want to "extend" those borders.
pub const ATTRIBUTE_UV_0: MeshVertexAttribute =
MeshVertexAttribute::new("Vertex_Uv", 2, VertexFormat::Float32x2);

/// The direction of the vertex tangent. Used for normal mapping
/// The direction of the vertex tangent. Used for normal mapping.
/// Usually generated with [`generate_tangents`](Mesh::generate_tangents).
pub const ATTRIBUTE_TANGENT: MeshVertexAttribute =
MeshVertexAttribute::new("Vertex_Tangent", 3, VertexFormat::Float32x4);

/// Per vertex coloring. Use in conjunction with [`Mesh::insert_attribute`]
/// Per vertex coloring. Use in conjunction with [`Mesh::insert_attribute`].
pub const ATTRIBUTE_COLOR: MeshVertexAttribute =
MeshVertexAttribute::new("Vertex_Color", 4, 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`].
pub const ATTRIBUTE_JOINT_WEIGHT: MeshVertexAttribute =
MeshVertexAttribute::new("Vertex_JointWeight", 5, 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`].
pub const ATTRIBUTE_JOINT_INDEX: MeshVertexAttribute =
MeshVertexAttribute::new("Vertex_JointIndex", 6, VertexFormat::Uint16x4);

Expand Down

0 comments on commit 1f4b281

Please sign in to comment.