From 721da2943257a54bad4e40b2a360189defee62bc Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 18 Nov 2015 18:47:33 -0800 Subject: [PATCH] WIP checkpoint * No longer normalizing scale in AnimSkeleton and AnimClip This means graph is animating in 'geometry' coordinates before unit scale is even applied. This is necessary to properly work with both Avatar based models and ModelEntity based models Many things are broken. * debug rendering (translations are x100) * IK hand targets * follow cam * I did not even dare to try HMD mode --- interface/src/avatar/MyAvatar.cpp | 21 ++++++++++++++------ interface/src/avatar/SkeletonModel.cpp | 9 +++++---- libraries/animation/src/AnimClip.cpp | 18 ++++++++--------- libraries/animation/src/AnimSkeleton.cpp | 17 +++++++++++++--- libraries/animation/src/AnimSkeleton.h | 7 ++++--- libraries/animation/src/JointState.cpp | 2 +- libraries/animation/src/Rig.cpp | 25 ++++++++++++++---------- libraries/animation/src/Rig.h | 8 +++++--- libraries/render-utils/src/Model.cpp | 8 ++++---- 9 files changed, 72 insertions(+), 43 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5bacb567e1..cc8f232436 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -359,11 +359,11 @@ void MyAvatar::updateHMDFollowVelocity() { // This is so the correct camera can be used for rendering. void MyAvatar::updateSensorToWorldMatrix() { -#ifdef DEBUG_RENDERING +//#ifdef DEBUG_RENDERING // draw marker about avatar's position const glm::vec4 red(1.0f, 0.0f, 0.0f, 1.0f); DebugDraw::getInstance().addMyAvatarMarker("pos", glm::quat(), glm::vec3(), red); -#endif +//#endif // update the sensor mat so that the body position will end up in the desired // position when driven from the head. @@ -1286,7 +1286,10 @@ void MyAvatar::preRender(RenderArgs* renderArgs) { if (_enableDebugDrawAnimPose && _debugDrawSkeleton) { glm::vec4 cyan(0.1f, 0.6f, 0.6f, 1.0f); + auto rig = _skeletonModel.getRig(); + // AJT: TODO move this into rig! // build AnimPoseVec from JointStates. + // AJT: TODO THIS SHIT IS ALL BROKEN AnimPoseVec poses; poses.reserve(_debugDrawSkeleton->getNumJoints()); for (int i = 0; i < _debugDrawSkeleton->getNumJoints(); i++) { @@ -1297,6 +1300,11 @@ void MyAvatar::preRender(RenderArgs* renderArgs) { _rig->getJointTranslation(i, jointTrans); pose.rot = pose.rot * jointRot; pose.trans = jointTrans; + /* + if (_debugDrawSkeleton->getParentIndex(i) < 0) { + pose = _rig->getGeometryOffset() * pose; + } + */ poses.push_back(pose); } @@ -1765,6 +1773,7 @@ glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const { const glm::vec3 DEFAULT_NECK_POS(0.0f, 1.70f, 0.0f); const glm::vec3 DEFAULT_HIPS_POS(0.0f, 1.05f, 0.0f); + AnimPose geometryOffset = _rig->getGeometryOffset(); vec3 localEyes, localNeck; if (!_debugDrawSkeleton) { const glm::quat rotY180 = glm::angleAxis((float)PI, glm::vec3(0.0f, 1.0f, 0.0f)); @@ -1780,10 +1789,10 @@ glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const { int neckIndex = _debugDrawSkeleton->nameToJointIndex("Neck"); int hipsIndex = _debugDrawSkeleton->nameToJointIndex("Hips"); - glm::vec3 absRightEyePos = rightEyeIndex != -1 ? _debugDrawSkeleton->getAbsoluteBindPose(rightEyeIndex).trans : DEFAULT_RIGHT_EYE_POS; - glm::vec3 absLeftEyePos = leftEyeIndex != -1 ? _debugDrawSkeleton->getAbsoluteBindPose(leftEyeIndex).trans : DEFAULT_LEFT_EYE_POS; - glm::vec3 absNeckPos = neckIndex != -1 ? _debugDrawSkeleton->getAbsoluteBindPose(neckIndex).trans : DEFAULT_NECK_POS; - glm::vec3 absHipsPos = neckIndex != -1 ? _debugDrawSkeleton->getAbsoluteBindPose(hipsIndex).trans : DEFAULT_HIPS_POS; + glm::vec3 absRightEyePos = rightEyeIndex != -1 ? geometryOffset * _debugDrawSkeleton->getAbsoluteBindPose(rightEyeIndex).trans : DEFAULT_RIGHT_EYE_POS; + glm::vec3 absLeftEyePos = leftEyeIndex != -1 ? geometryOffset * _debugDrawSkeleton->getAbsoluteBindPose(leftEyeIndex).trans : DEFAULT_LEFT_EYE_POS; + glm::vec3 absNeckPos = neckIndex != -1 ? geometryOffset * _debugDrawSkeleton->getAbsoluteBindPose(neckIndex).trans : DEFAULT_NECK_POS; + glm::vec3 absHipsPos = neckIndex != -1 ? geometryOffset * _debugDrawSkeleton->getAbsoluteBindPose(hipsIndex).trans : DEFAULT_HIPS_POS; const glm::quat rotY180 = glm::angleAxis((float)PI, glm::vec3(0.0f, 1.0f, 0.0f)); localEyes = rotY180 * (((absRightEyePos + absLeftEyePos) / 2.0f) - absHipsPos); diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 8b34d9248e..b60ed85429 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -43,7 +43,8 @@ SkeletonModel::~SkeletonModel() { void SkeletonModel::initJointStates() { const FBXGeometry& geometry = _geometry->getFBXGeometry(); - glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; + glm::mat4 geometryOffset = geometry.offset; + glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset); int rootJointIndex = geometry.rootJointIndex; int leftHandJointIndex = geometry.leftHandJointIndex; @@ -241,9 +242,9 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { Model::simulate(deltaTime, fullUpdate); // let rig compute the model offset - glm::vec3 modelOffset; - if (_rig->getModelOffset(modelOffset)) { - setOffset(modelOffset); + glm::vec3 registrationPoint; + if (_rig->getModelRegistrationPoint(registrationPoint)) { + setOffset(registrationPoint); } if (!isActive() || !_owningAvatar->isMyAvatar()) { diff --git a/libraries/animation/src/AnimClip.cpp b/libraries/animation/src/AnimClip.cpp index b2b6f728fd..582a55cd62 100644 --- a/libraries/animation/src/AnimClip.cpp +++ b/libraries/animation/src/AnimClip.cpp @@ -107,8 +107,6 @@ void AnimClip::copyFromNetworkAnim() { const int skeletonJointCount = _skeleton->getNumJoints(); _anim.resize(frameCount); - const glm::vec3 offsetScale = extractScale(geom.offset); - for (int frame = 0; frame < frameCount; frame++) { // init all joints in animation to bind pose @@ -125,23 +123,25 @@ void AnimClip::copyFromNetworkAnim() { // skip joints that are in the animation but not in the skeleton. if (skeletonJoint >= 0 && skeletonJoint < skeletonJointCount) { - const glm::vec3& fbxZeroTrans = geom.animationFrames[0].translations[animJoint] * offsetScale; - const AnimPose& relBindPose = _skeleton->getRelativeBindPose(skeletonJoint); + const glm::vec3& fbxZeroTrans = geom.animationFrames[0].translations[animJoint]; + // AJT: TODO: use the actual preRotation not the bind pose here. + const AnimPose& jointOrientPose = _skeleton->getRelativeBindPose(skeletonJoint); + const AnimPose& relDefaultPose = _skeleton->getRelativeDefaultPose(skeletonJoint); // used to adjust translation offsets, so large translation animatons on the reference skeleton // will be adjusted when played on a skeleton with short limbs. - float limbLengthScale = fabsf(glm::length(fbxZeroTrans)) <= 0.0001f ? 1.0f : (glm::length(relBindPose.trans) / glm::length(fbxZeroTrans)); + float limbLengthScale = fabsf(glm::length(fbxZeroTrans)) <= 0.0001f ? 1.0f : (glm::length(relDefaultPose.trans) / glm::length(fbxZeroTrans)); AnimPose& pose = _anim[frame][skeletonJoint]; const FBXAnimationFrame& fbxAnimFrame = geom.animationFrames[frame]; - // rotation in fbxAnimationFrame is a delta from a reference skeleton bind pose. - pose.rot = relBindPose.rot * fbxAnimFrame.rotations[animJoint]; + // rotation in fbxAnimationFrame is a delta from its jointOrientPose (aka preRotation) + pose.rot = jointOrientPose.rot * fbxAnimFrame.rotations[animJoint]; // translation in fbxAnimationFrame is not a delta. // convert it into a delta by subtracting from the first frame. - const glm::vec3& fbxTrans = fbxAnimFrame.translations[animJoint] * offsetScale; - pose.trans = relBindPose.trans + limbLengthScale * (fbxTrans - fbxZeroTrans); + const glm::vec3& fbxTrans = fbxAnimFrame.translations[animJoint]; + pose.trans = relDefaultPose.trans + limbLengthScale * (fbxTrans - fbxZeroTrans); } } } diff --git a/libraries/animation/src/AnimSkeleton.cpp b/libraries/animation/src/AnimSkeleton.cpp index f6c5ce09db..ae73d380e6 100644 --- a/libraries/animation/src/AnimSkeleton.cpp +++ b/libraries/animation/src/AnimSkeleton.cpp @@ -24,12 +24,17 @@ AnimSkeleton::AnimSkeleton(const FBXGeometry& fbxGeometry) { joints.push_back(joint); } + // AJT: REMOVE + /* AnimPose geometryOffset(fbxGeometry.offset); buildSkeletonFromJoints(joints, geometryOffset); + */ + + buildSkeletonFromJoints(joints); } -AnimSkeleton::AnimSkeleton(const std::vector& joints, const AnimPose& geometryOffset) { - buildSkeletonFromJoints(joints, geometryOffset); +AnimSkeleton::AnimSkeleton(const std::vector& joints) { + buildSkeletonFromJoints(joints); } int AnimSkeleton::nameToJointIndex(const QString& jointName) const { @@ -94,7 +99,7 @@ AnimPose AnimSkeleton::getAbsolutePose(int jointIndex, const AnimPoseVec& poses) } } -void AnimSkeleton::buildSkeletonFromJoints(const std::vector& joints, const AnimPose& geometryOffset) { +void AnimSkeleton::buildSkeletonFromJoints(const std::vector& joints) { _joints = joints; // build a cache of bind poses @@ -143,12 +148,17 @@ void AnimSkeleton::buildSkeletonFromJoints(const std::vector& joints, } } + // AJT: REMOVE + /* // now we want to normalize scale from geometryOffset to all poses. // This will ensure our bone translations will be in meters, even if the model was authored with some other unit of mesure. normalizeScale(geometryOffset, _relativeBindPoses, _absoluteBindPoses); normalizeScale(geometryOffset, _relativeDefaultPoses, _absoluteDefaultPoses); + */ } +/* +// AJT: REMOVE void AnimSkeleton::normalizeScale(const AnimPose& geometryOffset, AnimPoseVec& relPoses, AnimPoseVec& absPoses) const { for (auto& absPose : absPoses) { absPose.trans = (geometryOffset * absPose).trans; @@ -164,6 +174,7 @@ void AnimSkeleton::normalizeScale(const AnimPose& geometryOffset, AnimPoseVec& r } } } +*/ #define DUMP_FBX_JOINTS diff --git a/libraries/animation/src/AnimSkeleton.h b/libraries/animation/src/AnimSkeleton.h index 7c57096280..8711f24587 100644 --- a/libraries/animation/src/AnimSkeleton.h +++ b/libraries/animation/src/AnimSkeleton.h @@ -24,7 +24,7 @@ public: using ConstPointer = std::shared_ptr; AnimSkeleton(const FBXGeometry& fbxGeometry); - AnimSkeleton(const std::vector& joints, const AnimPose& geometryOffset); + AnimSkeleton(const std::vector& joints); int nameToJointIndex(const QString& jointName) const; const QString& getJointName(int jointIndex) const; int getNumJoints() const; @@ -54,8 +54,9 @@ public: #endif protected: - void buildSkeletonFromJoints(const std::vector& joints, const AnimPose& geometryOffset); - void normalizeScale(const AnimPose& geometryOffset, AnimPoseVec& relPoses, AnimPoseVec& absPoses) const; + void buildSkeletonFromJoints(const std::vector& joints); + // AJT: REMOVE + //void normalizeScale(const AnimPose& geometryOffset, AnimPoseVec& relPoses, AnimPoseVec& absPoses) const; std::vector _joints; AnimPoseVec _absoluteBindPoses; diff --git a/libraries/animation/src/JointState.cpp b/libraries/animation/src/JointState.cpp index 5bc88ad57f..4c4e40119a 100644 --- a/libraries/animation/src/JointState.cpp +++ b/libraries/animation/src/JointState.cpp @@ -73,7 +73,7 @@ glm::quat JointState::getRotation() const { void JointState::initTransform(const glm::mat4& parentTransform) { - _unitsScale = extractScale(parentTransform); + //_unitsScale = extractScale(parentTransform); computeTransform(parentTransform); _positionInParentFrame = glm::inverse(extractRotation(parentTransform)) * (extractTranslation(_transform) - extractTranslation(parentTransform)); diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 426661455f..5dfb90f0eb 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -167,9 +167,10 @@ void Rig::initJointStates(const FBXGeometry& geometry, glm::mat4 modelOffset, in int leftHandJointIndex, int leftElbowJointIndex, int leftShoulderJointIndex, int rightHandJointIndex, int rightElbowJointIndex, int rightShoulderJointIndex) { + _geometryOffset = AnimPose(geometry.offset); _animSkeleton = std::make_shared(geometry); - _animSkeleton->dump(); + //_animSkeleton->dump(); computeEyesInRootFrame(_animSkeleton->getRelativeDefaultPoses()); @@ -198,12 +199,13 @@ void Rig::initJointStates(const FBXGeometry& geometry, glm::mat4 modelOffset, in // was old Rig::initJointStates // compute model transforms + glm::mat4 rootTransform = (glm::mat4)(_modelOffset * _geometryOffset); int numStates = _animSkeleton->getNumJoints(); for (int i = 0; i < numStates; ++i) { JointState& state = _jointStates[i]; int parentIndex = state.getParentIndex(); if (parentIndex == -1) { - state.initTransform(modelOffset); + state.initTransform(rootTransform); } else { const JointState& parentState = _jointStates.at(parentIndex); state.initTransform(parentState.getTransform()); @@ -248,7 +250,6 @@ void Rig::setModelOffset(const glm::mat4& modelOffset) { _legacyModelOffset = modelOffset; } _modelOffset = AnimPose(modelOffset); - _modelScale = _modelOffset.scale; } // AJT: REMOVE @@ -1220,9 +1221,9 @@ void Rig::initAnimGraph(const QUrl& url) { }); } -bool Rig::getModelOffset(glm::vec3& modelOffsetOut) const { +bool Rig::getModelRegistrationPoint(glm::vec3& modelRegistrationPointOut) const { if (_animSkeleton && _rootJointIndex >= 0) { - modelOffsetOut = -_animSkeleton->getAbsoluteBindPose(_rootJointIndex).trans; + modelRegistrationPointOut = _geometryOffset * -_animSkeleton->getAbsoluteBindPose(_rootJointIndex).trans; return true; } else { return false; @@ -1263,15 +1264,19 @@ void Rig::buildAbsolutePoses() { } for (int i = 0; i < (int)_absolutePoses.size(); i++) { + _absolutePoses[i] = _modelOffset * _geometryOffset * _absolutePoses[i]; + // AJT: REMOVE + /* _absolutePoses[i].trans = _modelOffset.trans + _absolutePoses[i].trans; _absolutePoses[i].rot = _modelOffset.rot * _absolutePoses[i].rot; _absolutePoses[i].scale = _absolutePoses[i].scale * _modelScale; + */ } // AJT: LEGACY { // Build the joint states - glm::mat4 rootTransform = _legacyModelOffset; + glm::mat4 rootTransform = (glm::mat4)(_modelOffset * _geometryOffset); for (int i = 0; i < (int)_animSkeleton->getNumJoints(); i++) { JointState& state = _jointStates[i]; @@ -1300,12 +1305,12 @@ glm::mat4 Rig::getJointTransform(int jointIndex) const { //if (_jointStates.size() == 73) { // check for differences between jointStates and _absolutePoses! - { + if (false) { // should display for model entities glm::mat4 newMat = _absolutePoses[jointIndex]; glm::mat4 oldMat = _jointStates[jointIndex].getTransform(); - const float EPSILON = 0.005f; + const float EPSILON = 0.01f; if (glm::length(newMat[0] - oldMat[0]) > EPSILON || glm::length(newMat[1] - oldMat[1]) > EPSILON || glm::length(newMat[2] - oldMat[2]) > EPSILON || @@ -1321,9 +1326,9 @@ glm::mat4 Rig::getJointTransform(int jointIndex) const { // AJT: LEGACY { - //return _jointStates[jointIndex].getTransform(); + return _jointStates[jointIndex].getTransform(); } - return _absolutePoses[jointIndex]; + //return _absolutePoses[jointIndex]; } diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 88a0b45529..182b7e632b 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -94,6 +94,7 @@ public: int indexOfJoint(const QString& jointName); void setModelOffset(const glm::mat4& modelOffset); + const AnimPose& getGeometryOffset() const { return _geometryOffset; } // AJT: REMOVE /* @@ -162,7 +163,7 @@ public: void removeAnimationStateHandler(QScriptValue handler); void animationStateHandlerResult(int identifier, QScriptValue result); - bool getModelOffset(glm::vec3& modelOffsetOut) const; + bool getModelRegistrationPoint(glm::vec3& modelRegistrationPointOut) const; const glm::vec3& getEyesInRootFrame() const { return _eyesInRootFrame; } @@ -182,8 +183,9 @@ public: QVector _jointStates; glm::mat4 _legacyModelOffset; - AnimPose _modelOffset; - glm::vec3 _modelScale; + // AJT: TODO document these better + AnimPose _modelOffset; // model to avatar space (without 180 flip) + AnimPose _geometryOffset; // geometry to model space (includes unit offset & fst offsets) AnimPoseVec _relativePoses; // in fbx model space relative to parent. AnimPoseVec _absolutePoses; // in fbx model space after _modelOffset is applied. AnimPoseVec _overridePoses; // in fbx model space relative to parent. diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 19c3131233..07d624c73f 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -107,7 +107,7 @@ void Model::initJointTransforms() { return; } const FBXGeometry& geometry = _geometry->getFBXGeometry(); - glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; + glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset); _rig->setModelOffset(modelOffset); } @@ -160,7 +160,7 @@ bool Model::updateGeometry() { // virtual void Model::initJointStates() { const FBXGeometry& geometry = _geometry->getFBXGeometry(); - glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; + glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset); int rootJointIndex = geometry.rootJointIndex; int leftHandJointIndex = geometry.leftHandJointIndex; @@ -947,7 +947,7 @@ void Model::simulateInternal(float deltaTime) { // update the world space transforms for all joints const FBXGeometry& geometry = _geometry->getFBXGeometry(); - glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; + glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset); updateRig(deltaTime, parentTransform); } void Model::updateClusterMatrices() { @@ -1011,7 +1011,7 @@ void Model::updateClusterMatrices() { void Model::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm::quat& targetRotation, float priority) { const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& freeLineage = geometry.joints.at(endIndex).freeLineage; - glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; + glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset); _rig->inverseKinematics(endIndex, targetPosition, targetRotation, priority, freeLineage, parentTransform); }