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