block_mesh/geometry.rs
1//! Voxel geometry and coordinate systems.
2//!
3//! `block-mesh` is designed to work for any 3-dimensional coordinate system.
4//! Doing this requires a somewhat complicated interplay between the types in
5//! this module. This documentation attempts to clarify what's going on.
6//!
7//! # Quads and Faces
8//!
9//! As most will know, a cube is composed of six **faces**.
10//!
11//! ```text
12//! O--------O
13//! / | / |
14//! O--------O |
15//! | | | |
16//! | O----|---O
17//! | / | /
18//! O--------O
19//!
20//! Fig 1: Cube
21//! ```
22//!
23//! When rendering a cube to the screen, this will involve rendering six
24//! **quads**. A quad has four **vertices**, each with a unique **UV** texture
25//! coordinate and the same **normal** vector. The quad is rendered as two
26//! triangles, typically as four vertices and six **indices**.
27//!
28//! ```text
29//! (U, V) 3
30//! 3 3------> N / ^
31//! / | / | / |
32//! (U, V) / | / | 2 |
33//! 2 | 2------> N \ |
34//! | \ | | \ | 2 \ |
35//! | \ | | \ | | \ 1
36//! | 1 | 1------> N | \
37//! | / (U, V) | / | 1
38//! | / | / | /
39//! 0 0------> N V /
40//! (U, V) 0
41//!
42//! Fig 2: Quad with vertices [A, B, C, D].
43//! - (left) UVs.
44//! - (middle) Normals.
45//! - (right) Two triangles rendered using indices [0, 1, 2, 3, 2, 1].
46//! ```
47//!
48//! # Coordinate System
49//!
50//! Different domains (e.g., your game engine or 3D modeling application) use
51//! different coordinate systems. Generating correct vertex positions, normals,
52//! and UV coordinates requires knowing the specifics of the coordinate system.
53//!
54//! ```text
55//! +Y +Y -Y
56//! | +Z | -Z | -Z
57//! -X____|/____+X -X____|/____+X +X____|/____-X
58//! /| /| /|
59//! -Z | +Z | +Z |
60//! -Y -Y +Y
61//!
62//! Fig 3: Various coordinate systems.
63//! - (left) Left-handed coordinate system with Y up.
64//! - (middle) Right-handed coordinate system with Y up.
65//! - (right) Right-handed coordinate system with Y down.
66//! ```
67//!
68//! ## Handedness
69//!
70//! **Handedness** (also called chirality) is this weird property of 3D things.
71//! If two 3D things have different handedness, then it is impossible to rotate
72//! or translate one to look like the other; it's only possible if you mirror
73//! it.
74//!
75//! Most often, in games and 3D modeling, this corresponds to which way the Z
76//! axis grows. Often, +X is right, +Y is up, and the handedness determines
77//! whether +Z is into or out of the screen.
78//!
79//! See wikipedia for more information on handedness:
80//! - <https://en.wikipedia.org/wiki/Right-hand_rule>
81//! - <https://en.wikipedia.org/wiki/Orientation_(vector_space)>
82//!
83//! ## Orientation
84//!
85//! The **orientation** of the coordinate system determines which way textures
86//! are displayed on cube faces. Most often, the orientation is "Y up", meaning
87//! that textures are displayed with the top of the image toward the +Y axis.
88//!
89//! # `{N, U, V}` Space
90//!
91//! "`{N, U, V}` space" is basically the **face-local coordinate space**
92//! (**N**ormal, **U**, **V**).
93//!
94//! The notion of an `{N, U, V}` space is convenient because we can return
95//! vertices, UVs, and indices in a consistent order regardless of the face. See
96//! [`OrientedBlockFace::quad_corners`].
97//!
98//! # Putting It All Together
99//!
100//! The output of the `block-mesh` algorithms are [`UnorientedQuad`]s. These
101//! simply specify the size and minimum `{X, Y, Z}` coordinate of the cube they
102//! are a part of.
103//!
104//! In order to get vertex positions, UV coordinates, normals, and mesh indices
105//! for an [`UnorientedQuad`], it must be paired with an [`OrientedBlockFace`],
106//! which specifies the `{N, U, V}` --> `{X, Y, Z}` mapping and the sign of the
107//! normal vector.
108//!
109//! Six [`OrientedBlockFace`] definitions combine to form a
110//! [`QuadCoordinateConfig`], which also implicitly defines the coordinate
111//! system.
112
113mod axis;
114mod face;
115mod quad;
116
117pub use axis::*;
118pub use face::*;
119pub use quad::*;
120
121/// A configuration of XYZ --> NUV axis mappings and orientations of the cube
122/// faces for a given coordinate system.
123///
124/// See the [`geometry` module documentation][crate::geometry] for more
125/// information on `{N, U, V}` space.
126#[derive(Clone)]
127pub struct QuadCoordinateConfig {
128 pub faces: [OrientedBlockFace; 6],
129
130 /// For a given coordinate system, one of the two axes that isn't UP must be
131 /// flipped in the U texel coordinate direction to avoid incorrect texture
132 /// mirroring. For example, in a right-handed coordinate system with +Y
133 /// pointing up, you should set `u_flip_face` to [`Axis::X`], because those
134 /// faces need their U coordinates to be flipped relative to the other
135 /// faces:
136 ///
137 /// ```text
138 /// +X face O
139 /// +Z face / |
140 /// ^ O--------O ^ O |
141 /// | | | | | |
142 /// +V | | | +V | | O ^
143 /// | | | | | / /
144 /// | O--------O | O /
145 /// ------------ > | / +U
146 /// +U
147 ///
148 /// +Y
149 /// | -Z
150 /// -X____|/____+X
151 /// /|
152 /// +Z |
153 /// -Y
154 /// ```
155 ///
156 /// As you can see, for the +Z face, +U is toward positive X. But for the +X
157 /// face, +U is towards **negative** Z.
158 pub u_flip_face: Axis,
159}
160
161/// Coordinate configuration for a right-handed coordinate system with Y up.
162///
163/// ```text
164/// +Y
165/// | -Z
166/// -X____|/____+X
167/// /|
168/// +Z |
169/// -Y
170/// ```
171pub const RIGHT_HANDED_Y_UP_CONFIG: QuadCoordinateConfig = QuadCoordinateConfig {
172 // Y is always in the V direction when it's not the normal. When Y is the
173 // normal, right-handedness determines that we must use Yzx permutations.
174 faces: [
175 OrientedBlockFace::new(-1, AxisPermutation::Xzy),
176 OrientedBlockFace::new(-1, AxisPermutation::Yzx),
177 OrientedBlockFace::new(-1, AxisPermutation::Zxy),
178 OrientedBlockFace::new(1, AxisPermutation::Xzy),
179 OrientedBlockFace::new(1, AxisPermutation::Yzx),
180 OrientedBlockFace::new(1, AxisPermutation::Zxy),
181 ],
182 u_flip_face: Axis::X,
183};