1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
use bspline;
use la;
use linalg::{quaternion, Vector, Matrix4, Quaternion, Transform};
#[derive(Debug, Copy, Clone)]
pub struct Keyframe {
pub translation: Vector,
pub rotation: Quaternion,
pub scaling: Vector,
}
impl Keyframe {
pub fn new(transform: &Transform) -> Keyframe {
let (t, r, s) = Keyframe::decompose(transform);
Keyframe { translation: t, rotation: r, scaling: s }
}
pub fn from_parts(translation: &Vector, rotation: &Quaternion, scaling: &Vector) -> Keyframe {
Keyframe { translation: *translation, rotation: *rotation, scaling: *scaling }
}
fn decompose(transform: &Transform) -> (Vector, Quaternion, Vector) {
let m = transform.mat;
let translation = Vector::new(*m.at(0, 3), *m.at(1, 3), *m.at(2, 3));
let la_mat = la::Matrix::<f64>::new(3, 3, vec![*m.at(0, 0) as f64, *m.at(0, 1) as f64, *m.at(0, 2) as f64,
*m.at(1, 0) as f64, *m.at(1, 1) as f64, *m.at(1, 2) as f64,
*m.at(2, 0) as f64, *m.at(2, 1) as f64, *m.at(2, 2) as f64]);
let svd = la::SVD::<f64>::new(&la_mat);
let mut q = svd.get_u() * svd.get_v().t();
let mut p = svd.get_v() * svd.get_s() * svd.get_v().t();
if q.det() < 0.0 {
q = -q;
p = -p;
}
let rotation = Quaternion::from_matrix(
&Matrix4::new([q.get(0, 0) as f32, q.get(0, 1) as f32, q.get(0, 2) as f32, 0.0,
q.get(1, 0) as f32, q.get(1, 1) as f32, q.get(1, 2) as f32, 0.0,
q.get(2, 0) as f32, q.get(2, 1) as f32, q.get(2, 2) as f32, 0.0,
0.0, 0.0, 0.0, 1.0]));
let scaling = Vector::new(p.get(0, 0) as f32, p.get(1, 1) as f32, p.get(2, 2) as f32);
(translation, rotation, scaling)
}
pub fn transform(&self) -> Transform {
let m = self.rotation.to_matrix();
Transform::translate(&self.translation) * Transform::from_mat(&m) * Transform::scale(&self.scaling)
}
}
impl bspline::Interpolate for Keyframe {
fn interpolate(&self, other: &Keyframe, t: f32) -> Keyframe {
let translation = (1.0 - t) * self.translation + t * other.translation;
let rotation = quaternion::slerp(t, &self.rotation, &other.rotation);
let scaling = (1.0 - t) * self.scaling + t * other.scaling;
Keyframe::from_parts(&translation, &rotation, &scaling)
}
}