Skip to main content

renderling/
geometry.rs

1//! Types and functions for staging geometry.
2use crate::math::IsVector;
3use crabslab::SlabItem;
4
5#[cfg(cpu)]
6mod cpu;
7#[cfg(cpu)]
8pub use cpu::*;
9use glam::{Vec2, Vec3, Vec4};
10
11pub mod shader;
12
13/// A displacement target.
14///
15/// Use to displace vertices using weights defined on the mesh.
16///
17/// For more info on morph targets in general, see
18/// <https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#morph-targets>
19#[derive(Clone, Copy, Default, PartialEq, SlabItem, core::fmt::Debug)]
20pub struct MorphTarget {
21    pub position: Vec3,
22    pub normal: Vec3,
23    pub tangent: Vec3,
24    // TODO: Extend MorphTargets to include UV and Color.
25    // I think this would take a contribution to the `gltf` crate.
26}
27
28/// A vertex in a mesh.
29#[derive(Clone, Copy, core::fmt::Debug, PartialEq, SlabItem)]
30pub struct Vertex {
31    pub position: Vec3,
32    pub color: Vec4,
33    pub uv0: Vec2,
34    pub uv1: Vec2,
35    pub normal: Vec3,
36    pub tangent: Vec4,
37    // Indices that point to this vertex's 'joint' transforms.
38    pub joints: [u32; 4],
39    // The weights of influence that each joint has over this vertex
40    pub weights: [f32; 4],
41}
42
43impl Default for Vertex {
44    fn default() -> Self {
45        Self {
46            position: Default::default(),
47            color: Vec4::ONE,
48            uv0: Vec2::ZERO,
49            uv1: Vec2::ZERO,
50            normal: Vec3::Z,
51            tangent: Vec4::Y,
52            joints: [0; 4],
53            weights: [0.0; 4],
54        }
55    }
56}
57
58impl Vertex {
59    pub fn with_position(mut self, p: impl Into<Vec3>) -> Self {
60        self.position = p.into();
61        self
62    }
63
64    pub fn with_color(mut self, c: impl Into<Vec4>) -> Self {
65        self.color = c.into();
66        self
67    }
68
69    pub fn with_uv0(mut self, uv: impl Into<Vec2>) -> Self {
70        self.uv0 = uv.into();
71        self
72    }
73
74    pub fn with_uv1(mut self, uv: impl Into<Vec2>) -> Self {
75        self.uv1 = uv.into();
76        self
77    }
78
79    pub fn with_normal(mut self, n: impl Into<Vec3>) -> Self {
80        self.normal = n.into();
81        self
82    }
83
84    pub fn with_tangent(mut self, t: impl Into<Vec4>) -> Self {
85        self.tangent = t.into();
86        self
87    }
88
89    pub fn generate_normal(a: Vec3, b: Vec3, c: Vec3) -> Vec3 {
90        let ab = a - b;
91        let ac = a - c;
92        ab.cross(ac).normalize()
93    }
94
95    pub fn generate_tangent(a: Vec3, a_uv: Vec2, b: Vec3, b_uv: Vec2, c: Vec3, c_uv: Vec2) -> Vec4 {
96        let ab = b - a;
97        let ac = c - a;
98        let n = ab.cross(ac);
99        let d_uv1 = b_uv - a_uv;
100        let d_uv2 = c_uv - a_uv;
101        let denom = d_uv1.x * d_uv2.y - d_uv2.x * d_uv1.y;
102        let denom_sign = if denom >= 0.0 { 1.0 } else { -1.0 };
103        let denom = denom.abs().max(f32::EPSILON) * denom_sign;
104        let f = 1.0 / denom;
105        let s = f * Vec3::new(
106            d_uv2.y * ab.x - d_uv1.y * ac.x,
107            d_uv2.y * ab.y - d_uv1.y * ac.y,
108            d_uv2.y * ab.z - d_uv1.y * ac.z,
109        );
110        let t = f * Vec3::new(
111            d_uv1.x * ac.x - d_uv2.x * ab.x,
112            d_uv1.x * ac.y - d_uv2.x * ab.y,
113            d_uv1.x * ac.z - d_uv2.x * ab.z,
114        );
115        let n_cross_t_dot_s_sign = if n.cross(t).dot(s) >= 0.0 { 1.0 } else { -1.0 };
116        (s - s.dot(n) * n)
117            .alt_norm_or_zero()
118            .extend(n_cross_t_dot_s_sign)
119    }
120
121    #[cfg(cpu)]
122    /// A triangle list mesh of points.
123    pub fn cube_mesh() -> [Vertex; 36] {
124        let mut mesh = [Vertex::default(); 36];
125        let unit_cube = crate::math::unit_cube();
126        debug_assert_eq!(36, unit_cube.len());
127        for (i, (position, normal)) in unit_cube.into_iter().enumerate() {
128            mesh[i].position = position;
129            mesh[i].normal = normal;
130        }
131        mesh
132    }
133}