mirror of
https://codeberg.org/icewind/vmdl.git
synced 2026-06-03 16:44:11 +02:00
more orientation work
This commit is contained in:
parent
7f4adac2db
commit
d40299f3aa
7 changed files with 252 additions and 180 deletions
32
src/lib.rs
32
src/lib.rs
|
|
@ -11,7 +11,7 @@ pub use crate::vtx::Vtx;
|
|||
use crate::vvd::Vertex;
|
||||
pub use crate::vvd::Vvd;
|
||||
use bytemuck::{pod_read_unaligned, Contiguous, Pod};
|
||||
use cgmath::{Matrix4, SquareMatrix};
|
||||
use cgmath::{Matrix4, SquareMatrix, Transform, Vector3};
|
||||
pub use error::*;
|
||||
pub use handle::Handle;
|
||||
use itertools::Either;
|
||||
|
|
@ -134,9 +134,12 @@ impl Model {
|
|||
}
|
||||
|
||||
pub fn root_transform(&self) -> Matrix4<f32> {
|
||||
if self.bones().next().map(|bone| bone.name.as_str()) == Some("static_prop") {
|
||||
return Matrix4::identity();
|
||||
}
|
||||
self.bones()
|
||||
.next()
|
||||
.map(|bone| Quaternion::from(bone.rot))
|
||||
.find(|bone| bone.name != "root")
|
||||
.map(|bone| bone.pose_to_bone)
|
||||
.map(Matrix4::from)
|
||||
.unwrap_or_else(Matrix4::identity)
|
||||
}
|
||||
|
|
@ -150,13 +153,22 @@ impl Model {
|
|||
}
|
||||
|
||||
pub fn vertex_to_world_space(&self, vertex: &Vertex) -> Vector {
|
||||
let mut pos = vertex.position;
|
||||
for weights in vertex.bone_weights.weights() {
|
||||
if let Some(bone) = self.mdl.bones.get(weights.bone_id as usize) {
|
||||
pos = pos.transformed(bone.pose_to_bone);
|
||||
}
|
||||
}
|
||||
pos
|
||||
vertex.position.transformed(self.root_transform())
|
||||
// let mut pos = Vector3::from(vertex.position);
|
||||
// for weights in vertex.bone_weights.weights() {
|
||||
// if let Some(bone) = self.mdl.bones.get(weights.bone_id as usize) {
|
||||
// let transform = Quaternion::from(bone.rot);
|
||||
// if bone.parent == 0 {
|
||||
// if bone.name == "joint1" {
|
||||
// dbg!(&bone.name, bone.rot, transform);
|
||||
// }
|
||||
// let transform = Matrix4::from(transform);
|
||||
// pos = transform.transform_vector(pos);
|
||||
// // pos = bone.pose_to_bone.transform(pos);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// pos.into()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
mod raw;
|
||||
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
pub use raw::header::*;
|
||||
pub use raw::header2::*;
|
||||
pub use raw::*;
|
||||
use std::mem::size_of;
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
|
||||
use crate::vvd::Vertex;
|
||||
use crate::{read_relative, read_relative_iter, read_single, FixedString, ModelError, ReadRelative, Readable, Transform3x4, Vector};
|
||||
use crate::{
|
||||
read_relative, read_relative_iter, read_single, FixedString, ModelError, ReadRelative,
|
||||
Readable, Transform3x4, Vector,
|
||||
};
|
||||
|
||||
type Result<T> = std::result::Result<T, ModelError>;
|
||||
|
||||
|
|
@ -54,9 +57,6 @@ impl Mdl {
|
|||
let skin_table = read_relative::<u16, _>(data, header.skin_reference_indexes())?;
|
||||
let bones = read_relative(data, header.bone_indexes())?;
|
||||
|
||||
// are these used?
|
||||
let _source_bone_transforms: Vec<SourceBoneTransform> = read_relative(data, header2.unwrap().source_bone_transforms())?;
|
||||
|
||||
let surface_prop = read_single(data, header.surface_prop_index)?;
|
||||
let key_values = (header.key_value_size > 0)
|
||||
.then(|| read_single(data, header.key_value_index))
|
||||
|
|
@ -165,7 +165,11 @@ impl ReadRelative for TextureInfo {
|
|||
|
||||
fn read(data: &[u8], header: Self::Header) -> Result<Self> {
|
||||
Ok(TextureInfo {
|
||||
name: String::read(&data[header.name_index as usize..], ())?.replace('\\', "/"),
|
||||
name: String::read(
|
||||
data.get(header.name_index as usize..).unwrap_or_default(),
|
||||
(),
|
||||
)?
|
||||
.replace('\\', "/"),
|
||||
name_index: header.name_index,
|
||||
search_paths: Vec::new(),
|
||||
})
|
||||
|
|
@ -185,7 +189,11 @@ impl ReadRelative for StudioAttachment {
|
|||
|
||||
fn read(data: &[u8], header: Self::Header) -> Result<Self> {
|
||||
Ok(StudioAttachment {
|
||||
name: String::read(&data[header.name_index as usize..], ())?.replace('\\', "/"),
|
||||
name: String::read(
|
||||
data.get(header.name_index as usize..).unwrap_or_default(),
|
||||
(),
|
||||
)?
|
||||
.replace('\\', "/"),
|
||||
flags: header.flags,
|
||||
local: header.local,
|
||||
local_bone: header.local_bone,
|
||||
|
|
@ -196,7 +204,7 @@ impl ReadRelative for StudioAttachment {
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct HitBoxSet {
|
||||
pub name: String,
|
||||
pub boxes: Vec<BoundingBox>
|
||||
pub boxes: Vec<BoundingBox>,
|
||||
}
|
||||
|
||||
impl ReadRelative for HitBoxSet {
|
||||
|
|
@ -204,8 +212,12 @@ impl ReadRelative for HitBoxSet {
|
|||
|
||||
fn read(data: &[u8], header: Self::Header) -> Result<Self> {
|
||||
Ok(HitBoxSet {
|
||||
name: String::read(&data[header.name_index as usize..], ())?.replace('\\', "/"),
|
||||
boxes: read_relative(data, header.hitbox_indexes())?
|
||||
name: String::read(
|
||||
data.get(header.name_index as usize..).unwrap_or_default(),
|
||||
(),
|
||||
)?
|
||||
.replace('\\', "/"),
|
||||
boxes: read_relative(data, header.hitbox_indexes())?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -216,7 +228,7 @@ pub struct BoundingBox {
|
|||
pub bone: i32,
|
||||
pub group: i32,
|
||||
pub min: Vector,
|
||||
pub max: Vector
|
||||
pub max: Vector,
|
||||
}
|
||||
|
||||
impl ReadRelative for BoundingBox {
|
||||
|
|
@ -224,11 +236,15 @@ impl ReadRelative for BoundingBox {
|
|||
|
||||
fn read(data: &[u8], header: Self::Header) -> Result<Self> {
|
||||
Ok(BoundingBox {
|
||||
name: String::read(&data[header.name_index as usize..], ())?.replace('\\', "/"),
|
||||
name: String::read(
|
||||
data.get(header.name_index as usize..).unwrap_or_default(),
|
||||
(),
|
||||
)?
|
||||
.replace('\\', "/"),
|
||||
bone: header.bone,
|
||||
group: header.group,
|
||||
min: header.bounding_box_min,
|
||||
max: header.bounding_box_max,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ pub struct AnimationDescriptionHeader {
|
|||
_padding: [i32; 6],
|
||||
|
||||
animation_block: i32,
|
||||
animation_index: i32,
|
||||
animation_index: i32, // non-zero when anim data isn't in sections
|
||||
|
||||
ik_rule_count: i32,
|
||||
ik_rule_offset: i32,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{ModelError, StringError};
|
||||
use arrayvec::ArrayString;
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use cgmath::{Deg, Euler, Matrix3, Matrix4, Rad, Rotation3, Vector3, Vector4};
|
||||
use cgmath::{Deg, Euler, InnerSpace, Matrix3, Matrix4, Rad, Rotation3, Transform, Vector3};
|
||||
use std::fmt;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::ops::{Add, Mul};
|
||||
|
|
@ -41,8 +41,7 @@ impl Vector {
|
|||
|
||||
pub fn transformed<T: Into<Matrix4<f32>>>(&self, transform: T) -> Vector {
|
||||
let transform = transform.into();
|
||||
let transformed = transform * Vector4::new(self.x, self.y, self.z, 1.0);
|
||||
transformed.truncate().into()
|
||||
transform.transform_vector(self.clone().into()).into()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -155,9 +154,10 @@ impl From<RadianEuler> for Euler<Deg<f32>> {
|
|||
impl From<RadianEuler> for cgmath::Quaternion<f32> {
|
||||
fn from(value: RadianEuler) -> Self {
|
||||
// angles are applied in roll, pitch, yaw order
|
||||
cgmath::Quaternion::from_angle_y(Rad(value.x))
|
||||
* cgmath::Quaternion::from_angle_x(Rad(value.y))
|
||||
* cgmath::Quaternion::from_angle_z(Rad(-value.z))
|
||||
// additionally the access are remapped
|
||||
cgmath::Quaternion::from_angle_y(Rad(value.y))
|
||||
* cgmath::Quaternion::from_angle_x(Rad(-value.z))
|
||||
* cgmath::Quaternion::from_angle_z(Rad(value.x))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -213,25 +213,55 @@ pub struct Transform3x4 {
|
|||
}
|
||||
|
||||
impl Transform3x4 {
|
||||
pub fn rotation_matrix(&self) -> Matrix3<f32> {
|
||||
Matrix3 {
|
||||
x: Vector3 {
|
||||
x: self.transform[0][0],
|
||||
y: self.transform[0][1],
|
||||
z: self.transform[0][2],
|
||||
},
|
||||
y: Vector3 {
|
||||
x: self.transform[1][0],
|
||||
y: self.transform[1][1],
|
||||
z: self.transform[1][2],
|
||||
},
|
||||
z: Vector3 {
|
||||
x: self.transform[2][0],
|
||||
y: self.transform[2][1],
|
||||
z: self.transform[2][2],
|
||||
},
|
||||
fn x(&self) -> Vector3<f32> {
|
||||
Vector3 {
|
||||
x: self.transform[0][0],
|
||||
y: self.transform[0][1],
|
||||
z: self.transform[0][2],
|
||||
}
|
||||
}
|
||||
fn y(&self) -> Vector3<f32> {
|
||||
Vector3 {
|
||||
x: self.transform[1][0],
|
||||
y: self.transform[1][1],
|
||||
z: self.transform[1][2],
|
||||
}
|
||||
}
|
||||
fn z(&self) -> Vector3<f32> {
|
||||
Vector3 {
|
||||
x: self.transform[2][0],
|
||||
y: self.transform[2][1],
|
||||
z: self.transform[2][2],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rotation_matrix(&self) -> Matrix3<f32> {
|
||||
let mat = Matrix3 {
|
||||
x: self.x(),
|
||||
y: self.y(),
|
||||
z: self.z(),
|
||||
};
|
||||
// mat
|
||||
let quat = cgmath::Quaternion::from(mat);
|
||||
let euler = Euler::from(quat);
|
||||
#[cfg(debug_assertions)]
|
||||
dbg!(euler);
|
||||
let mapped_rotation = cgmath::Quaternion::from_angle_x(-euler.z)
|
||||
* cgmath::Quaternion::from_angle_y(euler.y)
|
||||
* cgmath::Quaternion::from_angle_z(euler.x);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
dbg!(Euler::from(mapped_rotation));
|
||||
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 {
|
||||
cgmath::Quaternion::from(self.rotation_matrix()).into()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue