Files
EVEngine/test/animation_two_bone_precision.cpp

70 lines
2.9 KiB
C++

#include <array>
#include <cmath>
#include "animation/AnimPose.h"
#include "animation/AnimSkeleton.h"
#include "zeroerr/assert.h"
#include "zeroerr/unittest.h"
using namespace eve::animation;
TEST_CASE("animation.pose.twoBoneIkRespectsRotatedScaledParent") {
AnimSkeleton skeleton;
skeleton.addBone("parent");
skeleton.addBone("hip", 0);
skeleton.addBone("knee", 1);
skeleton.addBone("ankle", 2);
skeleton.setBindPosition(0, .5f, .25f, -.3f);
skeleton.setBindRotation(0, 0.f, .70710678f, 0.f, .70710678f);
skeleton.setBindScale(0, 1.5f, 1.5f, 1.5f);
skeleton.setBindPosition(1, 0.f, .1f, 0.f);
skeleton.setBindPosition(2, 0.f, 1.f, 0.f);
skeleton.setBindPosition(3, 0.f, 1.f, 0.f);
AnimPose pose;
skeleton.applyBindPose(&pose);
REQUIRE(pose.solveTwoBoneIK(&skeleton, 1, 2, 3, .8f, 2.1f, .1f, 1.f));
CHECK(std::abs(pose.world(3).px - .8f) < .0003f);
CHECK(std::abs(pose.world(3).py - 2.1f) < .0003f);
CHECK(std::abs(pose.world(3).pz - .1f) < .0003f);
}
TEST_CASE("animation.pose.twoBoneIkReachesTargetsWithoutIteration") {
AnimSkeleton skeleton;
skeleton.addBone("hip");
skeleton.addBone("knee", 0);
skeleton.addBone("ankle", 1);
skeleton.setBindPosition(1, 0, 1, 0);
skeleton.setBindPosition(2, 0, 1, 0);
AnimPose pose;
for (auto target : {std::array{.2f, 1.4f, .1f}, std::array{0.f, 1.99f, 0.f}, std::array{0.f, .01f, 0.f},
std::array{-.3f, -1.5f, .2f}}) {
skeleton.applyBindPose(&pose);
REQUIRE(pose.solveTwoBoneIK(&skeleton, 0, 1, 2, target[0], target[1], target[2], 1));
float error = 0;
const auto& p = pose.world(2);
error = std::sqrt(std::pow(p.px - target[0], 2.f) + std::pow(p.py - target[1], 2.f) +
std::pow(p.pz - target[2], 2.f));
CHECK(error < .0003f);
const auto before = pose.world(1);
REQUIRE(pose.solveTwoBoneIK(&skeleton, 0, 1, 2, target[0], target[1], target[2], 1));
const auto after = pose.world(1);
CHECK(std::abs(before.px - after.px) < .0003f);
CHECK(std::abs(before.py - after.py) < .0003f);
CHECK(std::abs(before.pz - after.pz) < .0003f);
}
}
TEST_CASE("animation.pose.twoBoneIkClampsReachAndKeepsZeroWeightPose") {
AnimSkeleton skeleton;
skeleton.addBone("hip");
skeleton.addBone("knee", 0);
skeleton.addBone("ankle", 1);
skeleton.setBindPosition(1, 0, 1, 0);
skeleton.setBindPosition(2, 0, 1, 0);
AnimPose pose;
skeleton.applyBindPose(&pose);
REQUIRE(pose.solveTwoBoneIK(&skeleton, 0, 1, 2, 1, 0, 1, 0));
CHECK(std::abs(pose.world(2).py - 2) < 1e-6f);
REQUIRE(pose.solveTwoBoneIK(&skeleton, 0, 1, 2, 0, 3, 0, 1));
CHECK(std::abs(pose.world(2).py - 2) < 1e-6f);
skeleton.setBindPosition(1, 0, 0, 0);
skeleton.applyBindPose(&pose);
CHECK(!pose.solveTwoBoneIK(&skeleton, 0, 1, 2, 1, 0, 1, 1));
CHECK(std::abs(pose.world(2).py - 1) < 1e-6f);
}