1use crate::{prelude::*, Error, Indices, Positions, Result};
2
3#[derive(Clone)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub struct TriMesh {
9 pub positions: Positions,
12 pub indices: Indices,
14 pub normals: Option<Vec<Vec3>>,
16 pub tangents: Option<Vec<Vec4>>,
19 pub uvs: Option<Vec<Vec2>>,
21 pub colors: Option<Vec<Srgba>>,
23}
24
25impl std::default::Default for TriMesh {
26 fn default() -> Self {
27 Self {
28 positions: Positions::default(),
29 indices: Indices::None,
30 normals: None,
31 tangents: None,
32 uvs: None,
33 colors: None,
34 }
35 }
36}
37
38impl std::fmt::Debug for TriMesh {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 let mut d = f.debug_struct("Mesh");
41 d.field("positions", &self.positions.len());
42 d.field("indices", &self.indices);
43 d.field("normals", &self.normals.as_ref().map(|v| v.len()));
44 d.field("tangents", &self.tangents.as_ref().map(|v| v.len()));
45 d.field("uvs", &self.uvs.as_ref().map(|v| v.len()));
46 d.field("colors", &self.colors.as_ref().map(|v| v.len()));
47 d.finish()
48 }
49}
50
51impl TriMesh {
52 pub fn vertex_count(&self) -> usize {
54 self.positions.len()
55 }
56
57 pub fn triangle_count(&self) -> usize {
59 self.indices
60 .len()
61 .map(|i| i / 3)
62 .unwrap_or(self.positions.len() / 3)
63 }
64
65 pub fn transform(&mut self, transform: Mat4) -> Result<()> {
69 match self.positions {
70 Positions::F32(ref mut positions) => {
71 for pos in positions.iter_mut() {
72 *pos = (transform * pos.extend(1.0)).truncate();
73 }
74 }
75 Positions::F64(ref mut positions) => {
76 let t = transform.cast::<f64>().unwrap();
77 for pos in positions.iter_mut() {
78 *pos = (t * pos.extend(1.0)).truncate();
79 }
80 }
81 };
82
83 if self.normals.is_some() || self.tangents.is_some() {
84 let normal_transform = transform
85 .invert()
86 .ok_or(Error::FailedInvertingTransformationMatrix)?
87 .transpose();
88
89 if let Some(ref mut normals) = self.normals {
90 for n in normals.iter_mut() {
91 *n = (normal_transform * n.extend(1.0)).truncate();
92 }
93 }
94 if let Some(ref mut tangents) = self.tangents {
95 for t in tangents.iter_mut() {
96 *t = (normal_transform * t.truncate().extend(1.0))
97 .truncate()
98 .extend(t.w);
99 }
100 }
101 }
102 Ok(())
103 }
104
105 pub fn square() -> Self {
109 let indices = vec![0u8, 1, 2, 2, 3, 0];
110 let halfsize = 1.0;
111 let positions = vec![
112 Vec3::new(-halfsize, -halfsize, 0.0),
113 Vec3::new(halfsize, -halfsize, 0.0),
114 Vec3::new(halfsize, halfsize, 0.0),
115 Vec3::new(-halfsize, halfsize, 0.0),
116 ];
117 let normals = vec![
118 Vec3::new(0.0, 0.0, 1.0),
119 Vec3::new(0.0, 0.0, 1.0),
120 Vec3::new(0.0, 0.0, 1.0),
121 Vec3::new(0.0, 0.0, 1.0),
122 ];
123 let tangents = vec![
124 Vec4::new(1.0, 0.0, 0.0, 1.0),
125 Vec4::new(1.0, 0.0, 0.0, 1.0),
126 Vec4::new(1.0, 0.0, 0.0, 1.0),
127 Vec4::new(1.0, 0.0, 0.0, 1.0),
128 ];
129 let uvs = vec![
130 Vec2::new(0.0, 1.0),
131 Vec2::new(1.0, 1.0),
132 Vec2::new(1.0, 0.0),
133 Vec2::new(0.0, 0.0),
134 ];
135 TriMesh {
136 indices: Indices::U8(indices),
137 positions: Positions::F32(positions),
138 normals: Some(normals),
139 tangents: Some(tangents),
140 uvs: Some(uvs),
141 ..Default::default()
142 }
143 }
144
145 pub fn circle(angle_subdivisions: u32) -> Self {
149 let mut positions = Vec::new();
150 let mut indices = Vec::new();
151 let mut normals = Vec::new();
152 for j in 0..angle_subdivisions {
153 let angle = 2.0 * std::f32::consts::PI * j as f32 / angle_subdivisions as f32;
154
155 positions.push(Vec3::new(angle.cos(), angle.sin(), 0.0));
156 normals.push(Vec3::new(0.0, 0.0, 1.0));
157 }
158
159 for j in 0..angle_subdivisions {
160 indices.push(0);
161 indices.push(j as u16);
162 indices.push(((j + 1) % angle_subdivisions) as u16);
163 }
164 TriMesh {
165 indices: Indices::U16(indices),
166 positions: Positions::F32(positions),
167 normals: Some(normals),
168 ..Default::default()
169 }
170 }
171
172 pub fn sphere(angle_subdivisions: u32) -> Self {
176 let mut positions = Vec::new();
177 let mut indices = Vec::new();
178 let mut normals = Vec::new();
179
180 positions.push(Vec3::new(0.0, 0.0, 1.0));
181 normals.push(Vec3::new(0.0, 0.0, 1.0));
182
183 for j in 0..angle_subdivisions * 2 {
184 let j1 = (j + 1) % (angle_subdivisions * 2);
185 indices.push(0);
186 indices.push((1 + j) as u16);
187 indices.push((1 + j1) as u16);
188 }
189
190 for i in 0..angle_subdivisions - 1 {
191 let theta = std::f32::consts::PI * (i + 1) as f32 / angle_subdivisions as f32;
192 let sin_theta = theta.sin();
193 let cos_theta = theta.cos();
194 let i0 = 1 + i * angle_subdivisions * 2;
195 let i1 = 1 + (i + 1) * angle_subdivisions * 2;
196
197 for j in 0..angle_subdivisions * 2 {
198 let phi = std::f32::consts::PI * j as f32 / angle_subdivisions as f32;
199 let x = sin_theta * phi.cos();
200 let y = sin_theta * phi.sin();
201 let z = cos_theta;
202 positions.push(Vec3::new(x, y, z));
203 normals.push(Vec3::new(x, y, z));
204
205 if i != angle_subdivisions - 2 {
206 let j1 = (j + 1) % (angle_subdivisions * 2);
207 indices.push((i0 + j) as u16);
208 indices.push((i1 + j1) as u16);
209 indices.push((i0 + j1) as u16);
210 indices.push((i1 + j1) as u16);
211 indices.push((i0 + j) as u16);
212 indices.push((i1 + j) as u16);
213 }
214 }
215 }
216 positions.push(Vec3::new(0.0, 0.0, -1.0));
217 normals.push(Vec3::new(0.0, 0.0, -1.0));
218
219 let i = 1 + (angle_subdivisions - 2) * angle_subdivisions * 2;
220 for j in 0..angle_subdivisions * 2 {
221 let j1 = (j + 1) % (angle_subdivisions * 2);
222 indices.push((i + j) as u16);
223 indices.push(((angle_subdivisions - 1) * angle_subdivisions * 2 + 1) as u16);
224 indices.push((i + j1) as u16);
225 }
226
227 TriMesh {
228 indices: Indices::U16(indices),
229 positions: Positions::F32(positions),
230 normals: Some(normals),
231 ..Default::default()
232 }
233 }
234
235 pub fn cube() -> Self {
239 let positions = vec![
240 Vec3::new(1.0, 1.0, -1.0),
242 Vec3::new(-1.0, 1.0, -1.0),
243 Vec3::new(1.0, 1.0, 1.0),
244 Vec3::new(-1.0, 1.0, 1.0),
245 Vec3::new(1.0, 1.0, 1.0),
246 Vec3::new(-1.0, 1.0, -1.0),
247 Vec3::new(-1.0, -1.0, -1.0),
249 Vec3::new(1.0, -1.0, -1.0),
250 Vec3::new(1.0, -1.0, 1.0),
251 Vec3::new(1.0, -1.0, 1.0),
252 Vec3::new(-1.0, -1.0, 1.0),
253 Vec3::new(-1.0, -1.0, -1.0),
254 Vec3::new(1.0, -1.0, -1.0),
256 Vec3::new(-1.0, -1.0, -1.0),
257 Vec3::new(1.0, 1.0, -1.0),
258 Vec3::new(-1.0, 1.0, -1.0),
259 Vec3::new(1.0, 1.0, -1.0),
260 Vec3::new(-1.0, -1.0, -1.0),
261 Vec3::new(-1.0, -1.0, 1.0),
263 Vec3::new(1.0, -1.0, 1.0),
264 Vec3::new(1.0, 1.0, 1.0),
265 Vec3::new(1.0, 1.0, 1.0),
266 Vec3::new(-1.0, 1.0, 1.0),
267 Vec3::new(-1.0, -1.0, 1.0),
268 Vec3::new(1.0, -1.0, -1.0),
270 Vec3::new(1.0, 1.0, -1.0),
271 Vec3::new(1.0, 1.0, 1.0),
272 Vec3::new(1.0, 1.0, 1.0),
273 Vec3::new(1.0, -1.0, 1.0),
274 Vec3::new(1.0, -1.0, -1.0),
275 Vec3::new(-1.0, 1.0, -1.0),
277 Vec3::new(-1.0, -1.0, -1.0),
278 Vec3::new(-1.0, 1.0, 1.0),
279 Vec3::new(-1.0, -1.0, 1.0),
280 Vec3::new(-1.0, 1.0, 1.0),
281 Vec3::new(-1.0, -1.0, -1.0),
282 ];
283 let uvs = vec![
284 Vec2::new(0.25, 0.0),
286 Vec2::new(0.25, 1.0 / 3.0),
287 Vec2::new(0.5, 0.0),
288 Vec2::new(0.5, 1.0 / 3.0),
289 Vec2::new(0.5, 0.0),
290 Vec2::new(0.25, 1.0 / 3.0),
291 Vec2::new(0.25, 2.0 / 3.0),
293 Vec2::new(0.25, 1.0),
294 Vec2::new(0.5, 1.0),
295 Vec2::new(0.5, 1.0),
296 Vec2::new(0.5, 2.0 / 3.0),
297 Vec2::new(0.25, 2.0 / 3.0),
298 Vec2::new(0.0, 2.0 / 3.0),
300 Vec2::new(0.25, 2.0 / 3.0),
301 Vec2::new(0.0, 1.0 / 3.0),
302 Vec2::new(0.25, 1.0 / 3.0),
303 Vec2::new(0.0, 1.0 / 3.0),
304 Vec2::new(0.25, 2.0 / 3.0),
305 Vec2::new(0.5, 2.0 / 3.0),
307 Vec2::new(0.75, 2.0 / 3.0),
308 Vec2::new(0.75, 1.0 / 3.0),
309 Vec2::new(0.75, 1.0 / 3.0),
310 Vec2::new(0.5, 1.0 / 3.0),
311 Vec2::new(0.5, 2.0 / 3.0),
312 Vec2::new(1.0, 2.0 / 3.0),
314 Vec2::new(1.0, 1.0 / 3.0),
315 Vec2::new(0.75, 1.0 / 3.0),
316 Vec2::new(0.75, 1.0 / 3.0),
317 Vec2::new(0.75, 2.0 / 3.0),
318 Vec2::new(1.0, 2.0 / 3.0),
319 Vec2::new(0.25, 1.0 / 3.0),
321 Vec2::new(0.25, 2.0 / 3.0),
322 Vec2::new(0.5, 1.0 / 3.0),
323 Vec2::new(0.5, 2.0 / 3.0),
324 Vec2::new(0.5, 1.0 / 3.0),
325 Vec2::new(0.25, 2.0 / 3.0),
326 ];
327 let mut mesh = TriMesh {
328 positions: Positions::F32(positions),
329 uvs: Some(uvs),
330 ..Default::default()
331 };
332 mesh.compute_normals();
333 mesh.compute_tangents();
334 mesh
335 }
336
337 pub fn cylinder(angle_subdivisions: u32) -> Self {
341 let length_subdivisions = 1;
342 let mut positions = Vec::new();
343 let mut indices = Vec::new();
344 for i in 0..length_subdivisions + 1 {
345 let x = i as f32 / length_subdivisions as f32;
346 for j in 0..angle_subdivisions {
347 let angle = 2.0 * std::f32::consts::PI * j as f32 / angle_subdivisions as f32;
348
349 positions.push(Vec3::new(x, angle.cos(), angle.sin()));
350 }
351 }
352 for i in 0..length_subdivisions {
353 for j in 0..angle_subdivisions {
354 indices.push((i * angle_subdivisions + j) as u16);
355 indices.push((i * angle_subdivisions + (j + 1) % angle_subdivisions) as u16);
356 indices.push(((i + 1) * angle_subdivisions + (j + 1) % angle_subdivisions) as u16);
357
358 indices.push((i * angle_subdivisions + j) as u16);
359 indices.push(((i + 1) * angle_subdivisions + (j + 1) % angle_subdivisions) as u16);
360 indices.push(((i + 1) * angle_subdivisions + j) as u16);
361 }
362 }
363 let mut mesh = Self {
364 positions: Positions::F32(positions),
365 indices: Indices::U16(indices),
366 ..Default::default()
367 };
368 mesh.compute_normals();
369 mesh
370 }
371
372 pub fn cone(angle_subdivisions: u32) -> Self {
376 let length_subdivisions = 1;
377 let mut positions = Vec::new();
378 let mut indices = Vec::new();
379 for i in 0..length_subdivisions + 1 {
380 let x = i as f32 / length_subdivisions as f32;
381 for j in 0..angle_subdivisions {
382 let angle = 2.0 * std::f32::consts::PI * j as f32 / angle_subdivisions as f32;
383
384 positions.push(Vec3::new(
385 x,
386 angle.cos() * (1.0 - x),
387 angle.sin() * (1.0 - x),
388 ));
389 }
390 }
391 for i in 0..length_subdivisions {
392 for j in 0..angle_subdivisions {
393 indices.push((i * angle_subdivisions + j) as u16);
394 indices.push((i * angle_subdivisions + (j + 1) % angle_subdivisions) as u16);
395 indices.push(((i + 1) * angle_subdivisions + (j + 1) % angle_subdivisions) as u16);
396
397 indices.push((i * angle_subdivisions + j) as u16);
398 indices.push(((i + 1) * angle_subdivisions + (j + 1) % angle_subdivisions) as u16);
399 indices.push(((i + 1) * angle_subdivisions + j) as u16);
400 }
401 }
402 let mut mesh = Self {
403 positions: Positions::F32(positions),
404 indices: Indices::U16(indices),
405 ..Default::default()
406 };
407 mesh.compute_normals();
408 mesh
409 }
410
411 pub fn arrow(tail_length: f32, tail_radius: f32, angle_subdivisions: u32) -> Self {
416 let mut arrow = Self::cylinder(angle_subdivisions);
417 arrow
418 .transform(Mat4::from_nonuniform_scale(
419 tail_length,
420 tail_radius,
421 tail_radius,
422 ))
423 .unwrap();
424 let mut cone = Self::cone(angle_subdivisions);
425 cone.transform(
426 Mat4::from_translation(Vec3::new(tail_length, 0.0, 0.0))
427 * Mat4::from_nonuniform_scale(1.0 - tail_length, 1.0, 1.0),
428 )
429 .unwrap();
430 let mut indices = arrow.indices.into_u32().unwrap();
431 let cone_indices = cone.indices.into_u32().unwrap();
432 let offset = indices.iter().max().unwrap() + 1;
433 indices.extend(cone_indices.iter().map(|i| i + offset));
434 arrow.indices = Indices::U16(indices.iter().map(|i| *i as u16).collect());
435
436 if let Positions::F32(ref mut p) = arrow.positions {
437 if let Positions::F32(ref p2) = cone.positions {
438 p.extend(p2);
439 }
440 }
441 arrow
442 .normals
443 .as_mut()
444 .unwrap()
445 .extend(cone.normals.as_ref().unwrap());
446 arrow
447 }
448
449 pub fn compute_normals(&mut self) {
454 let mut normals = vec![Vec3::new(0.0, 0.0, 0.0); self.positions.len()];
455 self.for_each_triangle(|i0, i1, i2| {
456 let normal = match self.positions {
457 Positions::F32(ref positions) => {
458 let p0 = positions[i0];
459 let p1 = positions[i1];
460 let p2 = positions[i2];
461 (p1 - p0).cross(p2 - p0)
462 }
463 Positions::F64(ref positions) => {
464 let p0 = positions[i0];
465 let p1 = positions[i1];
466 let p2 = positions[i2];
467 let n = (p1 - p0).cross(p2 - p0);
468 Vec3::new(n.x as f32, n.y as f32, n.z as f32)
469 }
470 };
471 normals[i0] += normal;
472 normals[i1] += normal;
473 normals[i2] += normal;
474 });
475
476 for n in normals.iter_mut() {
477 *n = n.normalize();
478 }
479 self.normals = Some(normals);
480 }
481
482 pub fn compute_tangents(&mut self) {
487 if self.normals.is_none() || self.uvs.is_none() {
488 panic!("mesh must have both normals and uv coordinates to be able to compute tangents");
489 }
490 let mut tan1 = vec![Vec3::new(0.0, 0.0, 0.0); self.positions.len()];
491 let mut tan2 = vec![Vec3::new(0.0, 0.0, 0.0); self.positions.len()];
492
493 self.for_each_triangle(|i0, i1, i2| {
494 let (a, b, c) = match self.positions {
495 Positions::F32(ref positions) => (positions[i0], positions[i1], positions[i2]),
496 Positions::F64(ref positions) => {
497 let (a, b, c) = (positions[i0], positions[i1], positions[i2]);
498 (
499 Vec3::new(a.x as f32, a.y as f32, a.z as f32),
500 Vec3::new(b.x as f32, b.y as f32, b.z as f32),
501 Vec3::new(c.x as f32, c.y as f32, c.z as f32),
502 )
503 }
504 };
505 let uva = self.uvs.as_ref().unwrap()[i0];
506 let uvb = self.uvs.as_ref().unwrap()[i1];
507 let uvc = self.uvs.as_ref().unwrap()[i2];
508
509 let ba = b - a;
510 let ca = c - a;
511
512 let uvba = uvb - uva;
513 let uvca = uvc - uva;
514
515 let d = uvba.x * uvca.y - uvca.x * uvba.y;
516 if d.abs() > 0.00001 {
517 let r = 1.0 / d;
518 let sdir = (ba * uvca.y - ca * uvba.y) * r;
519 let tdir = (ca * uvba.x - ba * uvca.x) * r;
520 tan1[i0] += sdir;
521 tan1[i1] += sdir;
522 tan1[i2] += sdir;
523 tan2[i0] += tdir;
524 tan2[i1] += tdir;
525 tan2[i2] += tdir;
526 }
527 });
528
529 let mut tangents = vec![Vec4::new(0.0, 0.0, 0.0, 0.0); self.positions.len()];
530 self.for_each_vertex(|index| {
531 let normal = self.normals.as_ref().unwrap()[index];
532 let t = tan1[index];
533 let tangent = (t - normal * normal.dot(t)).normalize();
534 let handedness = if normal.cross(tangent).dot(tan2[index]) < 0.0 {
535 1.0
536 } else {
537 -1.0
538 };
539 tangents[index] = tangent.extend(handedness);
540 });
541
542 self.tangents = Some(tangents);
543 }
544
545 pub fn for_each_vertex(&self, mut callback: impl FnMut(usize)) {
549 for i in 0..self.positions.len() {
550 callback(i);
551 }
552 }
553
554 pub fn for_each_triangle(&self, mut callback: impl FnMut(usize, usize, usize)) {
558 match self.indices {
559 Indices::U8(ref indices) => {
560 for face in 0..indices.len() / 3 {
561 let index0 = indices[face * 3] as usize;
562 let index1 = indices[face * 3 + 1] as usize;
563 let index2 = indices[face * 3 + 2] as usize;
564 callback(index0, index1, index2);
565 }
566 }
567 Indices::U16(ref indices) => {
568 for face in 0..indices.len() / 3 {
569 let index0 = indices[face * 3] as usize;
570 let index1 = indices[face * 3 + 1] as usize;
571 let index2 = indices[face * 3 + 2] as usize;
572 callback(index0, index1, index2);
573 }
574 }
575 Indices::U32(ref indices) => {
576 for face in 0..indices.len() / 3 {
577 let index0 = indices[face * 3] as usize;
578 let index1 = indices[face * 3 + 1] as usize;
579 let index2 = indices[face * 3 + 2] as usize;
580 callback(index0, index1, index2);
581 }
582 }
583 Indices::None => {
584 for face in 0..self.triangle_count() {
585 callback(face * 3, face * 3 + 1, face * 3 + 2);
586 }
587 }
588 }
589 }
590
591 pub fn compute_aabb(&self) -> AxisAlignedBoundingBox {
595 self.positions.compute_aabb()
596 }
597
598 pub fn validate(&self) -> Result<()> {
602 if self.indices.len().map(|i| i % 3 != 0).unwrap_or(false) {
603 Err(Error::InvalidNumberOfIndices(self.indices.len().unwrap()))?;
604 }
605 let vertex_count = self.vertex_count();
606 let max_index = match &self.indices {
607 Indices::U8(ind) => ind.iter().max().map(|m| *m as usize),
608 Indices::U16(ind) => ind.iter().max().map(|m| *m as usize),
609 Indices::U32(ind) => ind.iter().max().map(|m| *m as usize),
610 Indices::None => None,
611 };
612 if max_index.map(|i| i >= vertex_count).unwrap_or(false) {
613 Err(Error::InvalidIndices(max_index.unwrap(), vertex_count))?;
614 }
615 let buffer_check = |length: Option<usize>, name: &str| -> Result<()> {
616 if let Some(length) = length {
617 if length < vertex_count {
618 Err(Error::InvalidBufferLength(
619 name.to_string(),
620 vertex_count,
621 length,
622 ))?;
623 }
624 }
625 Ok(())
626 };
627
628 buffer_check(Some(self.positions.len()), "position")?;
629 buffer_check(self.normals.as_ref().map(|b| b.len()), "normal")?;
630 buffer_check(self.tangents.as_ref().map(|b| b.len()), "tangent")?;
631 buffer_check(self.colors.as_ref().map(|b| b.len()), "color")?;
632 buffer_check(self.uvs.as_ref().map(|b| b.len()), "uv coordinate")?;
633
634 Ok(())
635 }
636}