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