block_mesh/geometry/face.rs
1use crate::{Axis, AxisPermutation, SignedAxis, UnorientedQuad};
2
3use ilattice::glam::{IVec3, UVec3};
4
5/// Metadata that's used to aid in the geometric calculations for one of the 6 possible cube faces.
6#[derive(Clone, Copy, Debug, Eq, PartialEq)]
7pub struct OrientedBlockFace {
8 /// Determines the orientation of the plane.
9 pub(crate) n_sign: i32,
10
11 /// Determines the {N, U, V} <--> {X, Y, Z} relation.
12 pub(crate) permutation: AxisPermutation,
13
14 /// First in the `permutation` of +X, +Y, and +Z.
15 pub(crate) n: UVec3,
16 /// Second in the `permutation` of +X, +Y, and +Z.
17 pub(crate) u: UVec3,
18 /// Third in the `permutation` of +X, +Y, and +Z.
19 pub(crate) v: UVec3,
20}
21
22impl OrientedBlockFace {
23 pub const fn new(n_sign: i32, permutation: AxisPermutation) -> Self {
24 let [n_axis, u_axis, v_axis] = permutation.axes();
25
26 Self {
27 n_sign,
28 permutation,
29 n: n_axis.get_unit_vector(),
30 u: u_axis.get_unit_vector(),
31 v: v_axis.get_unit_vector(),
32 }
33 }
34
35 /// A cube face, using axes with an even permutation.
36 pub fn canonical(normal: SignedAxis) -> Self {
37 Self::new(
38 normal.signum(),
39 AxisPermutation::even_with_normal_axis(normal.unsigned_axis()),
40 )
41 }
42
43 #[inline]
44 pub fn signed_normal(&self) -> IVec3 {
45 self.n.as_ivec3() * self.n_sign
46 }
47
48 /// Returns the 4 corners of the quad in this order:
49 ///
50 /// ```text
51 /// 2 ----> 3
52 /// ^
53 /// ^ \
54 /// | \
55 /// +V | 0 ----> 1
56 /// |
57 /// -------->
58 /// +U
59 ///
60 /// (+N pointing out of the screen)
61 /// ```
62 ///
63 /// Note that this is natural when UV coordinates have (0,0) at the bottom
64 /// left, but when (0,0) is at the top left, V must be flipped.
65 #[inline]
66 pub fn quad_corners(&self, quad: &UnorientedQuad) -> [UVec3; 4] {
67 let w_vec = self.u * quad.width;
68 let h_vec = self.v * quad.height;
69
70 let minu_minv = if self.n_sign > 0 {
71 UVec3::from(quad.minimum) + self.n
72 } else {
73 UVec3::from(quad.minimum)
74 };
75 let maxu_minv = minu_minv + w_vec;
76 let minu_maxv = minu_minv + h_vec;
77 let maxu_maxv = minu_minv + w_vec + h_vec;
78
79 [minu_minv, maxu_minv, minu_maxv, maxu_maxv]
80 }
81
82 #[inline]
83 pub fn quad_mesh_positions(&self, quad: &UnorientedQuad, voxel_size: f32) -> [[f32; 3]; 4] {
84 self.quad_corners(quad)
85 .map(|c| (voxel_size * c.as_vec3()).to_array())
86 }
87
88 #[inline]
89 pub fn quad_mesh_normals(&self) -> [[f32; 3]; 4] {
90 [self.signed_normal().as_vec3().to_array(); 4]
91 }
92
93 /// Returns the 6 vertex indices for the quad in order to make two triangles
94 /// in a mesh. Winding order depends on both the sign of the surface normal
95 /// and the permutation of the UVs.
96 ///
97 /// Front faces will be wound counterclockwise, and back faces clockwise, as
98 /// per convention.
99 #[inline]
100 pub fn quad_mesh_indices(&self, start: u32) -> [u32; 6] {
101 quad_indices(start, self.n_sign * self.permutation.sign() > 0)
102 }
103
104 /// Returns the UV coordinates of the 4 corners of the quad. Returns
105 /// vertices in the same order as [`OrientedBlockFace::quad_corners`].
106 ///
107 /// `u_flip_face` should correspond to the field on
108 /// [`QuadCoordinateConfig`](crate::QuadCoordinateConfig). See the docs
109 /// there for more info.
110 ///
111 /// This is just one way of assigning UVs to voxel quads. It assumes that
112 /// each material has a single tile texture with wrapping coordinates, and
113 /// each voxel face should show the entire texture. It also assumes a
114 /// particular orientation for the texture. This should be sufficient for
115 /// minecraft-style meshing.
116 ///
117 /// If you need to use a texture atlas, you must calculate your own
118 /// coordinates from the `Quad`.
119 #[inline]
120 pub fn tex_coords(
121 &self,
122 u_flip_face: Axis,
123 flip_v: bool,
124 quad: &UnorientedQuad,
125 ) -> [[f32; 2]; 4] {
126 let face_normal_axis = self.permutation.axes()[0];
127 let flip_u = if self.n_sign < 0 {
128 u_flip_face != face_normal_axis
129 } else {
130 u_flip_face == face_normal_axis
131 };
132
133 match (flip_u, flip_v) {
134 (false, false) => [
135 [0.0, 0.0],
136 [quad.width as f32, 0.0],
137 [0.0, quad.height as f32],
138 [quad.width as f32, quad.height as f32],
139 ],
140 (true, false) => [
141 [quad.width as f32, 0.0],
142 [0.0, 0.0],
143 [quad.width as f32, quad.height as f32],
144 [0.0, quad.height as f32],
145 ],
146 (false, true) => [
147 [0.0, quad.height as f32],
148 [quad.width as f32, quad.height as f32],
149 [0.0, 0.0],
150 [quad.width as f32, 0.0],
151 ],
152 (true, true) => [
153 [quad.width as f32, quad.height as f32],
154 [0.0, quad.height as f32],
155 [quad.width as f32, 0.0],
156 [0.0, 0.0],
157 ],
158 }
159 }
160}
161
162/// Returns the vertex indices for a single quad (two triangles). The triangles
163/// may have either clockwise or counter-clockwise winding. `start` is the first
164/// index.
165fn quad_indices(start: u32, counter_clockwise: bool) -> [u32; 6] {
166 if counter_clockwise {
167 [start, start + 1, start + 2, start + 1, start + 3, start + 2]
168 } else {
169 [start, start + 2, start + 1, start + 1, start + 2, start + 3]
170 }
171}