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};