fix animation-tests

This commit is contained in:
Andrew Meadows 2016-03-10 13:48:27 -08:00
parent ae596d79f1
commit df9ccf76ab
3 changed files with 114 additions and 78 deletions

View file

@ -22,7 +22,13 @@ AnimInverseKinematics::AnimInverseKinematics(const QString& id) : AnimNode(AnimN
}
AnimInverseKinematics::~AnimInverseKinematics() {
std::cout << "adebug dtor" << std::endl; // adebug
clearConstraints();
std::cout << "adebug dtor 002" << std::endl; // adebug
_accumulators.clear();
std::cout << "adebug dtor 003 targetVarVec.size() = " << _targetVarVec.size() << std::endl; // adebug
_targetVarVec.clear();
std::cout << "adebug dtor 004 targetVarVec.size() = " << _targetVarVec.size() << std::endl; // adebug
}
void AnimInverseKinematics::loadDefaultPoses(const AnimPoseVec& poses) {
@ -485,6 +491,7 @@ RotationConstraint* AnimInverseKinematics::getConstraint(int index) {
}
void AnimInverseKinematics::clearConstraints() {
std::cout << "adebug clearConstraints size = " << _constraints.size() << std::endl; // adebug
std::map<int, RotationConstraint*>::iterator constraintItr = _constraints.begin();
while (constraintItr != _constraints.end()) {
delete constraintItr->second;

View file

@ -29,7 +29,7 @@ const glm::quat identity = glm::quat();
const glm::quat quaterTurnAroundZ = glm::angleAxis(0.5f * PI, zAxis);
void makeTestFBXJoints(std::vector<FBXJoint>& fbxJoints) {
void makeTestFBXJoints(FBXGeometry& geometry) {
FBXJoint joint;
joint.isFree = false;
joint.freeLineage.clear();
@ -61,29 +61,29 @@ void makeTestFBXJoints(std::vector<FBXJoint>& fbxJoints) {
joint.name = "A";
joint.parentIndex = -1;
joint.translation = origin;
fbxJoints.push_back(joint);
geometry.joints.push_back(joint);
joint.name = "B";
joint.parentIndex = 0;
joint.translation = xAxis;
fbxJoints.push_back(joint);
geometry.joints.push_back(joint);
joint.name = "C";
joint.parentIndex = 1;
joint.translation = xAxis;
fbxJoints.push_back(joint);
geometry.joints.push_back(joint);
joint.name = "D";
joint.parentIndex = 2;
joint.translation = xAxis;
fbxJoints.push_back(joint);
geometry.joints.push_back(joint);
// compute each joint's transform
for (int i = 1; i < (int)fbxJoints.size(); ++i) {
FBXJoint& j = fbxJoints[i];
for (int i = 1; i < (int)geometry.joints.size(); ++i) {
FBXJoint& j = geometry.joints[i];
int parentIndex = j.parentIndex;
// World = ParentWorld * T * (Roff * Rp) * Rpre * R * Rpost * (Rp-1 * Soff * Sp * S * Sp-1)
j.transform = fbxJoints[parentIndex].transform *
j.transform = geometry.joints[parentIndex].transform *
glm::translate(j.translation) *
j.preTransform *
glm::mat4_cast(j.preRotation * j.rotation * j.postRotation) *
@ -94,14 +94,14 @@ void makeTestFBXJoints(std::vector<FBXJoint>& fbxJoints) {
}
void AnimInverseKinematicsTests::testSingleChain() {
std::vector<FBXJoint> fbxJoints;
makeTestFBXJoints(fbxJoints);
FBXGeometry geometry;
makeTestFBXJoints(geometry);
// create a skeleton and doll
AnimPose offset;
AnimSkeleton* skeleton = new AnimSkeleton(fbxJoints, offset);
AnimSkeleton::Pointer skeletonPtr(skeleton);
AnimSkeleton::Pointer skeletonPtr = std::make_shared<AnimSkeleton>(geometry);
AnimInverseKinematics ikDoll("doll");
ikDoll.setSkeleton(skeletonPtr);
{ // easy test IK of joint C
@ -113,11 +113,11 @@ void AnimInverseKinematicsTests::testSingleChain() {
pose.rot = identity;
pose.trans = origin;
std::vector<AnimPose> poses;
AnimPoseVec poses;
poses.push_back(pose);
pose.trans = xAxis;
for (int i = 1; i < (int)fbxJoints.size(); ++i) {
for (int i = 1; i < (int)geometry.joints.size(); ++i) {
poses.push_back(pose);
}
ikDoll.loadPoses(poses);
@ -134,7 +134,8 @@ void AnimInverseKinematicsTests::testSingleChain() {
AnimVariantMap varMap;
varMap.set("positionD", targetPosition);
varMap.set("rotationD", targetRotation);
ikDoll.setTargetVars("D", "positionD", "rotationD");
varMap.set("targetType", (int)IKTarget::Type::RotationAndPosition);
ikDoll.setTargetVars(QString("D"), QString("positionD"), QString("rotationD"), QString("targetType"));
AnimNode::Triggers triggers;
// the IK solution should be:
@ -144,38 +145,49 @@ void AnimInverseKinematicsTests::testSingleChain() {
// |
// A------>B------>C
//
// iterate several times
float dt = 1.0f;
ikDoll.evaluate(varMap, dt, triggers);
ikDoll.overlay(varMap, dt, triggers, poses);
ikDoll.overlay(varMap, dt, triggers, poses);
ikDoll.overlay(varMap, dt, triggers, poses);
ikDoll.overlay(varMap, dt, triggers, poses);
ikDoll.overlay(varMap, dt, triggers, poses);
ikDoll.overlay(varMap, dt, triggers, poses);
const AnimPoseVec& relativePoses = ikDoll.overlay(varMap, dt, triggers, poses);
// verify absolute results
// NOTE: since we expect this solution to converge very quickly (one loop)
// we can impose very tight error thresholds.
std::vector<AnimPose> absolutePoses;
AnimPoseVec absolutePoses;
for (auto pose : poses) {
absolutePoses.push_back(pose);
}
ikDoll.computeAbsolutePoses(absolutePoses);
float acceptableAngle = 0.0001f;
QCOMPARE_QUATS(absolutePoses[0].rot, identity, acceptableAngle);
QCOMPARE_QUATS(absolutePoses[1].rot, identity, acceptableAngle);
QCOMPARE_QUATS(absolutePoses[2].rot, quaterTurnAroundZ, acceptableAngle);
QCOMPARE_QUATS(absolutePoses[3].rot, quaterTurnAroundZ, acceptableAngle);
const float acceptableAngleError = 0.001f;
QCOMPARE_QUATS(absolutePoses[0].rot, identity, acceptableAngleError);
QCOMPARE_QUATS(absolutePoses[1].rot, identity, acceptableAngleError);
QCOMPARE_QUATS(absolutePoses[2].rot, quaterTurnAroundZ, acceptableAngleError);
QCOMPARE_QUATS(absolutePoses[3].rot, quaterTurnAroundZ, acceptableAngleError);
QCOMPARE_WITH_ABS_ERROR(absolutePoses[0].trans, origin, EPSILON);
QCOMPARE_WITH_ABS_ERROR(absolutePoses[1].trans, xAxis, EPSILON);
QCOMPARE_WITH_ABS_ERROR(absolutePoses[2].trans, 2.0f * xAxis, EPSILON);
QCOMPARE_WITH_ABS_ERROR(absolutePoses[3].trans, targetPosition, EPSILON);
const float acceptableTranslationError = 0.025f;
QCOMPARE_WITH_ABS_ERROR(absolutePoses[0].trans, origin, acceptableTranslationError);
QCOMPARE_WITH_ABS_ERROR(absolutePoses[1].trans, xAxis, acceptableTranslationError);
QCOMPARE_WITH_ABS_ERROR(absolutePoses[2].trans, 2.0f * xAxis, acceptableTranslationError);
QCOMPARE_WITH_ABS_ERROR(absolutePoses[3].trans, targetPosition, acceptableTranslationError);
// verify relative results
const std::vector<AnimPose>& relativePoses = ikDoll.getRelativePoses();
QCOMPARE_QUATS(relativePoses[0].rot, identity, acceptableAngle);
QCOMPARE_QUATS(relativePoses[1].rot, identity, acceptableAngle);
QCOMPARE_QUATS(relativePoses[2].rot, quaterTurnAroundZ, acceptableAngle);
QCOMPARE_QUATS(relativePoses[3].rot, identity, acceptableAngle);
QCOMPARE_QUATS(relativePoses[0].rot, identity, acceptableAngleError);
QCOMPARE_QUATS(relativePoses[1].rot, identity, acceptableAngleError);
QCOMPARE_QUATS(relativePoses[2].rot, quaterTurnAroundZ, acceptableAngleError);
QCOMPARE_QUATS(relativePoses[3].rot, identity, acceptableAngleError);
QCOMPARE_WITH_ABS_ERROR(relativePoses[0].trans, origin, EPSILON);
QCOMPARE_WITH_ABS_ERROR(relativePoses[1].trans, xAxis, EPSILON);
QCOMPARE_WITH_ABS_ERROR(relativePoses[2].trans, xAxis, EPSILON);
QCOMPARE_WITH_ABS_ERROR(relativePoses[3].trans, xAxis, EPSILON);
QCOMPARE_WITH_ABS_ERROR(relativePoses[0].trans, origin, acceptableTranslationError);
QCOMPARE_WITH_ABS_ERROR(relativePoses[1].trans, xAxis, acceptableTranslationError);
QCOMPARE_WITH_ABS_ERROR(relativePoses[2].trans, xAxis, acceptableTranslationError);
QCOMPARE_WITH_ABS_ERROR(relativePoses[3].trans, xAxis, acceptableTranslationError);
}
{ // hard test IK of joint C
// load intial poses that look like this:
//
@ -188,8 +200,8 @@ void AnimInverseKinematicsTests::testSingleChain() {
pose.scale = glm::vec3(1.0f);
pose.rot = identity;
pose.trans = origin;
std::vector<AnimPose> poses;
AnimPoseVec poses;
poses.push_back(pose);
pose.trans = xAxis;
@ -211,15 +223,26 @@ void AnimInverseKinematicsTests::testSingleChain() {
AnimVariantMap varMap;
varMap.set("positionD", targetPosition);
varMap.set("rotationD", targetRotation);
ikDoll.setTargetVars("D", "positionD", "rotationD");
varMap.set("targetType", (int)IKTarget::Type::RotationAndPosition);
ikDoll.setTargetVars(QString("D"), QString("positionD"), QString("rotationD"), QString("targetType"));
AnimNode::Triggers triggers;
// the IK solution should be:
//
// A------>B------>C------>D
//
// iterate several times
float dt = 1.0f;
ikDoll.evaluate(varMap, dt, triggers);
ikDoll.overlay(varMap, dt, triggers, poses);
ikDoll.overlay(varMap, dt, triggers, poses);
ikDoll.overlay(varMap, dt, triggers, poses);
ikDoll.overlay(varMap, dt, triggers, poses);
ikDoll.overlay(varMap, dt, triggers, poses);
ikDoll.overlay(varMap, dt, triggers, poses);
ikDoll.overlay(varMap, dt, triggers, poses);
ikDoll.overlay(varMap, dt, triggers, poses);
const AnimPoseVec& relativePoses = ikDoll.overlay(varMap, dt, triggers, poses);
// verify absolute results
// NOTE: the IK algorithm doesn't converge very fast for full-reach targets,
@ -228,31 +251,33 @@ void AnimInverseKinematicsTests::testSingleChain() {
// NOTE: constraints may help speed up convergence since some joints may get clamped
// to maximum extension. TODO: experiment with tightening the error thresholds when
// constraints are working.
std::vector<AnimPose> absolutePoses;
AnimPoseVec absolutePoses;
for (auto pose : poses) {
absolutePoses.push_back(pose);
}
ikDoll.computeAbsolutePoses(absolutePoses);
float acceptableAngle = 0.1f; // radians
float acceptableAngle = 0.01f; // radians
QCOMPARE_QUATS(absolutePoses[0].rot, identity, acceptableAngle);
QCOMPARE_QUATS(absolutePoses[1].rot, identity, acceptableAngle);
QCOMPARE_QUATS(absolutePoses[2].rot, identity, acceptableAngle);
QCOMPARE_QUATS(absolutePoses[3].rot, identity, acceptableAngle);
float acceptableDistance = 0.4f;
QCOMPARE_WITH_ABS_ERROR(absolutePoses[0].trans, origin, EPSILON);
float acceptableDistance = 0.03f;
QCOMPARE_WITH_ABS_ERROR(absolutePoses[0].trans, origin, acceptableDistance);
QCOMPARE_WITH_ABS_ERROR(absolutePoses[1].trans, xAxis, acceptableDistance);
QCOMPARE_WITH_ABS_ERROR(absolutePoses[2].trans, 2.0f * xAxis, acceptableDistance);
QCOMPARE_WITH_ABS_ERROR(absolutePoses[3].trans, 3.0f * xAxis, acceptableDistance);
// verify relative results
const std::vector<AnimPose>& relativePoses = ikDoll.getRelativePoses();
QCOMPARE_QUATS(relativePoses[0].rot, identity, acceptableAngle);
QCOMPARE_QUATS(relativePoses[1].rot, identity, acceptableAngle);
QCOMPARE_QUATS(relativePoses[2].rot, identity, acceptableAngle);
QCOMPARE_QUATS(relativePoses[3].rot, identity, acceptableAngle);
QCOMPARE_WITH_ABS_ERROR(relativePoses[0].trans, origin, EPSILON);
QCOMPARE_WITH_ABS_ERROR(relativePoses[1].trans, xAxis, EPSILON);
QCOMPARE_WITH_ABS_ERROR(relativePoses[2].trans, xAxis, EPSILON);
QCOMPARE_WITH_ABS_ERROR(relativePoses[3].trans, xAxis, EPSILON);
QCOMPARE_WITH_ABS_ERROR(relativePoses[0].trans, origin, acceptableDistance);
QCOMPARE_WITH_ABS_ERROR(relativePoses[1].trans, xAxis, acceptableDistance);
QCOMPARE_WITH_ABS_ERROR(relativePoses[2].trans, xAxis, acceptableDistance);
QCOMPARE_WITH_ABS_ERROR(relativePoses[3].trans, xAxis, acceptableDistance);
}
}

View file

@ -38,8 +38,9 @@ void AnimTests::testClipInternalState() {
float endFrame = 20.0f;
float timeScale = 1.1f;
bool loopFlag = true;
bool mirrorFlag = false;
AnimClip clip(id, url, startFrame, endFrame, timeScale, loopFlag);
AnimClip clip(id, url, startFrame, endFrame, timeScale, loopFlag, mirrorFlag);
QVERIFY(clip.getID() == id);
QVERIFY(clip.getType() == AnimNode::Type::Clip);
@ -49,6 +50,7 @@ void AnimTests::testClipInternalState() {
QVERIFY(clip._endFrame == endFrame);
QVERIFY(clip._timeScale == timeScale);
QVERIFY(clip._loopFlag == loopFlag);
QVERIFY(clip._mirrorFlag == mirrorFlag);
}
static float framesToSec(float secs) {
@ -62,12 +64,13 @@ void AnimTests::testClipEvaulate() {
float startFrame = 2.0f;
float endFrame = 22.0f;
float timeScale = 1.0f;
float loopFlag = true;
bool loopFlag = true;
bool mirrorFlag = false;
auto vars = AnimVariantMap();
vars.set("FalseVar", false);
AnimClip clip(id, url, startFrame, endFrame, timeScale, loopFlag);
AnimClip clip(id, url, startFrame, endFrame, timeScale, loopFlag, mirrorFlag);
AnimNode::Triggers triggers;
clip.evaluate(vars, framesToSec(10.0f), triggers);
@ -97,7 +100,8 @@ void AnimTests::testClipEvaulateWithVars() {
float startFrame = 2.0f;
float endFrame = 22.0f;
float timeScale = 1.0f;
float loopFlag = true;
bool loopFlag = true;
bool mirrorFlag = false;
float startFrame2 = 22.0f;
float endFrame2 = 100.0f;
@ -110,7 +114,7 @@ void AnimTests::testClipEvaulateWithVars() {
vars.set("timeScale2", timeScale2);
vars.set("loopFlag2", loopFlag2);
AnimClip clip(id, url, startFrame, endFrame, timeScale, loopFlag);
AnimClip clip(id, url, startFrame, endFrame, timeScale, loopFlag, mirrorFlag);
clip.setStartFrameVar("startFrame2");
clip.setEndFrameVar("endFrame2");
clip.setTimeScaleVar("timeScale2");
@ -583,23 +587,23 @@ void AnimTests::testExpressionEvaluator() {
TEST_BOOL_EXPR(false && false);
TEST_BOOL_EXPR(false && true);
TEST_BOOL_EXPR(true || false && true);
TEST_BOOL_EXPR(true || false && false);
TEST_BOOL_EXPR(true || true && true);
TEST_BOOL_EXPR(true || true && false);
TEST_BOOL_EXPR(false || false && true);
TEST_BOOL_EXPR(false || false && false);
TEST_BOOL_EXPR(false || true && true);
TEST_BOOL_EXPR(false || true && false);
TEST_BOOL_EXPR(true || (false && true));
TEST_BOOL_EXPR(true || (false && false));
TEST_BOOL_EXPR(true || (true && true));
TEST_BOOL_EXPR(true || (true && false));
TEST_BOOL_EXPR(false || (false && true));
TEST_BOOL_EXPR(false || (false && false));
TEST_BOOL_EXPR(false || (true && true));
TEST_BOOL_EXPR(false || (true && false));
TEST_BOOL_EXPR(true && false || true);
TEST_BOOL_EXPR(true && false || false);
TEST_BOOL_EXPR(true && true || true);
TEST_BOOL_EXPR(true && true || false);
TEST_BOOL_EXPR(false && false || true);
TEST_BOOL_EXPR(false && false || false);
TEST_BOOL_EXPR(false && true || true);
TEST_BOOL_EXPR(false && true || false);
TEST_BOOL_EXPR((true && false) || true);
TEST_BOOL_EXPR((true && false) || false);
TEST_BOOL_EXPR((true && true) || true);
TEST_BOOL_EXPR((true && true) || false);
TEST_BOOL_EXPR((false && false) || true);
TEST_BOOL_EXPR((false && false) || false);
TEST_BOOL_EXPR((false && true) || true);
TEST_BOOL_EXPR((false && true) || false);
TEST_BOOL_EXPR(t || false);
TEST_BOOL_EXPR(t || true);
@ -610,14 +614,14 @@ void AnimTests::testExpressionEvaluator() {
TEST_BOOL_EXPR(!false);
TEST_BOOL_EXPR(!true || true);
TEST_BOOL_EXPR(!true && !false || !true);
TEST_BOOL_EXPR(!true && !false || true);
TEST_BOOL_EXPR(!true && false || !true);
TEST_BOOL_EXPR(!true && false || true);
TEST_BOOL_EXPR(true && !false || !true);
TEST_BOOL_EXPR(true && !false || true);
TEST_BOOL_EXPR(true && false || !true);
TEST_BOOL_EXPR(true && false || true);
TEST_BOOL_EXPR((!true && !false) || !true);
TEST_BOOL_EXPR((!true && !false) || true);
TEST_BOOL_EXPR((!true && false) || !true);
TEST_BOOL_EXPR((!true && false) || true);
TEST_BOOL_EXPR((true && !false) || !true);
TEST_BOOL_EXPR((true && !false) || true);
TEST_BOOL_EXPR((true && false) || !true);
TEST_BOOL_EXPR((true && false) || true);
TEST_BOOL_EXPR(!(true && f) || !t);
TEST_BOOL_EXPR(!!!(t) && (!!f || true));