Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_mesh/src/primitives/dim3/triangle3d.rs
6598 views
1
use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology};
2
use bevy_asset::RenderAssetUsages;
3
use bevy_math::{primitives::Triangle3d, Vec3};
4
use bevy_reflect::prelude::*;
5
6
/// A builder used for creating a [`Mesh`] with a [`Triangle3d`] shape.
7
#[derive(Clone, Copy, Debug, Default, Reflect)]
8
#[reflect(Default, Debug, Clone)]
9
pub struct Triangle3dMeshBuilder {
10
triangle: Triangle3d,
11
}
12
13
impl MeshBuilder for Triangle3dMeshBuilder {
14
fn build(&self) -> Mesh {
15
let positions: Vec<_> = self.triangle.vertices.into();
16
let uvs: Vec<_> = uv_coords(&self.triangle).into();
17
18
// Every vertex has the normal of the face of the triangle (or zero if the triangle is degenerate).
19
let normal: Vec3 = normal_vec(&self.triangle);
20
let normals = vec![normal; 3];
21
22
let indices = Indices::U32(vec![0, 1, 2]);
23
24
Mesh::new(
25
PrimitiveTopology::TriangleList,
26
RenderAssetUsages::default(),
27
)
28
.with_inserted_indices(indices)
29
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions)
30
.with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
31
.with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs)
32
}
33
}
34
35
impl Meshable for Triangle3d {
36
type Output = Triangle3dMeshBuilder;
37
38
fn mesh(&self) -> Self::Output {
39
Triangle3dMeshBuilder { triangle: *self }
40
}
41
}
42
43
/// The normal of a [`Triangle3d`] with zeroing so that a [`Vec3`] is always obtained for meshing.
44
#[inline]
45
pub(crate) fn normal_vec(triangle: &Triangle3d) -> Vec3 {
46
triangle.normal().map_or(Vec3::ZERO, Into::into)
47
}
48
49
/// Unskewed uv-coordinates for a [`Triangle3d`].
50
#[inline]
51
pub(crate) fn uv_coords(triangle: &Triangle3d) -> [[f32; 2]; 3] {
52
let [a, b, c] = triangle.vertices;
53
54
let main_length = a.distance(b);
55
let Some(x) = (b - a).try_normalize() else {
56
return [[0., 0.], [1., 0.], [0., 1.]];
57
};
58
let y = c - a;
59
60
// `x` corresponds to one of the axes in uv-coordinates;
61
// to uv-map the triangle without skewing, we use the orthogonalization
62
// of `y` with respect to `x` as the second direction and construct a rectangle that
63
// contains `triangle`.
64
let y_proj = y.project_onto_normalized(x);
65
66
// `offset` represents the x-coordinate of the point `c`; note that x has been shrunk by a
67
// factor of `main_length`, so `offset` follows it.
68
let offset = y_proj.dot(x) / main_length;
69
70
// Obtuse triangle leaning to the left => x direction extends to the left, shifting a from 0.
71
if offset < 0. {
72
let total_length = 1. - offset;
73
let a_uv = [offset.abs() / total_length, 0.];
74
let b_uv = [1., 0.];
75
let c_uv = [0., 1.];
76
77
[a_uv, b_uv, c_uv]
78
}
79
// Obtuse triangle leaning to the right => x direction extends to the right, shifting b from 1.
80
else if offset > 1. {
81
let a_uv = [0., 0.];
82
let b_uv = [1. / offset, 0.];
83
let c_uv = [1., 1.];
84
85
[a_uv, b_uv, c_uv]
86
}
87
// Acute triangle => no extending necessary; a remains at 0 and b remains at 1.
88
else {
89
let a_uv = [0., 0.];
90
let b_uv = [1., 0.];
91
let c_uv = [offset, 1.];
92
93
[a_uv, b_uv, c_uv]
94
}
95
}
96
97
impl From<Triangle3d> for Mesh {
98
fn from(triangle: Triangle3d) -> Self {
99
triangle.mesh().build()
100
}
101
}
102
103
#[cfg(test)]
104
mod tests {
105
use super::uv_coords;
106
use bevy_math::primitives::Triangle3d;
107
108
#[test]
109
fn uv_test() {
110
use bevy_math::vec3;
111
let mut triangle = Triangle3d::new(vec3(0., 0., 0.), vec3(2., 0., 0.), vec3(-1., 1., 0.));
112
113
let [a_uv, b_uv, c_uv] = uv_coords(&triangle);
114
assert_eq!(a_uv, [1. / 3., 0.]);
115
assert_eq!(b_uv, [1., 0.]);
116
assert_eq!(c_uv, [0., 1.]);
117
118
triangle.vertices[2] = vec3(3., 1., 0.);
119
let [a_uv, b_uv, c_uv] = uv_coords(&triangle);
120
assert_eq!(a_uv, [0., 0.]);
121
assert_eq!(b_uv, [2. / 3., 0.]);
122
assert_eq!(c_uv, [1., 1.]);
123
124
triangle.vertices[2] = vec3(2., 1., 0.);
125
let [a_uv, b_uv, c_uv] = uv_coords(&triangle);
126
assert_eq!(a_uv, [0., 0.]);
127
assert_eq!(b_uv, [1., 0.]);
128
assert_eq!(c_uv, [1., 1.]);
129
}
130
}
131
132