mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-07 06:02:28 +02:00
fix animation-tests
This commit is contained in:
parent
ae596d79f1
commit
df9ccf76ab
3 changed files with 114 additions and 78 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in a new issue