bevy_mesh/
vertex.rs

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