Skip to main content

renderling/geometry/
shader.rs

1use crabslab::{Array, Id, Slab, SlabItem};
2use glam::Mat4;
3
4use crate::{
5    camera::shader::CameraDescriptor, geometry::Vertex, transform::shader::TransformDescriptor,
6};
7
8/// A vertex skin descriptor.
9///
10/// For more info on vertex skinning, see
11/// <https://github.khronos.org/glTF-Tutorials/gltfTutorial/gltfTutorial_019_SimpleSkin.html>
12#[derive(Clone, Copy, Default, SlabItem, core::fmt::Debug)]
13pub struct SkinDescriptor {
14    // Ids of the skeleton nodes' global transforms used as joints in this skin.
15    pub joints_array: Array<Id<TransformDescriptor>>,
16    // Contains the 4x4 inverse-bind matrices.
17    //
18    // When is none, each matrix is assumed to be the 4x4 identity matrix
19    // which implies that the inverse-bind matrices were pre-applied.
20    pub inverse_bind_matrices_array: Array<Mat4>,
21}
22
23impl SkinDescriptor {
24    pub fn get_joint_matrix(&self, i: usize, vertex: Vertex, slab: &[u32]) -> Mat4 {
25        let joint_index = vertex.joints[i] as usize;
26        let joint_id = slab.read(self.joints_array.at(joint_index));
27        let joint_transform = slab.read(joint_id);
28        // First apply the inverse bind matrix to bring the vertex into the
29        // joint's local space, then apply the joint's current
30        // transformation to move it into world space.
31        let inverse_bind_matrix = slab.read(self.inverse_bind_matrices_array.at(joint_index));
32        Mat4::from(joint_transform) * inverse_bind_matrix
33    }
34
35    pub fn get_skinning_matrix(&self, vertex: Vertex, slab: &[u32]) -> Mat4 {
36        let mut skinning_matrix = Mat4::ZERO;
37        for i in 0..vertex.joints.len() {
38            let joint_matrix = self.get_joint_matrix(i, vertex, slab);
39            // Ensure weights are applied correctly to the joint matrix
40            let weight = vertex.weights[i];
41            skinning_matrix += weight * joint_matrix;
42        }
43
44        if skinning_matrix == Mat4::ZERO {
45            Mat4::IDENTITY
46        } else {
47            skinning_matrix
48        }
49    }
50}
51
52/// Holds configuration info for vertex and shading render passes of
53/// geometry.
54///
55/// This descriptor lives at the root (index 0) of the geometry slab.
56#[derive(Clone, Copy, PartialEq, SlabItem, core::fmt::Debug)]
57#[offsets]
58pub struct GeometryDescriptor {
59    pub camera_id: Id<CameraDescriptor>,
60    pub atlas_size: glam::UVec2,
61    pub resolution: glam::UVec2,
62    pub debug_channel: crate::pbr::debug::DebugChannel,
63    pub has_lighting: bool,
64    pub has_skinning: bool,
65    pub perform_frustum_culling: bool,
66    pub perform_occlusion_culling: bool,
67}
68
69impl Default for GeometryDescriptor {
70    fn default() -> Self {
71        Self {
72            camera_id: Id::NONE,
73            atlas_size: Default::default(),
74            resolution: glam::UVec2::ONE,
75            debug_channel: Default::default(),
76            has_lighting: true,
77            has_skinning: true,
78            perform_frustum_culling: true,
79            perform_occlusion_culling: false,
80        }
81    }
82}