Skip to content

Commit

Permalink
Merge pull request #38 from SlimeYummy/feat/cpp-tests
Browse files Browse the repository at this point in the history
add cpp tests
  • Loading branch information
SlimeYummy authored Jan 31, 2024
2 parents bff9b93 + 7d9e063 commit b6431d1
Show file tree
Hide file tree
Showing 65 changed files with 176 additions and 107 deletions.
Binary file modified expected/blend/blend+0.00.rkyv
Binary file not shown.
Binary file modified expected/blend/blend+0.10.rkyv
Binary file not shown.
Binary file modified expected/blend/blend+0.20.rkyv
Binary file not shown.
Binary file modified expected/blend/blend+0.30.rkyv
Binary file not shown.
Binary file modified expected/blend/blend+0.40.rkyv
Binary file not shown.
Binary file modified expected/blend/blend+0.50.rkyv
Binary file not shown.
Binary file modified expected/blend/blend+0.60.rkyv
Binary file not shown.
Binary file modified expected/blend/blend+0.70.rkyv
Binary file not shown.
Binary file modified expected/blend/blend+0.80.rkyv
Binary file not shown.
Binary file modified expected/blend/blend+0.90.rkyv
Binary file not shown.
Binary file modified expected/blend/blend+1.00.rkyv
Binary file not shown.
Binary file modified expected/blend/blend+1.10.rkyv
Binary file not shown.
Binary file modified expected/blend/blend-0.10.rkyv
Binary file not shown.
Binary file added expected/blend/blend_cpp.bin
Binary file not shown.
Binary file added expected/look_at/look_at_00.rkyv
Binary file not shown.
Binary file added expected/look_at/look_at_01.rkyv
Binary file not shown.
Binary file added expected/look_at/look_at_02.rkyv
Binary file not shown.
Binary file added expected/look_at/look_at_03.rkyv
Binary file not shown.
Binary file added expected/look_at/look_at_04.rkyv
Binary file not shown.
Binary file added expected/look_at/look_at_05.rkyv
Binary file not shown.
Binary file added expected/look_at/look_at_06.rkyv
Binary file not shown.
Binary file added expected/look_at/look_at_07.rkyv
Binary file not shown.
Binary file added expected/look_at/look_at_08.rkyv
Binary file not shown.
Binary file added expected/look_at/look_at_09.rkyv
Binary file not shown.
Binary file added expected/look_at/look_at_10.rkyv
Binary file not shown.
Binary file added expected/look_at/look_at_cpp.bin
Binary file not shown.
Binary file removed expected/look_at/look_at_ik_00.rkyv
Binary file not shown.
Binary file removed expected/look_at/look_at_ik_01.rkyv
Binary file not shown.
Binary file removed expected/look_at/look_at_ik_02.rkyv
Binary file not shown.
Binary file removed expected/look_at/look_at_ik_03.rkyv
Binary file not shown.
Binary file removed expected/look_at/look_at_ik_04.rkyv
Binary file not shown.
Binary file removed expected/look_at/look_at_ik_05.rkyv
Binary file not shown.
Binary file removed expected/look_at/look_at_ik_06.rkyv
Binary file not shown.
Binary file removed expected/look_at/look_at_ik_07.rkyv
Binary file not shown.
Binary file removed expected/look_at/look_at_ik_08.rkyv
Binary file not shown.
Binary file removed expected/look_at/look_at_ik_09.rkyv
Binary file not shown.
Binary file removed expected/look_at/look_at_ik_10.rkyv
Binary file not shown.
Binary file modified expected/playback/playback+0.00.rkyv
Binary file not shown.
Binary file modified expected/playback/playback+0.10.rkyv
Binary file not shown.
Binary file modified expected/playback/playback+0.20.rkyv
Binary file not shown.
Binary file modified expected/playback/playback+0.30.rkyv
Binary file not shown.
Binary file modified expected/playback/playback+0.40.rkyv
Binary file not shown.
Binary file modified expected/playback/playback+0.50.rkyv
Binary file not shown.
Binary file modified expected/playback/playback+0.60.rkyv
Binary file not shown.
Binary file modified expected/playback/playback+0.70.rkyv
Binary file not shown.
Binary file modified expected/playback/playback+0.80.rkyv
Binary file not shown.
Binary file modified expected/playback/playback+0.90.rkyv
Binary file not shown.
Binary file modified expected/playback/playback+1.00.rkyv
Binary file not shown.
Binary file modified expected/playback/playback+1.10.rkyv
Binary file not shown.
Binary file modified expected/playback/playback-0.10.rkyv
Binary file not shown.
Binary file added expected/playback/playback_cpp.bin
Binary file not shown.
Binary file modified expected/two_bone_ik/two_bone_ik_00.rkyv
Binary file not shown.
Binary file modified expected/two_bone_ik/two_bone_ik_01.rkyv
Binary file not shown.
Binary file modified expected/two_bone_ik/two_bone_ik_05.rkyv
Binary file not shown.
Binary file modified expected/two_bone_ik/two_bone_ik_06.rkyv
Binary file not shown.
Binary file modified expected/two_bone_ik/two_bone_ik_07.rkyv
Binary file not shown.
Binary file added expected/two_bone_ik/two_bone_ik_cpp.bin
Binary file not shown.
39 changes: 21 additions & 18 deletions src/animation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,10 @@ impl QuaternionKey {
k3: &QuaternionKey,
soa: &mut SoaQuat,
) {
const INT_2_FLOAT: f32x4 = f32x4::from_array([1.0f32 / (32767.0f32 * core::f32::consts::SQRT_2); 4]);
const INT_2_FLOAT: f32x4 = f32x4::from_array([1.0 / (32767.0 * core::f32::consts::SQRT_2); 4]);

const ONE: f32x4 = f32x4::from_array([1.0f32; 4]);
const SMALL: f32x4 = f32x4::from_array([1e-16f32; 4]);
const ONE: f32x4 = f32x4::from_array([1.0; 4]);
const SMALL: f32x4 = f32x4::from_array([1e-16; 4]);

const MASK_F000:i32x4 = i32x4::from_array([-1i32, 0, 0, 0]);
const MASK_0F00:i32x4 = i32x4::from_array([0, -1i32, 0, 0]);
Expand All @@ -137,26 +137,26 @@ impl QuaternionKey {
let m2 = &MAPPING[k2.largest() as usize];
let m3 = &MAPPING[k3.largest() as usize];

let mut cmp_keys: [[f32; 4]; 4] = [
[ k0.value[m0[0]] as f32, k1.value[m1[0]] as f32, k2.value[m2[0]] as f32, k3.value[m3[0]] as f32 ],
[ k0.value[m0[1]] as f32, k1.value[m1[1]] as f32, k2.value[m2[1]] as f32, k3.value[m3[1]] as f32 ],
[ k0.value[m0[2]] as f32, k1.value[m1[2]] as f32, k2.value[m2[2]] as f32, k3.value[m3[2]] as f32 ],
[ k0.value[m0[3]] as f32, k1.value[m1[3]] as f32, k2.value[m2[3]] as f32, k3.value[m3[3]] as f32 ],
let mut cmp_keys: [f32x4; 4] = [
f32x4::from_array([ k0.value[m0[0]] as f32, k1.value[m1[0]] as f32, k2.value[m2[0]] as f32, k3.value[m3[0]] as f32 ]),
f32x4::from_array([ k0.value[m0[1]] as f32, k1.value[m1[1]] as f32, k2.value[m2[1]] as f32, k3.value[m3[1]] as f32 ]),
f32x4::from_array([ k0.value[m0[2]] as f32, k1.value[m1[2]] as f32, k2.value[m2[2]] as f32, k3.value[m3[2]] as f32 ]),
f32x4::from_array([ k0.value[m0[3]] as f32, k1.value[m1[3]] as f32, k2.value[m2[3]] as f32, k3.value[m3[3]] as f32 ]),
]; // TODO: simd int to float
cmp_keys[k0.largest() as usize][0] = 0.0f32;
cmp_keys[k1.largest() as usize][1] = 0.0f32;
cmp_keys[k2.largest() as usize][2] = 0.0f32;
cmp_keys[k3.largest() as usize][3] = 0.0f32;

let mut cpnt = [
INT_2_FLOAT * f32x4::from_array(cmp_keys[0]),
INT_2_FLOAT * f32x4::from_array(cmp_keys[1]),
INT_2_FLOAT * f32x4::from_array(cmp_keys[2]),
INT_2_FLOAT * f32x4::from_array(cmp_keys[3]),
INT_2_FLOAT * cmp_keys[0],
INT_2_FLOAT * cmp_keys[1],
INT_2_FLOAT * cmp_keys[2],
INT_2_FLOAT * cmp_keys[3],
];
let dot = cpnt[0] * cpnt[0] + cpnt[1] * cpnt[1] + cpnt[2] * cpnt[2] + cpnt[3] * cpnt[3];
let ww0 = f32x4::simd_max(SMALL, ONE - dot);
let w0 = ww0 * ww0.recip().sqrt();
let w0 = ww0.sqrt();
let sign = i32x4::from_array([k0.sign() as i32, k1.sign() as i32, k2.sign() as i32, k3.sign() as i32]) << 31;
let restored = ix4(w0) | sign;

Expand Down Expand Up @@ -229,7 +229,10 @@ impl ArchiveReader<Animation> for Animation {
let rotation_count: i32 = archive.read()?;
let scale_count: i32 = archive.read()?;

let name: String = archive.read_string(name_len as usize)?;
let mut name = String::new();
if name_len != 0 {
name = archive.read_string(name_len as usize)?;
}
let translations: Vec<Float3Key> = archive.read_vec(translation_count as usize)?;
let rotations: Vec<QuaternionKey> = archive.read_vec(rotation_count as usize)?;
let scales: Vec<Float3Key> = archive.read_vec(scale_count as usize)?;
Expand Down Expand Up @@ -436,10 +439,10 @@ mod tests {
assert_eq!(
soa,
SoaQuat {
x: f32x4::from_array([0.008545618438802194, 0.767303715540273, 0.00000000, -0.501839280]),
y: f32x4::from_array([0.008826156417853781, 0.11342366291501094, 0.00000000, -0.507083178]),
z: f32x4::from_array([0.006085516160965199, -0.3139651582478109, -0.00420806976, -0.525850952]),
w: f32x4::from_array([0.9999060145140845, 0.5475453955750709, 0.999991119, 0.463146627]),
x: f32x4::from_array([0.0085456185, 0.7673037, 0.0, -0.5018393]),
y: f32x4::from_array([0.008826156, 0.11342366, 0.0, -0.5070832]),
z: f32x4::from_array([0.006085516, -0.31396517, -0.0042080698, -0.52585095]),
w: f32x4::from_array([0.999906, 0.5475454, 0.9999911, 0.46314663]),
}
);
}
Expand Down
4 changes: 2 additions & 2 deletions src/ik_aim_job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ impl IKAimJob {
let rotate_plane_axis_js;
let rotate_plane_js;
if denoms.simd_ne(ZERO).to_bitmask() & 0x7 == 0x7 {
let rsqrts = denoms.recip().sqrt();
let rsqrts = denoms.sqrt().recip();
rotate_plane_axis_js = joint_to_target_js * fx4_splat_x(rsqrts);

let rotate_plane_cos_angle = vec3_dot_s(
Expand All @@ -173,7 +173,7 @@ impl IKAimJob {
rotate_plane_cos_angle.simd_clamp(NEG_ONE, ONE),
);
} else {
rotate_plane_axis_js = joint_to_target_js * fx4_splat_x(denoms.sqrt());
rotate_plane_axis_js = joint_to_target_js * fx4_splat_x(denoms.sqrt().recip());
rotate_plane_js = QUAT_UNIT;
}

Expand Down
10 changes: 5 additions & 5 deletions src/ik_two_bone_job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ impl IKTwoBoneJob {
fn compute_mid_joint(&self, setup: &IKConstantSetup, start_target_ss_len2: f32x4) -> f32x4 {
let start_mid_end_sum_ss_len2 = setup.start_mid_ss_len2 + setup.mid_end_ss_len2; // [x]
let start_mid_end_ss_half_rlen =
fx4_splat_x(FRAC_1_2 * (setup.start_mid_ss_len2 * setup.mid_end_ss_len2).recip().sqrt()); // [x]
fx4_splat_x(FRAC_1_2 * (setup.start_mid_ss_len2 * setup.mid_end_ss_len2).sqrt().recip()); // [x]

let mid_cos_angles_unclamped = (fx4_splat_x(start_mid_end_sum_ss_len2)
- fx4_set_y(start_target_ss_len2, setup.start_end_ss_len2))
Expand Down Expand Up @@ -309,8 +309,8 @@ impl IKTwoBoneJob {
fx4_set_y(start_target_ss_len2, ref_plane_normal_ss_len2),
joint_plane_normal_ss_len2,
)
.recip()
.sqrt(); // [x y z]
.sqrt()
.recip(); // [x y z]

let rotate_plane_cos_angle = vec3_dot_s(
ref_plane_normal_ss * fx4_splat_y(rsqrts),
Expand Down Expand Up @@ -353,8 +353,8 @@ impl IKTwoBoneJob {
0.0,
0.0,
])
.recip()
.sqrt();
.sqrt()
.recip();

self.start_joint_correction = start_lerp * fx4_splat_x(rsqrts);
self.mid_joint_correction = mid_lerp * fx4_splat_y(rsqrts);
Expand Down
8 changes: 4 additions & 4 deletions src/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1049,8 +1049,8 @@ pub(crate) fn fx4_sin_cos(v: f32x4) -> (f32x4, f32x4) {
let cos_sign = bit1 ^ bit2;

// Correct the signs
let out_sin = sin_sign.simd_eq(SIGN).select(-s, s);
let out_cos = cos_sign.simd_eq(SIGN).select(-c, c);
let out_sin = fx4_xor(s, sin_sign);
let out_cos = fx4_xor(c, cos_sign);
return (out_sin, out_cos);
}

Expand Down Expand Up @@ -1083,7 +1083,7 @@ pub(crate) fn fx4_asin(v: f32x4) -> f32x4 {
const N5: f32x4 = f32x4::from_array([1.6666752422e-1; 4]);

// Make argument positive
let non_neg = v.simd_ge(ZERO);
let asin_sign = fx4_sign(v);
let mut a = v.abs();

// ASin is not defined outside the range [-1, 1] but it often happens that a value is slightly above 1 so we just clamp here
Expand All @@ -1109,7 +1109,7 @@ pub(crate) fn fx4_asin(v: f32x4) -> f32x4 {
z = greater.select(FRAC_PI_2 - (z + z), z);

// Put the sign back
return non_neg.select(z, -z);
return fx4_xor(z, asin_sign);
}

#[inline]
Expand Down
74 changes: 45 additions & 29 deletions tests/blend.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
#![cfg(feature = "rkyv")]

use glam::Mat4;
use ozz_animation_rs::*;
use rkyv::{Archive, Deserialize, Serialize};
use std::rc::Rc;

#[derive(Debug, PartialEq, Archive, Serialize, Deserialize)]
#[derive(Debug, PartialEq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
struct TestData {
ratio: f32,
sample_out1: Vec<SoaTransform>,
Expand All @@ -19,7 +16,25 @@ struct TestData {
}

#[test]
fn test_deterministic_blend() {
fn test_blend() {
run_blend(2..=2, |_, data| {
test_utils::compare_with_cpp("blend", "blend", &data.l2m_out, 1e-6).unwrap();
});
}

#[cfg(feature = "rkyv")]
#[test]
fn test_blend_deterministic() {
run_blend(-1..=11, |ratio, data| {
test_utils::compare_with_rkyv("blend", &format!("blend{:+.2}", ratio), data).unwrap();
});
}

fn run_blend<I, T>(range: I, tester: T)
where
I: Iterator<Item = i32>,
T: Fn(f32, &TestData),
{
let skeleton = Rc::new(Skeleton::from_file("./resource/blend/skeleton.ozz").unwrap());
let animation1 = Rc::new(Animation::from_file("./resource/blend/animation1.ozz").unwrap());
let animation2 = Rc::new(Animation::from_file("./resource/blend/animation2.ozz").unwrap());
Expand Down Expand Up @@ -57,40 +72,41 @@ fn test_deterministic_blend() {
let l2m_out = ozz_buf(vec![Mat4::default(); skeleton.num_joints()]);
l2m_job.set_output(l2m_out.clone());

for i in -1..=11 {
let r = i as f32 / 10.0;
for i in range {
let ratio = i as f32 / 10.0;

sample_job1.set_ratio(r);
sample_job1.set_ratio(ratio);
sample_job1.run().unwrap();
sample_job2.set_ratio(r);
sample_job2.set_ratio(ratio);
sample_job2.run().unwrap();
sample_job3.set_ratio(r);
sample_job3.set_ratio(ratio);
sample_job3.run().unwrap();

blending_job.layers_mut()[0].weight = (1.0 - 2.0 * r).clamp(0.0, 1.0); // 0%=1.0, 50%=0.0, 100%=0.0
blending_job.layers_mut()[2].weight = (2.0 * r - 1.0).clamp(0.0, 1.0); // 0%=0.0, 50%=0.0, 100%=1.0
// 0%=0.0, 50%=1.0, 100%=0.0
if r < 0.5 {
blending_job.layers_mut()[1].weight = (2.0 * r).clamp(0.0, 1.0);
blending_job.layers_mut()[0].weight = (1.0 - 2.0 * ratio).clamp(0.0, 1.0); // 0%=1.0, 50%=0.0, 100%=0.0
blending_job.layers_mut()[2].weight = (2.0 * ratio - 1.0).clamp(0.0, 1.0); // 0%=0.0, 50%=0.0, 100%=1.0
// 0%=0.0, 50%=1.0, 100%=0.0
if ratio < 0.5 {
blending_job.layers_mut()[1].weight = (2.0 * ratio).clamp(0.0, 1.0);
} else {
blending_job.layers_mut()[1].weight = (2.0 * (1.0 - r)).clamp(0.0, 1.0);
blending_job.layers_mut()[1].weight = (2.0 * (1.0 - ratio)).clamp(0.0, 1.0);
}
blending_job.run().unwrap();

l2m_job.run().unwrap();

let data = TestData {
ratio: r,
sample_out1: sample_out1.vec().unwrap().clone(),
sample_ctx1: sample_job1.context().unwrap().clone_without_animation_id(),
sample_out2: sample_out2.vec().unwrap().clone(),
sample_ctx2: sample_job2.context().unwrap().clone_without_animation_id(),
sample_out3: sample_out3.vec().unwrap().clone(),
sample_ctx3: sample_job3.context().unwrap().clone_without_animation_id(),
blending_out: blending_out.vec().unwrap().clone(),
l2m_out: l2m_out.vec().unwrap().clone(),
};

test_utils::compare_with_rkyv("blend", &format!("blend{:+.2}", r), &data).unwrap();
tester(
ratio,
&TestData {
ratio,
sample_out1: sample_out1.vec().unwrap().clone(),
sample_ctx1: sample_job1.context().unwrap().clone_without_animation_id(),
sample_out2: sample_out2.vec().unwrap().clone(),
sample_ctx2: sample_job2.context().unwrap().clone_without_animation_id(),
sample_out3: sample_out3.vec().unwrap().clone(),
sample_ctx3: sample_job3.context().unwrap().clone_without_animation_id(),
blending_out: blending_out.vec().unwrap().clone(),
l2m_out: l2m_out.vec().unwrap().clone(),
},
);
}
}
51 changes: 34 additions & 17 deletions tests/look_at.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
#![cfg(feature = "rkyv")]

use glam::{Mat4, Quat, Vec3A};
use ozz_animation_rs::*;
use rkyv::{Archive, Deserialize, Serialize};
use std::rc::Rc;

#[derive(Debug, PartialEq, Archive, Serialize, Deserialize)]
#[derive(Debug, PartialEq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
struct TestData {
locals1: Vec<SoaTransform>,
locals2: Vec<SoaTransform>,
Expand All @@ -22,7 +19,25 @@ const TARGET_OFFSET: Vec3A = Vec3A::new(0.2, 1.5, -0.3);
const EYES_OFFSET: Vec3A = Vec3A::new(0.07, 0.1, 0.0);

#[test]
fn test_deterministic_look_at() {
fn test_look_at() {
run_look_at(1..=1, |_, data| {
test_utils::compare_with_cpp("look_at", "look_at", &data.models2, 1.5e-4).unwrap();
});
}

#[cfg(feature = "rkyv")]
#[test]
fn test_look_at_deterministic() {
run_look_at(0..=10, |idx, data| {
test_utils::compare_with_rkyv("look_at", &format!("look_at_{:02}", idx), data).unwrap();
});
}

fn run_look_at<I, T>(range: I, tester: T)
where
I: Iterator<Item = i32>,
T: Fn(i32, &TestData),
{
let skeleton = Rc::new(Skeleton::from_file("./resource/look_at/skeleton.ozz").unwrap());
let animation = Rc::new(Animation::from_file("./resource/look_at/animation.ozz").unwrap());

Expand Down Expand Up @@ -58,8 +73,8 @@ fn test_deterministic_look_at() {
l2m_job2.set_input(locals2.clone());
l2m_job2.set_output(models2.clone());

for i in 0..=10 {
let time = i as f32;
for idx in range {
let time = idx as f32;
let delta = (time / 5.0).fract();

let animated_target = Vec3A::new(f32_sin(time * 0.5), f32_cos(time * 0.25), f32_cos(time) * 0.5 + 0.5);
Expand All @@ -70,6 +85,7 @@ fn test_deterministic_look_at() {

l2m_job1.run().unwrap();
locals2.borrow_mut().clone_from_slice(locals1.borrow().as_slice());
models2.borrow_mut().clone_from_slice(models1.borrow().as_slice());

ik_job.set_pole_vector(Vec3A::Y);
ik_job.set_target(target);
Expand Down Expand Up @@ -121,16 +137,17 @@ fn test_deterministic_look_at() {
l2m_job2.set_from(previous_joint);
l2m_job2.run().unwrap();

let data = TestData {
locals1: locals1.vec().unwrap().clone(),
locals2: locals2.vec().unwrap().clone(),
models1: models1.vec().unwrap().clone(),
models2: models2.vec().unwrap().clone(),
joint_corrections,
reacheds,
};

test_utils::compare_with_rkyv("look_at", &format!("look_at_ik_{:02}", i), &data).unwrap();
tester(
idx,
&TestData {
locals1: locals1.vec().unwrap().clone(),
locals2: locals2.vec().unwrap().clone(),
models1: models1.vec().unwrap().clone(),
models2: models2.vec().unwrap().clone(),
joint_corrections,
reacheds,
},
);
}
}

Expand Down
Loading

0 comments on commit b6431d1

Please sign in to comment.