more anim work

This commit is contained in:
Robin Appelman 2024-12-31 00:11:38 +01:00
commit 226d085211
4 changed files with 73 additions and 41 deletions

View file

@ -211,14 +211,14 @@ impl Model {
.map(|(_, weight)| weight.weight) .map(|(_, weight)| weight.weight)
.sum(); .sum();
let pose_to_bone = animated_bone.pos.into(); let pose_to_bone: Matrix4<f32> = animated_bone.pose_to_bone.into();
let bone_to_pose: Matrix4<f32> = pose_to_bone.inverse_transform().unwrap();
let bone_rotation: Matrix4<f32> = animated_bone.rot.into();
let bone_rotation = Matrix4::from(animated_bone.rot);
if weight > 0.0 { if weight > 0.0 {
position -= pose_to_bone; let transform =
let transform = (animation.transform(frame)) * bone_rotation; bone_to_pose * animation.transform(frame) * bone_rotation * pose_to_bone;
position = transform.transform_vector(position); position = transform.transform_point(position);
position += pose_to_bone;
} }
} }
} }

View file

@ -155,10 +155,22 @@ bitflags! {
} }
} }
#[derive(Zeroable, Pod, Copy, Clone, Debug)] #[derive(Debug, Copy, Clone)]
#[repr(C)] struct AnimationValuePointers<'a> {
struct AnimationValuePointer([u16; 3]); offsets: [u16; 3],
impl ReadableRelative for AnimationValuePointer {} data: &'a [u8],
}
impl<'a> ReadRelative<'a> for AnimationValuePointers<'a> {
type Header = [u16; 3];
fn read(data: &'a [u8], header: Self::Header) -> Result<Self, ModelError> {
Ok(AnimationValuePointers {
offsets: header,
data,
})
}
}
#[derive(Zeroable, Pod, Copy, Clone, Debug, Default)] #[derive(Zeroable, Pod, Copy, Clone, Debug, Default)]
#[repr(C)] #[repr(C)]
@ -172,17 +184,16 @@ static_assertions::const_assert_eq!(size_of::<ValueHeader>(), size_of::<i16>());
impl ReadableRelative for ValueHeader {} impl ReadableRelative for ValueHeader {}
fn read_animation_values( fn read_animation_values(
data: &[u8], // data starting at the AnimationValuePointer
frame: usize, frame: usize,
base_pointers: AnimationValuePointer, animation_value_pointers: AnimationValuePointers,
) -> Result<[f32; 3], ModelError> { ) -> Result<[f32; 3], ModelError> {
let [x, y, z] = base_pointers let [x, y, z] = animation_value_pointers
.0 .offsets
.map::<_, Result<_, ModelError>>(|base_pointer| { .map::<_, Result<_, ModelError>>(|offset| {
if base_pointer == 0 { if offset == 0 {
Ok(0) Ok(0)
} else { } else {
let values: FrameValues = read_single(data, base_pointer)?; let values: FrameValues = read_single(animation_value_pointers.data, offset)?;
Ok(values.get(frame as u8)?) Ok(values.get(frame as u8)?)
} }
}); });
@ -291,7 +302,9 @@ impl RotationData {
match self { match self {
RotationData::Quaternion48(_) => size_of::<Quaternion48>(), RotationData::Quaternion48(_) => size_of::<Quaternion48>(),
RotationData::Quaternion64(_) => size_of::<Quaternion64>(), RotationData::Quaternion64(_) => size_of::<Quaternion64>(),
RotationData::Animated(_) => size_of::<AnimationValuePointer>(), RotationData::Animated(_) => {
size_of::<<AnimationValuePointers<'_> as ReadRelative>::Header>()
}
RotationData::None => 0, RotationData::None => 0,
} }
} }
@ -332,7 +345,10 @@ impl PositionData {
pub fn position(&self, frame: usize) -> Vector { pub fn position(&self, frame: usize) -> Vector {
match self { match self {
PositionData::Vector48(vector) => Vector::from(*vector), PositionData::Vector48(vector) => Vector::from(*vector),
PositionData::PositionValues(values) => values.get(frame).copied().unwrap_or_default(), PositionData::PositionValues(values) => values
.get(frame)
.copied()
.unwrap_or_else(|| values.last().copied().unwrap_or_default()),
PositionData::None => Vector::default(), PositionData::None => Vector::default(),
} }
} }
@ -364,12 +380,13 @@ impl Animation {
self.rotation_data.rotation(frame) self.rotation_data.rotation(frame)
} }
pub fn position(&self, frame: usize) -> Vector { pub fn translation(&self, frame: usize) -> Vector {
self.position_data.position(frame) self.position_data.position(frame)
} }
pub fn transform(&self, frame: usize) -> Matrix4<f32> { pub fn transform(&self, frame: usize) -> Matrix4<f32> {
Matrix4::from_translation(self.position(frame).into()) * Matrix4::from(self.rotation(frame)) Matrix4::from(self.rotation(frame))
* Matrix4::from_translation(self.translation(frame).into())
} }
pub(crate) fn apply_bone_data(&mut self, bone: &Bone) { pub(crate) fn apply_bone_data(&mut self, bone: &Bone) {
@ -399,10 +416,9 @@ fn read_animation(
} else if header.flags.contains(AnimationFlags::STUDIO_ANIM_RAWROT2) { } else if header.flags.contains(AnimationFlags::STUDIO_ANIM_RAWROT2) {
RotationData::from(read_single::<Quaternion64, _>(data, offset)?) RotationData::from(read_single::<Quaternion64, _>(data, offset)?)
} else if header.flags.contains(AnimationFlags::STUDIO_ANIM_ANIMROT) { } else if header.flags.contains(AnimationFlags::STUDIO_ANIM_ANIMROT) {
let pointers: AnimationValuePointer = read_single(data, offset)?; let pointers: AnimationValuePointers = read_single(data, offset)?;
let value_data = &data[offset..];
let values: Vec<RadianEuler> = (0..frames) let values: Vec<RadianEuler> = (0..frames)
.map(|frame| read_animation_values(value_data, frame, pointers)) .map(|frame| read_animation_values(frame, pointers))
.map_ok(|[pitch, yaw, roll]| RadianEuler { pitch, yaw, roll }) .map_ok(|[pitch, yaw, roll]| RadianEuler { pitch, yaw, roll })
.collect::<Result<_, ModelError>>()?; .collect::<Result<_, ModelError>>()?;
RotationData::from(values) RotationData::from(values)
@ -414,10 +430,9 @@ fn read_animation(
let position_data = if header.flags.contains(AnimationFlags::STUDIO_ANIM_RAWPOS) { let position_data = if header.flags.contains(AnimationFlags::STUDIO_ANIM_RAWPOS) {
PositionData::Vector48(read_single(data, position_offset)?) PositionData::Vector48(read_single(data, position_offset)?)
} else if header.flags.contains(AnimationFlags::STUDIO_ANIM_ANIMPOS) { } else if header.flags.contains(AnimationFlags::STUDIO_ANIM_ANIMPOS) {
let pointers: AnimationValuePointer = read_single(data, position_offset)?; let pointers: AnimationValuePointers = read_single(data, position_offset)?;
let value_data = &data[position_offset..];
let values = (0..frames) let values = (0..frames)
.map(|frame| read_animation_values(value_data, frame, pointers)) .map(|frame| read_animation_values(frame, pointers))
.map_ok(Vector::from) .map_ok(Vector::from)
.collect::<Result<_, ModelError>>()?; .collect::<Result<_, ModelError>>()?;
PositionData::PositionValues(values) PositionData::PositionValues(values)

View file

@ -41,6 +41,12 @@ impl Display for BoneId {
} }
} }
impl PartialEq<u8> for BoneId {
fn eq(&self, other: &u8) -> bool {
self.0 == *other
}
}
#[derive(Debug, Clone, Copy, Zeroable, Pod)] #[derive(Debug, Clone, Copy, Zeroable, Pod)]
#[repr(C)] #[repr(C)]
pub struct BoneHeader { pub struct BoneHeader {

View file

@ -1,7 +1,7 @@
use crate::{ModelError, StringError}; use crate::{ModelError, StringError};
use arrayvec::ArrayString; use arrayvec::ArrayString;
use bytemuck::{Pod, Zeroable}; use bytemuck::{Pod, Zeroable};
use cgmath::{Angle, Deg, Euler, InnerSpace, Matrix3, Matrix4, Rad, Rotation3, Transform, Vector3}; use cgmath::{Deg, Euler, Matrix3, Matrix4, Point3, Rad, Rotation3, Transform, Vector3};
use std::f32::consts::PI; use std::f32::consts::PI;
use std::fmt; use std::fmt;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
@ -35,6 +35,26 @@ impl From<Vector3<f32>> for Vector {
} }
} }
impl From<Vector> for Point3<f32> {
fn from(v: Vector) -> Self {
Self {
x: v.x,
y: v.y,
z: v.z,
}
}
}
impl From<Point3<f32>> for Vector {
fn from(v: Point3<f32>) -> Self {
Self {
x: v.x,
y: v.y,
z: v.z,
}
}
}
impl Vector { impl Vector {
pub fn iter(&self) -> impl Iterator<Item = f32> { pub fn iter(&self) -> impl Iterator<Item = f32> {
[self.x, self.y, self.z].into_iter() [self.x, self.y, self.z].into_iter()
@ -321,23 +341,15 @@ impl Transform3x4 {
mapped_rotation.into() mapped_rotation.into()
} }
pub fn transform(&self, vec: Vector) -> Vector {
let vec: Vector3<f32> = [vec.y, vec.z, vec.x].into();
let z = vec.dot(self.x()) + self.transform[0][3];
let x = vec.dot(self.y()) + self.transform[1][3];
let y = vec.dot(self.z()) + self.transform[2][3];
Vector { x, y, z }
}
pub fn rotation(&self) -> Quaternion { pub fn rotation(&self) -> Quaternion {
cgmath::Quaternion::from(self.rotation_matrix()).into() cgmath::Quaternion::from(self.rotation_matrix()).into()
} }
pub fn translate(&self) -> Vector { pub fn translate(&self) -> Vector {
[ [
self.transform[2][3],
self.transform[0][3], self.transform[0][3],
self.transform[1][3], self.transform[1][3],
self.transform[2][3],
] ]
.into() .into()
} }
@ -345,9 +357,8 @@ impl Transform3x4 {
impl From<Transform3x4> for Matrix4<f32> { impl From<Transform3x4> for Matrix4<f32> {
fn from(value: Transform3x4) -> Self { fn from(value: Transform3x4) -> Self {
let translate = value.translate(); let translate = Matrix4::from_translation(value.translate().into());
let rotate = value.rotation_matrix(); let rotate = Matrix4::from(value.rotation_matrix());
let rotate = Matrix4::from(rotate); rotate * translate
rotate * Matrix4::from_translation(translate.into())
} }
} }