Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_mesh/src/vertex.rs
6595 views
1
use alloc::sync::Arc;
2
use bevy_derive::EnumVariantMeta;
3
use bevy_ecs::resource::Resource;
4
use bevy_math::Vec3;
5
#[cfg(feature = "serialize")]
6
use bevy_platform::collections::HashMap;
7
use bevy_platform::collections::HashSet;
8
use bytemuck::cast_slice;
9
use core::hash::{Hash, Hasher};
10
#[cfg(feature = "serialize")]
11
use serde::{Deserialize, Serialize};
12
use thiserror::Error;
13
use wgpu_types::{BufferAddress, VertexAttribute, VertexFormat, VertexStepMode};
14
15
#[derive(Debug, Clone, Copy, PartialEq)]
16
pub 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)]
31
pub(crate) struct SerializedMeshVertexAttribute {
32
pub(crate) name: String,
33
pub(crate) id: MeshVertexAttributeId,
34
pub(crate) format: VertexFormat,
35
}
36
37
#[cfg(feature = "serialize")]
38
impl 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
60
impl 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))]
76
pub struct MeshVertexAttributeId(u64);
77
78
impl From<MeshVertexAttribute> for MeshVertexAttributeId {
79
fn from(attribute: MeshVertexAttribute) -> Self {
80
attribute.id
81
}
82
}
83
84
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
85
pub struct MeshVertexBufferLayout {
86
pub(crate) attribute_ids: Vec<MeshVertexAttributeId>,
87
pub(crate) layout: VertexBufferLayout,
88
}
89
90
impl 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:?})")]
149
pub struct MissingVertexAttributeError {
150
pub pipeline_type: Option<&'static str>,
151
id: MeshVertexAttributeId,
152
name: &'static str,
153
}
154
155
pub struct VertexAttributeDescriptor {
156
pub shader_location: u32,
157
pub id: MeshVertexAttributeId,
158
name: &'static str,
159
}
160
161
impl 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)]
172
pub(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)]
179
pub(crate) struct SerializedMeshAttributeData {
180
pub(crate) attribute: SerializedMeshVertexAttribute,
181
pub(crate) values: VertexAttributeValues,
182
}
183
184
#[cfg(feature = "serialize")]
185
impl 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]
222
pub 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]
229
pub 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))]
238
pub 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
269
impl 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
363
impl 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)]
400
pub 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
409
impl 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)]
456
pub struct MeshVertexBufferLayoutRef(pub Arc<MeshVertexBufferLayout>);
457
458
/// Stores the single copy of each mesh vertex buffer layout.
459
#[derive(Clone, Default, Resource)]
460
pub struct MeshVertexBufferLayouts(HashSet<Arc<MeshVertexBufferLayout>>);
461
462
impl 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
479
impl PartialEq for MeshVertexBufferLayoutRef {
480
fn eq(&self, other: &Self) -> bool {
481
Arc::ptr_eq(&self.0, &other.0)
482
}
483
}
484
485
impl Eq for MeshVertexBufferLayoutRef {}
486
487
impl 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
}
494
495