Skip to content

Commit

Permalink
skinning WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
schell committed May 10, 2024
1 parent 1a876e1 commit 2d8c6e5
Show file tree
Hide file tree
Showing 11 changed files with 208 additions and 37 deletions.
Binary file modified crates/renderling/src/linkage/stage-renderlet_vertex.spv
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion crates/renderling/src/pbr/light.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Stage lighting.
use crabslab::{Id, SlabItem};
use glam::{Vec3, Vec4};
use glam::{Mat4, Vec3, Vec4};

use crate::transform::Transform;

Expand Down
79 changes: 52 additions & 27 deletions crates/renderling/src/stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use spirv_std::{

use crate::{
camera::Camera,
math::IsVector,
math::{IsMatrix, IsVector},
pbr::{Material, PbrConfig},
transform::Transform,
};
Expand Down Expand Up @@ -45,28 +45,32 @@ pub struct Skin {
pub inverse_bind_matrices: Array<Mat4>,
}

impl Skin {
pub fn get_transform(&self, vertex: Vertex, slab: &[u32]) -> Mat4 {
let mut mat = Mat4::ZERO;
for i in 0..vertex.joints.len() {
let joint_weight = vertex.weights[i];
if joint_weight == 0.0 {
continue;
}

let inverse_bind_matrix = slab.read(self.inverse_bind_matrices.at(i));
impl Skin {
pub fn get_inverse_bind_matrix(&self, i: usize, slab: &[u32]) -> Mat4 {
slab.read(self.inverse_bind_matrices.at(i))
}

let joint_index = vertex.joints[i] as usize;
let joint_id = slab.read(self.joints.at(joint_index));
let joint_matrix = Mat4::from(slab.read(joint_id)) * inverse_bind_matrix;
pub fn get_joint_matrix(&self, i: usize, vertex: Vertex, slab: &[u32]) -> Mat4 {
let joint_index = vertex.joints[i] as usize;
let joint_id = slab.read(self.joints.at(joint_index));
let joint_transform = slab.read(joint_id);
Mat4::from(joint_transform) * self.get_inverse_bind_matrix(i, slab)
}

mat += joint_matrix * joint_weight;
}
if mat == Mat4::ZERO {
Mat4::IDENTITY
} else {
mat
}
pub fn get_transform(&self, vertex: Vertex, slab: &[u32]) -> Transform {
let mat = vertex.weights[0] * self.get_joint_matrix(0, vertex, slab)
+ vertex.weights[1] * self.get_joint_matrix(1, vertex, slab)
+ vertex.weights[2] * self.get_joint_matrix(2, vertex, slab)
+ vertex.weights[3] * self.get_joint_matrix(3, vertex, slab);

Transform::from(
if mat == Mat4::ZERO {
Mat4::IDENTITY
} else {
mat
},
)
}
}

Expand Down Expand Up @@ -251,8 +255,6 @@ pub fn renderlet_vertex(
out_world_pos: &mut Vec3,
#[spirv(position)] out_clip_pos: &mut Vec4,
) {
use crate::math::IsMatrix;

let renderlet = slab.read_unchecked(renderlet_id);

let mut vertex_log = RenderletVertexLog::new(renderlet_id, renderlet.debug_index, vertex_index);
Expand All @@ -274,17 +276,16 @@ pub fn renderlet_vertex(
*out_uv0 = vertex.uv0;
*out_uv1 = vertex.uv1;

let model_matrix = if renderlet.skin_id.is_some() {
let transform = if renderlet.skin_id.is_some() {
let skin = slab.read(renderlet.skin_id);
skin.get_transform(vertex, slab)
} else {
let t = slab.read(renderlet.transform_id);
Mat4::from(t)
slab.read(renderlet.transform_id)
};
let (scale, _, _) = model_matrix.to_scale_rotation_translation_or_id();
let scale2 = scale * scale;
let scale2 = transform.scale * transform.scale;
let normal = vertex.normal.alt_norm_or_zero();
let tangent = vertex.tangent.xyz().alt_norm_or_zero();
let model_matrix = Mat4::from(transform);
let normal_w: Vec3 = (model_matrix * (normal / scale2).extend(0.0))
.xyz()
.alt_norm_or_zero();
Expand Down Expand Up @@ -459,3 +460,27 @@ pub fn test_i8_i16_extraction(
slab[index] = value as u32;
}
}

#[cfg(test)]
mod test {
use glam::{Mat4, Vec3};

use crate::transform::Transform;

#[test]
fn matrix_hierarchy_sanity() {
let a: Mat4 = Transform {
translation: Vec3::new(100.0, 100.0, 0.0),
..Default::default()
}
.into();
let b: Mat4 = Transform {
scale: Vec3::splat(0.5),
..Default::default()
}
.into();
let c1 = a * b;
let c2 = b * a;
assert_ne!(c1, c2);
}
}
3 changes: 2 additions & 1 deletion crates/renderling/src/stage/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use crate::{
stage::Renderlet,
texture::{DepthTexture, Texture},
tonemapping::Tonemapping,
transform::Transform,
};
use crabslab::{Array, CpuSlab, GrowableSlab, Id, Slab, SlabItem, WgpuBuffer};
use snafu::Snafu;
Expand Down Expand Up @@ -839,7 +840,7 @@ impl NestedTransform {
.as_ref()
.map(|parent| parent.get_global_transform())
.unwrap_or_default();
Transform::from(Mat4::from(parent_transform) * Mat4::from(transform))
Transform::from(Mat4::from(transform) * Mat4::from(parent_transform))
}

pub fn global_transform_id(&self) -> Id<Transform> {
Expand Down
20 changes: 19 additions & 1 deletion crates/renderling/src/stage/gltf_support.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,9 +468,22 @@ impl GltfPrimitive {
let vs = uv1s.zip(vs);
let vs = uv0s.into_iter().zip(vs);
let vs = positions.into_iter().zip(vs);
let mut logged_not_normalized = false;
let mut unnormalized_weight_vertices_count = 0;
let vertices = vs
.map(
|(position, (uv0, (uv1, (normal, (tangent, (color, (joints, weights)))))))| {
|(position, (uv0, (uv1, (normal, (tangent, (color, (joints, mut weights)))))))| {
let weight_sum: f32 = weights.iter().sum();
let are_normalized = 1.0 - weight_sum <= f32::EPSILON;
if !are_normalized {
unnormalized_weight_vertices_count += 1;
if !logged_not_normalized {
log::warn!("weights are not normalized: {weights:?}");
logged_not_normalized = true;
weights = weights.map(|w| w / weight_sum);
log::warn!(" normalized to {weights:?}");
}
}
Vertex {
position,
color,
Expand All @@ -486,6 +499,11 @@ impl GltfPrimitive {
.collect::<Vec<_>>();
let vertices = stage.new_array(vertices);
log::debug!("{} vertices, {:?}", vertices.len(), vertices.array());
if logged_not_normalized {
log::debug!(
" {unnormalized_weight_vertices_count} of which had unnormalized joint weights"
);
}
let indices = stage.new_array(indices);
log::debug!("{} indices, {:?}", indices.len(), indices.array());
let gltf::mesh::Bounds { min, max } = primitive.bounding_box();
Expand Down
4 changes: 2 additions & 2 deletions crates/renderling/src/stage/gltf_support/anime.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! Animation helpers for gltf.
use glam::{Quat, Vec3};
use glam::{Mat4, Quat, Vec3};
use snafu::prelude::*;

use crate::stage::NestedTransform;
use crate::{math::IsMatrix, stage::NestedTransform};

#[derive(Debug, Snafu)]
pub enum InterpolationError {
Expand Down
6 changes: 1 addition & 5 deletions crates/renderling/src/tutorial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,7 @@ pub fn tutorial_slabbed_renderlet(
*out_color = vertex.color;

let transform = slab.read(renderlet.transform_id);
let model = Mat4::from_scale_rotation_translation(
transform.scale,
transform.rotation,
transform.translation,
);
let model = Mat4::from(transform);
let camera = slab.read(renderlet.camera_id);
*clip_pos = camera.projection * camera.view * model * vertex.position.extend(1.0);
}
Expand Down
131 changes: 131 additions & 0 deletions gltf/SimpleSkin.gltf
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
{
"scene" : 0,
"scenes" : [ {
"nodes" : [ 0, 1 ]
} ],

"nodes" : [ {
"skin" : 0,
"mesh" : 0
}, {
"children" : [ 2 ]
}, {
"translation" : [ 0.0, 1.0, 0.0 ],
"rotation" : [ 0.0, 0.0, 0.0, 1.0 ]
} ],

"meshes" : [ {
"primitives" : [ {
"attributes" : {
"POSITION" : 1,
"JOINTS_0" : 2,
"WEIGHTS_0" : 3
},
"indices" : 0
} ]
} ],

"skins" : [ {
"inverseBindMatrices" : 4,
"joints" : [ 1, 2 ]
} ],

"animations" : [ {
"channels" : [ {
"sampler" : 0,
"target" : {
"node" : 2,
"path" : "rotation"
}
} ],
"samplers" : [ {
"input" : 5,
"interpolation" : "LINEAR",
"output" : 6
} ]
} ],

"buffers" : [ {
"uri" : "data:application/gltf-buffer;base64,AAABAAMAAAADAAIAAgADAAUAAgAFAAQABAAFAAcABAAHAAYABgAHAAkABgAJAAgAAAAAvwAAAAAAAAAAAAAAPwAAAAAAAAAAAAAAvwAAAD8AAAAAAAAAPwAAAD8AAAAAAAAAvwAAgD8AAAAAAAAAPwAAgD8AAAAAAAAAvwAAwD8AAAAAAAAAPwAAwD8AAAAAAAAAvwAAAEAAAAAAAAAAPwAAAEAAAAAA",
"byteLength" : 168
}, {
"uri" : "data:application/gltf-buffer;base64,AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAABAPwAAgD4AAAAAAAAAAAAAQD8AAIA+AAAAAAAAAAAAAAA/AAAAPwAAAAAAAAAAAAAAPwAAAD8AAAAAAAAAAAAAgD4AAEA/AAAAAAAAAAAAAIA+AABAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAA=",
"byteLength" : 320
}, {
"uri" : "data:application/gltf-buffer;base64,AACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAgD8=",
"byteLength" : 128
}, {
"uri" : "data:application/gltf-buffer;base64,AAAAAAAAAD8AAIA/AADAPwAAAEAAACBAAABAQAAAYEAAAIBAAACQQAAAoEAAALBAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAkxjEPkSLbD8AAAAAAAAAAPT9ND/0/TQ/AAAAAAAAAAD0/TQ/9P00PwAAAAAAAAAAkxjEPkSLbD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAkxjEvkSLbD8AAAAAAAAAAPT9NL/0/TQ/AAAAAAAAAAD0/TS/9P00PwAAAAAAAAAAkxjEvkSLbD8AAAAAAAAAAAAAAAAAAIA/",
"byteLength" : 240
} ],

"bufferViews" : [ {
"buffer" : 0,
"byteLength" : 48,
"target" : 34963
}, {
"buffer" : 0,
"byteOffset" : 48,
"byteLength" : 120,
"target" : 34962
}, {
"buffer" : 1,
"byteLength" : 320,
"byteStride" : 16
}, {
"buffer" : 2,
"byteLength" : 128
}, {
"buffer" : 3,
"byteLength" : 240
} ],

"accessors" : [ {
"bufferView" : 0,
"componentType" : 5123,
"count" : 24,
"type" : "SCALAR"
}, {
"bufferView" : 1,
"componentType" : 5126,
"count" : 10,
"type" : "VEC3",
"max" : [ 0.5, 2.0, 0.0 ],
"min" : [ -0.5, 0.0, 0.0 ]
}, {
"bufferView" : 2,
"componentType" : 5123,
"count" : 10,
"type" : "VEC4"
}, {
"bufferView" : 2,
"byteOffset" : 160,
"componentType" : 5126,
"count" : 10,
"type" : "VEC4"
}, {
"bufferView" : 3,
"componentType" : 5126,
"count" : 2,
"type" : "MAT4"
}, {
"bufferView" : 4,
"componentType" : 5126,
"count" : 12,
"type" : "SCALAR",
"max" : [ 5.5 ],
"min" : [ 0.0 ]
}, {
"bufferView" : 4,
"byteOffset" : 48,
"componentType" : 5126,
"count" : 12,
"type" : "VEC4",
"max" : [ 0.0, 0.0, 0.707, 1.0 ],
"min" : [ 0.0, 0.0, -0.707, 0.707 ]
} ],

"asset" : {
"version" : "2.0"
}
}

0 comments on commit 2d8c6e5

Please sign in to comment.