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