Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add cpp tests #38

Merged
merged 1 commit into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading