bevy_mesh/
vertex.rs

1use alloc::sync::Arc;
2use bevy_derive::EnumVariantMeta;
3use bevy_ecs::resource::Resource;
4use bevy_math::Vec3;
5#[cfg(feature = "serialize")]
6use bevy_platform::collections::HashMap;
7use bevy_platform::collections::HashSet;
8use bytemuck::cast_slice;
9use core::hash::{Hash, Hasher};
10#[cfg(feature = "serialize")]
11use serde::{Deserialize, Serialize};
12use thiserror::Error;
13use wgpu_types::{BufferAddress, VertexAttribute, VertexFormat, VertexStepMode};
14
15#[derive(Debug, Clone, Copy, PartialEq)]
16pub struct MeshVertexAttribute {
17    /// The friendly name of the vertex attribute
18    pub name: &'static str,
19
20    /// The _unique_ id of the vertex attribute. This will also determine sort ordering
21    /// when generating vertex buffers. Built-in / standard attributes will use "close to zero"
22    /// indices. When in doubt, use a random / very large u64 to avoid conflicts.
23    pub id: MeshVertexAttributeId,
24
25    /// The format of the vertex attribute.
26    pub format: VertexFormat,
27}
28
29#[cfg(feature = "serialize")]
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub(crate) struct SerializedMeshVertexAttribute {
32    pub(crate) name: String,
33    pub(crate) id: MeshVertexAttributeId,
34    pub(crate) format: VertexFormat,
35}
36
37#[cfg(feature = "serialize")]
38impl SerializedMeshVertexAttribute {
39    pub(crate) fn from_mesh_vertex_attribute(attribute: MeshVertexAttribute) -> Self {
40        Self {
41            name: attribute.name.to_string(),
42            id: attribute.id,
43            format: attribute.format,
44        }
45    }
46
47    pub(crate) fn try_into_mesh_vertex_attribute(
48        self,
49        possible_attributes: &HashMap<Box<str>, MeshVertexAttribute>,
50    ) -> Option<MeshVertexAttribute> {
51        let attr = possible_attributes.get(self.name.as_str())?;
52        if attr.id == self.id {
53            Some(*attr)
54        } else {
55            None
56        }
57    }
58}
59
60impl MeshVertexAttribute {
61    pub const fn new(name: &'static str, id: u64, format: VertexFormat) -> Self {
62        Self {
63            name,
64            id: MeshVertexAttributeId(id),
65            format,
66        }
67    }
68
69    pub const fn at_shader_location(&self, shader_location: u32) -> VertexAttributeDescriptor {
70        VertexAttributeDescriptor::new(shader_location, self.id, self.name)
71    }
72}
73
74#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
75#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
76pub struct MeshVertexAttributeId(u64);
77
78impl From<MeshVertexAttribute> for MeshVertexAttributeId {
79    fn from(attribute: MeshVertexAttribute) -> Self {
80        attribute.id
81    }
82}
83
84#[derive(Debug, Clone, Hash, Eq, PartialEq)]
85pub struct MeshVertexBufferLayout {
86    pub(crate) attribute_ids: Vec<MeshVertexAttributeId>,
87    pub(crate) layout: VertexBufferLayout,
88}
89
90impl MeshVertexBufferLayout {
91    pub fn new(attribute_ids: Vec<MeshVertexAttributeId>, layout: VertexBufferLayout) -> Self {
92        Self {
93            attribute_ids,
94            layout,
95        }
96    }
97
98    #[inline]
99    pub fn contains(&self, attribute_id: impl Into<MeshVertexAttributeId>) -> bool {
100        self.attribute_ids.contains(&attribute_id.into())
101    }
102
103    #[inline]
104    pub fn attribute_ids(&self) -> &[MeshVertexAttributeId] {
105        &self.attribute_ids
106    }
107
108    #[inline]
109    pub fn layout(&self) -> &VertexBufferLayout {
110        &self.layout
111    }
112
113    pub fn get_layout(
114        &self,
115        attribute_descriptors: &[VertexAttributeDescriptor],
116    ) -> Result<VertexBufferLayout, MissingVertexAttributeError> {
117        let mut attributes = Vec::with_capacity(attribute_descriptors.len());
118        for attribute_descriptor in attribute_descriptors {
119            if let Some(index) = self
120                .attribute_ids
121                .iter()
122                .position(|id| *id == attribute_descriptor.id)
123            {
124                let layout_attribute = &self.layout.attributes[index];
125                attributes.push(VertexAttribute {
126                    format: layout_attribute.format,
127                    offset: layout_attribute.offset,
128                    shader_location: attribute_descriptor.shader_location,
129                });
130            } else {
131                return Err(MissingVertexAttributeError {
132                    id: attribute_descriptor.id,
133                    name: attribute_descriptor.name,
134                    pipeline_type: None,
135                });
136            }
137        }
138
139        Ok(VertexBufferLayout {
140            array_stride: self.layout.array_stride,
141            step_mode: self.layout.step_mode,
142            attributes,
143        })
144    }
145}
146
147#[derive(Error, Debug)]
148#[error("Mesh is missing requested attribute: {name} ({id:?}, pipeline type: {pipeline_type:?})")]
149pub struct MissingVertexAttributeError {
150    pub pipeline_type: Option<&'static str>,
151    id: MeshVertexAttributeId,
152    name: &'static str,
153}
154
155pub struct VertexAttributeDescriptor {
156    pub shader_location: u32,
157    pub id: MeshVertexAttributeId,
158    name: &'static str,
159}
160
161impl VertexAttributeDescriptor {
162    pub const fn new(shader_location: u32, id: MeshVertexAttributeId, name: &'static str) -> Self {
163        Self {
164            shader_location,
165            id,
166            name,
167        }
168    }
169}
170
171#[derive(Debug, Clone, PartialEq)]
172pub(crate) struct MeshAttributeData {
173    pub(crate) attribute: MeshVertexAttribute,
174    pub(crate) values: VertexAttributeValues,
175}
176
177#[cfg(feature = "serialize")]
178#[derive(Debug, Clone, Serialize, Deserialize)]
179pub(crate) struct SerializedMeshAttributeData {
180    pub(crate) attribute: SerializedMeshVertexAttribute,
181    pub(crate) values: VertexAttributeValues,
182}
183
184#[cfg(feature = "serialize")]
185impl SerializedMeshAttributeData {
186    pub(crate) fn from_mesh_attribute_data(data: MeshAttributeData) -> Self {
187        Self {
188            attribute: SerializedMeshVertexAttribute::from_mesh_vertex_attribute(data.attribute),
189            values: data.values,
190        }
191    }
192
193    pub(crate) fn try_into_mesh_attribute_data(
194        self,
195        possible_attributes: &HashMap<Box<str>, MeshVertexAttribute>,
196    ) -> Option<MeshAttributeData> {
197        let attribute = self
198            .attribute
199            .try_into_mesh_vertex_attribute(possible_attributes)?;
200        Some(MeshAttributeData {
201            attribute,
202            values: self.values,
203        })
204    }
205}
206
207/// Compute a vector whose direction is the normal of the triangle formed by
208/// points a, b, c, and whose magnitude is double the area of the triangle. This
209/// is useful for computing smooth normals where the contributing normals are
210/// proportionate to the areas of the triangles as [discussed
211/// here](https://iquilezles.org/articles/normals/).
212///
213/// Question: Why double the area? Because the area of a triangle _A_ is
214/// determined by this equation:
215///
216/// _A = |(b - a) x (c - a)| / 2_
217///
218/// By computing _2 A_ we avoid a division operation, and when calculating the
219/// the sum of these vectors which are then normalized, a constant multiple has
220/// no effect.
221#[inline]
222pub fn triangle_area_normal(a: [f32; 3], b: [f32; 3], c: [f32; 3]) -> [f32; 3] {
223    let (a, b, c) = (Vec3::from(a), Vec3::from(b), Vec3::from(c));
224    (b - a).cross(c - a).into()
225}
226
227/// Compute the normal of a face made of three points: a, b, and c.
228#[inline]
229pub fn triangle_normal(a: [f32; 3], b: [f32; 3], c: [f32; 3]) -> [f32; 3] {
230    let (a, b, c) = (Vec3::from(a), Vec3::from(b), Vec3::from(c));
231    (b - a).cross(c - a).normalize_or_zero().into()
232}
233
234/// Contains an array where each entry describes a property of a single vertex.
235/// Matches the [`VertexFormats`](VertexFormat).
236#[derive(Clone, Debug, EnumVariantMeta, PartialEq)]
237#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
238pub enum VertexAttributeValues {
239    Float32(Vec<f32>),
240    Sint32(Vec<i32>),
241    Uint32(Vec<u32>),
242    Float32x2(Vec<[f32; 2]>),
243    Sint32x2(Vec<[i32; 2]>),
244    Uint32x2(Vec<[u32; 2]>),
245    Float32x3(Vec<[f32; 3]>),
246    Sint32x3(Vec<[i32; 3]>),
247    Uint32x3(Vec<[u32; 3]>),
248    Float32x4(Vec<[f32; 4]>),
249    Sint32x4(Vec<[i32; 4]>),
250    Uint32x4(Vec<[u32; 4]>),
251    Sint16x2(Vec<[i16; 2]>),
252    Snorm16x2(Vec<[i16; 2]>),
253    Uint16x2(Vec<[u16; 2]>),
254    Unorm16x2(Vec<[u16; 2]>),
255    Sint16x4(Vec<[i16; 4]>),
256    Snorm16x4(Vec<[i16; 4]>),
257    Uint16x4(Vec<[u16; 4]>),
258    Unorm16x4(Vec<[u16; 4]>),
259    Sint8x2(Vec<[i8; 2]>),
260    Snorm8x2(Vec<[i8; 2]>),
261    Uint8x2(Vec<[u8; 2]>),
262    Unorm8x2(Vec<[u8; 2]>),
263    Sint8x4(Vec<[i8; 4]>),
264    Snorm8x4(Vec<[i8; 4]>),
265    Uint8x4(Vec<[u8; 4]>),
266    Unorm8x4(Vec<[u8; 4]>),
267}
268
269impl VertexAttributeValues {
270    /// Returns the number of vertices in this [`VertexAttributeValues`]. For a single
271    /// mesh, all of the [`VertexAttributeValues`] must have the same length.
272    #[expect(
273        clippy::match_same_arms,
274        reason = "Although the `values` binding on some match arms may have matching types, each variant has different semantics; thus it's not guaranteed that they will use the same type forever."
275    )]
276    pub fn len(&self) -> usize {
277        match self {
278            VertexAttributeValues::Float32(values) => values.len(),
279            VertexAttributeValues::Sint32(values) => values.len(),
280            VertexAttributeValues::Uint32(values) => values.len(),
281            VertexAttributeValues::Float32x2(values) => values.len(),
282            VertexAttributeValues::Sint32x2(values) => values.len(),
283            VertexAttributeValues::Uint32x2(values) => values.len(),
284            VertexAttributeValues::Float32x3(values) => values.len(),
285            VertexAttributeValues::Sint32x3(values) => values.len(),
286            VertexAttributeValues::Uint32x3(values) => values.len(),
287            VertexAttributeValues::Float32x4(values) => values.len(),
288            VertexAttributeValues::Sint32x4(values) => values.len(),
289            VertexAttributeValues::Uint32x4(values) => values.len(),
290            VertexAttributeValues::Sint16x2(values) => values.len(),
291            VertexAttributeValues::Snorm16x2(values) => values.len(),
292            VertexAttributeValues::Uint16x2(values) => values.len(),
293            VertexAttributeValues::Unorm16x2(values) => values.len(),
294            VertexAttributeValues::Sint16x4(values) => values.len(),
295            VertexAttributeValues::Snorm16x4(values) => values.len(),
296            VertexAttributeValues::Uint16x4(values) => values.len(),
297            VertexAttributeValues::Unorm16x4(values) => values.len(),
298            VertexAttributeValues::Sint8x2(values) => values.len(),
299            VertexAttributeValues::Snorm8x2(values) => values.len(),
300            VertexAttributeValues::Uint8x2(values) => values.len(),
301            VertexAttributeValues::Unorm8x2(values) => values.len(),
302            VertexAttributeValues::Sint8x4(values) => values.len(),
303            VertexAttributeValues::Snorm8x4(values) => values.len(),
304            VertexAttributeValues::Uint8x4(values) => values.len(),
305            VertexAttributeValues::Unorm8x4(values) => values.len(),
306        }
307    }
308
309    /// Returns `true` if there are no vertices in this [`VertexAttributeValues`].
310    pub fn is_empty(&self) -> bool {
311        self.len() == 0
312    }
313
314    /// Returns the values as float triples if possible.
315    pub fn as_float3(&self) -> Option<&[[f32; 3]]> {
316        match self {
317            VertexAttributeValues::Float32x3(values) => Some(values),
318            _ => None,
319        }
320    }
321
322    // TODO: add vertex format as parameter here and perform type conversions
323    /// Flattens the [`VertexAttributeValues`] into a sequence of bytes. This is
324    /// useful for serialization and sending to the GPU.
325    #[expect(
326        clippy::match_same_arms,
327        reason = "Although the `values` binding on some match arms may have matching types, each variant has different semantics; thus it's not guaranteed that they will use the same type forever."
328    )]
329    pub fn get_bytes(&self) -> &[u8] {
330        match self {
331            VertexAttributeValues::Float32(values) => cast_slice(values),
332            VertexAttributeValues::Sint32(values) => cast_slice(values),
333            VertexAttributeValues::Uint32(values) => cast_slice(values),
334            VertexAttributeValues::Float32x2(values) => cast_slice(values),
335            VertexAttributeValues::Sint32x2(values) => cast_slice(values),
336            VertexAttributeValues::Uint32x2(values) => cast_slice(values),
337            VertexAttributeValues::Float32x3(values) => cast_slice(values),
338            VertexAttributeValues::Sint32x3(values) => cast_slice(values),
339            VertexAttributeValues::Uint32x3(values) => cast_slice(values),
340            VertexAttributeValues::Float32x4(values) => cast_slice(values),
341            VertexAttributeValues::Sint32x4(values) => cast_slice(values),
342            VertexAttributeValues::Uint32x4(values) => cast_slice(values),
343            VertexAttributeValues::Sint16x2(values) => cast_slice(values),
344            VertexAttributeValues::Snorm16x2(values) => cast_slice(values),
345            VertexAttributeValues::Uint16x2(values) => cast_slice(values),
346            VertexAttributeValues::Unorm16x2(values) => cast_slice(values),
347            VertexAttributeValues::Sint16x4(values) => cast_slice(values),
348            VertexAttributeValues::Snorm16x4(values) => cast_slice(values),
349            VertexAttributeValues::Uint16x4(values) => cast_slice(values),
350            VertexAttributeValues::Unorm16x4(values) => cast_slice(values),
351            VertexAttributeValues::Sint8x2(values) => cast_slice(values),
352            VertexAttributeValues::Snorm8x2(values) => cast_slice(values),
353            VertexAttributeValues::Uint8x2(values) => cast_slice(values),
354            VertexAttributeValues::Unorm8x2(values) => cast_slice(values),
355            VertexAttributeValues::Sint8x4(values) => cast_slice(values),
356            VertexAttributeValues::Snorm8x4(values) => cast_slice(values),
357            VertexAttributeValues::Uint8x4(values) => cast_slice(values),
358            VertexAttributeValues::Unorm8x4(values) => cast_slice(values),
359        }
360    }
361}
362
363impl From<&VertexAttributeValues> for VertexFormat {
364    fn from(values: &VertexAttributeValues) -> Self {
365        match values {
366            VertexAttributeValues::Float32(_) => VertexFormat::Float32,
367            VertexAttributeValues::Sint32(_) => VertexFormat::Sint32,
368            VertexAttributeValues::Uint32(_) => VertexFormat::Uint32,
369            VertexAttributeValues::Float32x2(_) => VertexFormat::Float32x2,
370            VertexAttributeValues::Sint32x2(_) => VertexFormat::Sint32x2,
371            VertexAttributeValues::Uint32x2(_) => VertexFormat::Uint32x2,
372            VertexAttributeValues::Float32x3(_) => VertexFormat::Float32x3,
373            VertexAttributeValues::Sint32x3(_) => VertexFormat::Sint32x3,
374            VertexAttributeValues::Uint32x3(_) => VertexFormat::Uint32x3,
375            VertexAttributeValues::Float32x4(_) => VertexFormat::Float32x4,
376            VertexAttributeValues::Sint32x4(_) => VertexFormat::Sint32x4,
377            VertexAttributeValues::Uint32x4(_) => VertexFormat::Uint32x4,
378            VertexAttributeValues::Sint16x2(_) => VertexFormat::Sint16x2,
379            VertexAttributeValues::Snorm16x2(_) => VertexFormat::Snorm16x2,
380            VertexAttributeValues::Uint16x2(_) => VertexFormat::Uint16x2,
381            VertexAttributeValues::Unorm16x2(_) => VertexFormat::Unorm16x2,
382            VertexAttributeValues::Sint16x4(_) => VertexFormat::Sint16x4,
383            VertexAttributeValues::Snorm16x4(_) => VertexFormat::Snorm16x4,
384            VertexAttributeValues::Uint16x4(_) => VertexFormat::Uint16x4,
385            VertexAttributeValues::Unorm16x4(_) => VertexFormat::Unorm16x4,
386            VertexAttributeValues::Sint8x2(_) => VertexFormat::Sint8x2,
387            VertexAttributeValues::Snorm8x2(_) => VertexFormat::Snorm8x2,
388            VertexAttributeValues::Uint8x2(_) => VertexFormat::Uint8x2,
389            VertexAttributeValues::Unorm8x2(_) => VertexFormat::Unorm8x2,
390            VertexAttributeValues::Sint8x4(_) => VertexFormat::Sint8x4,
391            VertexAttributeValues::Snorm8x4(_) => VertexFormat::Snorm8x4,
392            VertexAttributeValues::Uint8x4(_) => VertexFormat::Uint8x4,
393            VertexAttributeValues::Unorm8x4(_) => VertexFormat::Unorm8x4,
394        }
395    }
396}
397
398/// Describes how the vertex buffer is interpreted.
399#[derive(Default, Clone, Debug, Hash, Eq, PartialEq)]
400pub struct VertexBufferLayout {
401    /// The stride, in bytes, between elements of this buffer.
402    pub array_stride: BufferAddress,
403    /// How often this vertex buffer is "stepped" forward.
404    pub step_mode: VertexStepMode,
405    /// The list of attributes which comprise a single vertex.
406    pub attributes: Vec<VertexAttribute>,
407}
408
409impl VertexBufferLayout {
410    /// Creates a new densely packed [`VertexBufferLayout`] from an iterator of vertex formats.
411    /// Iteration order determines the `shader_location` and `offset` of the [`VertexAttributes`](VertexAttribute).
412    /// The first iterated item will have a `shader_location` and `offset` of zero.
413    /// The `array_stride` is the sum of the size of the iterated [`VertexFormats`](VertexFormat) (in bytes).
414    pub fn from_vertex_formats<T: IntoIterator<Item = VertexFormat>>(
415        step_mode: VertexStepMode,
416        vertex_formats: T,
417    ) -> Self {
418        let mut offset = 0;
419        let mut attributes = Vec::new();
420        for (shader_location, format) in vertex_formats.into_iter().enumerate() {
421            attributes.push(VertexAttribute {
422                format,
423                offset,
424                shader_location: shader_location as u32,
425            });
426            offset += format.size();
427        }
428
429        VertexBufferLayout {
430            array_stride: offset,
431            step_mode,
432            attributes,
433        }
434    }
435
436    /// Returns a [`VertexBufferLayout`] with the shader location of every attribute offset by
437    /// `location`.
438    pub fn offset_locations_by(mut self, location: u32) -> Self {
439        self.attributes.iter_mut().for_each(|attr| {
440            attr.shader_location += location;
441        });
442        self
443    }
444}
445
446/// Describes the layout of the mesh vertices in GPU memory.
447///
448/// At most one copy of a mesh vertex buffer layout ever exists in GPU memory at
449/// once. Therefore, comparing these for equality requires only a single pointer
450/// comparison, and this type's [`PartialEq`] and [`Hash`] implementations take
451/// advantage of this. To that end, this type doesn't implement
452/// [`bevy_derive::Deref`] or [`bevy_derive::DerefMut`] in order to reduce the
453/// possibility of accidental deep comparisons, which would be needlessly
454/// expensive.
455#[derive(Clone, Debug)]
456pub struct MeshVertexBufferLayoutRef(pub Arc<MeshVertexBufferLayout>);
457
458/// Stores the single copy of each mesh vertex buffer layout.
459#[derive(Clone, Default, Resource)]
460pub struct MeshVertexBufferLayouts(HashSet<Arc<MeshVertexBufferLayout>>);
461
462impl MeshVertexBufferLayouts {
463    /// Inserts a new mesh vertex buffer layout in the store and returns a
464    /// reference to it, reusing the existing reference if this mesh vertex
465    /// buffer layout was already in the store.
466    pub fn insert(&mut self, layout: MeshVertexBufferLayout) -> MeshVertexBufferLayoutRef {
467        // Because the special `PartialEq` and `Hash` implementations that
468        // compare by pointer are on `MeshVertexBufferLayoutRef`, not on
469        // `Arc<MeshVertexBufferLayout>`, this compares the mesh vertex buffer
470        // structurally, not by pointer.
471        MeshVertexBufferLayoutRef(
472            self.0
473                .get_or_insert_with(&layout, |layout| Arc::new(layout.clone()))
474                .clone(),
475        )
476    }
477}
478
479impl PartialEq for MeshVertexBufferLayoutRef {
480    fn eq(&self, other: &Self) -> bool {
481        Arc::ptr_eq(&self.0, &other.0)
482    }
483}
484
485impl Eq for MeshVertexBufferLayoutRef {}
486
487impl Hash for MeshVertexBufferLayoutRef {
488    fn hash<H: Hasher>(&self, state: &mut H) {
489        // Hash the address of the underlying data, so two layouts that share the same
490        // `MeshVertexBufferLayout` will have the same hash.
491        (Arc::as_ptr(&self.0) as usize).hash(state);
492    }
493}