bevy_mesh/primitives/dim3/
triangle3d.rs1use crate::{Indices, Mesh, MeshBuilder, Meshable};
2use bevy_asset::RenderAssetUsages;
3use bevy_math::{primitives::Triangle3d, Vec3};
4use wgpu::PrimitiveTopology;
5
6pub struct Triangle3dMeshBuilder {
8 triangle: Triangle3d,
9}
10
11impl MeshBuilder for Triangle3dMeshBuilder {
12 fn build(&self) -> Mesh {
13 let positions: Vec<_> = self.triangle.vertices.into();
14 let uvs: Vec<_> = uv_coords(&self.triangle).into();
15
16 let normal: Vec3 = normal_vec(&self.triangle);
18 let normals = vec![normal; 3];
19
20 let indices = Indices::U32(vec![0, 1, 2]);
21
22 Mesh::new(
23 PrimitiveTopology::TriangleList,
24 RenderAssetUsages::default(),
25 )
26 .with_inserted_indices(indices)
27 .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions)
28 .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
29 .with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs)
30 }
31}
32
33impl Meshable for Triangle3d {
34 type Output = Triangle3dMeshBuilder;
35
36 fn mesh(&self) -> Self::Output {
37 Triangle3dMeshBuilder { triangle: *self }
38 }
39}
40
41#[inline]
43pub(crate) fn normal_vec(triangle: &Triangle3d) -> Vec3 {
44 triangle.normal().map_or(Vec3::ZERO, Into::into)
45}
46
47#[inline]
49pub(crate) fn uv_coords(triangle: &Triangle3d) -> [[f32; 2]; 3] {
50 let [a, b, c] = triangle.vertices;
51
52 let main_length = a.distance(b);
53 let Some(x) = (b - a).try_normalize() else {
54 return [[0., 0.], [1., 0.], [0., 1.]];
55 };
56 let y = c - a;
57
58 let y_proj = y.project_onto_normalized(x);
63
64 let offset = y_proj.dot(x) / main_length;
67
68 if offset < 0. {
70 let total_length = 1. - offset;
71 let a_uv = [offset.abs() / total_length, 0.];
72 let b_uv = [1., 0.];
73 let c_uv = [0., 1.];
74
75 [a_uv, b_uv, c_uv]
76 }
77 else if offset > 1. {
79 let a_uv = [0., 0.];
80 let b_uv = [1. / offset, 0.];
81 let c_uv = [1., 1.];
82
83 [a_uv, b_uv, c_uv]
84 }
85 else {
87 let a_uv = [0., 0.];
88 let b_uv = [1., 0.];
89 let c_uv = [offset, 1.];
90
91 [a_uv, b_uv, c_uv]
92 }
93}
94
95impl From<Triangle3d> for Mesh {
96 fn from(triangle: Triangle3d) -> Self {
97 triangle.mesh().build()
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::uv_coords;
104 use bevy_math::primitives::Triangle3d;
105
106 #[test]
107 fn uv_test() {
108 use bevy_math::vec3;
109 let mut triangle = Triangle3d::new(vec3(0., 0., 0.), vec3(2., 0., 0.), vec3(-1., 1., 0.));
110
111 let [a_uv, b_uv, c_uv] = uv_coords(&triangle);
112 assert_eq!(a_uv, [1. / 3., 0.]);
113 assert_eq!(b_uv, [1., 0.]);
114 assert_eq!(c_uv, [0., 1.]);
115
116 triangle.vertices[2] = vec3(3., 1., 0.);
117 let [a_uv, b_uv, c_uv] = uv_coords(&triangle);
118 assert_eq!(a_uv, [0., 0.]);
119 assert_eq!(b_uv, [2. / 3., 0.]);
120 assert_eq!(c_uv, [1., 1.]);
121
122 triangle.vertices[2] = vec3(2., 1., 0.);
123 let [a_uv, b_uv, c_uv] = uv_coords(&triangle);
124 assert_eq!(a_uv, [0., 0.]);
125 assert_eq!(b_uv, [1., 0.]);
126 assert_eq!(c_uv, [1., 1.]);
127 }
128}