From df9ccf76ab98d56252a78d3df7b6edd583e3d360 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 10 Mar 2016 13:48:27 -0800 Subject: [PATCH] fix animation-tests --- .../animation/src/AnimInverseKinematics.cpp | 7 + .../src/AnimInverseKinematicsTests.cpp | 123 +++++++++++------- tests/animation/src/AnimTests.cpp | 62 ++++----- 3 files changed, 114 insertions(+), 78 deletions(-) diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 6a29ad61ac..4a6c3d819c 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -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::iterator constraintItr = _constraints.begin(); while (constraintItr != _constraints.end()) { delete constraintItr->second; diff --git a/tests/animation/src/AnimInverseKinematicsTests.cpp b/tests/animation/src/AnimInverseKinematicsTests.cpp index bb15a1d257..2b10892f82 100644 --- a/tests/animation/src/AnimInverseKinematicsTests.cpp +++ b/tests/animation/src/AnimInverseKinematicsTests.cpp @@ -29,7 +29,7 @@ const glm::quat identity = glm::quat(); const glm::quat quaterTurnAroundZ = glm::angleAxis(0.5f * PI, zAxis); -void makeTestFBXJoints(std::vector& fbxJoints) { +void makeTestFBXJoints(FBXGeometry& geometry) { FBXJoint joint; joint.isFree = false; joint.freeLineage.clear(); @@ -61,29 +61,29 @@ void makeTestFBXJoints(std::vector& 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& fbxJoints) { } void AnimInverseKinematicsTests::testSingleChain() { - std::vector 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(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 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 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& 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 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 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& 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); } } diff --git a/tests/animation/src/AnimTests.cpp b/tests/animation/src/AnimTests.cpp index 6812bb63b6..130b692fb0 100644 --- a/tests/animation/src/AnimTests.cpp +++ b/tests/animation/src/AnimTests.cpp @@ -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));