From a10b157affddd7bba5a294ffa63ef310a953b6a2 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 4 Apr 2017 17:26:00 -0700 Subject: [PATCH] First pass at having an explicit Hips IK target. Also, AnimManipulator nodes support setting position and rotation on a single joint. --- .../resources/avatar/avatar-animation.json | 23 ++- interface/src/avatar/MyAvatar.h | 3 + interface/src/avatar/SkeletonModel.cpp | 4 + .../animation/src/AnimInverseKinematics.cpp | 143 ++++++------------ libraries/animation/src/AnimManipulator.cpp | 95 ++++++++---- libraries/animation/src/AnimManipulator.h | 17 ++- libraries/animation/src/AnimNodeLoader.cpp | 33 ++-- libraries/animation/src/AnimOverlay.cpp | 8 + libraries/animation/src/AnimOverlay.h | 2 + libraries/animation/src/AnimVariant.h | 9 ++ libraries/animation/src/IKTarget.h | 3 +- libraries/animation/src/Rig.cpp | 11 +- libraries/animation/src/Rig.h | 2 + 13 files changed, 205 insertions(+), 148 deletions(-) diff --git a/interface/resources/avatar/avatar-animation.json b/interface/resources/avatar/avatar-animation.json index 975f01855d..daa69b95f7 100644 --- a/interface/resources/avatar/avatar-animation.json +++ b/interface/resources/avatar/avatar-animation.json @@ -50,6 +50,12 @@ "type": "inverseKinematics", "data": { "targets": [ + { + "jointName": "Hips", + "positionVar": "hipsPosition", + "rotationVar": "hipsRotation", + "typeVar": "hipsType" + }, { "jointName": "RightHand", "positionVar": "rightHandPosition", @@ -91,20 +97,27 @@ "children": [] }, { - "id": "manipulatorOverlay", + "id": "hipsManipulatorOverlay", "type": "overlay", "data": { - "alpha": 1.0, - "boneSet": "spineOnly" + "alpha": 0.0, + "boneSet": "hipsOnly" }, "children": [ { - "id": "spineLean", + "id": "hipsManipulator", "type": "manipulator", "data": { "alpha": 0.0, + "alphaVar": "hipsManipulatorAlpha", "joints": [ - { "type": "absoluteRotation", "jointName": "Spine", "var": "lean" } + { + "jointName": "Hips", + "rotationType": "absolute", + "translationType": "absolute", + "rotationVar": "hipsManipulatorRotation", + "translationVar": "hipsManipulatorPosition" + } ] }, "children": [] diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 097d3a1059..b5bea23aa3 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -553,9 +553,12 @@ private: void setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visiblity); + // AJT: FIX ME... reorder this +public: // derive avatar body position and orientation from the current HMD Sensor location. // results are in HMD frame glm::mat4 deriveBodyFromHMDSensor() const; +private: virtual void updatePalms() override {} void lateUpdatePalms(); diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 0c11fa456d..e26c339fb8 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -119,7 +119,11 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { headParams.rigHeadPosition = extractTranslation(rigHMDMat); headParams.rigHeadOrientation = extractRotation(rigHMDMat); headParams.worldHeadOrientation = extractRotation(worldHMDMat); + + headParams.hipsMatrix = worldToRig * myAvatar->getSensorToWorldMatrix() * myAvatar->deriveBodyFromHMDSensor(); + headParams.hipsEnabled = true; } else { + headParams.hipsEnabled = false; headParams.isInHMD = false; // We don't have a valid localHeadPosition. diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 2c9376d591..a27fd01b3c 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -87,6 +87,7 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std:: // build a list of valid targets from _targetVarVec and animVars _maxTargetIndex = -1; bool removeUnfoundJoints = false; + for (auto& targetVar : _targetVarVec) { if (targetVar.jointIndex == -1) { // this targetVar hasn't been validated yet... @@ -105,9 +106,8 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std:: AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses); glm::quat rotation = animVars.lookupRigToGeometry(targetVar.rotationVar, defaultPose.rot()); glm::vec3 translation = animVars.lookupRigToGeometry(targetVar.positionVar, defaultPose.trans()); - if (target.getType() == IKTarget::Type::HipsRelativeRotationAndPosition) { - translation += _hipsOffset; - } + AnimPose absPose(glm::vec3(1.0f), rotation, translation); + target.setPose(rotation, translation); target.setIndex(targetVar.jointIndex); targets.push_back(target); @@ -441,26 +441,6 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars computeTargets(animVars, targets, underPoses); } - // debug render ik targets - if (context.getEnableDebugDrawIKTargets()) { - const vec4 WHITE(1.0f); - glm::mat4 rigToAvatarMat = createMatFromQuatAndPos(Quaternions::Y_180, glm::vec3()); - - for (auto& target : targets) { - glm::mat4 geomTargetMat = createMatFromQuatAndPos(target.getRotation(), target.getTranslation()); - glm::mat4 avatarTargetMat = rigToAvatarMat * context.getGeometryToRigMatrix() * geomTargetMat; - - QString name = QString("ikTarget%1").arg(target.getIndex()); - DebugDraw::getInstance().addMyAvatarMarker(name, glmExtractRotation(avatarTargetMat), extractTranslation(avatarTargetMat), WHITE); - } - } else if (context.getEnableDebugDrawIKTargets() != _previousEnableDebugIKTargets) { - // remove markers if they were added last frame. - for (auto& target : targets) { - QString name = QString("ikTarget%1").arg(target.getIndex()); - DebugDraw::getInstance().removeMyAvatarMarker(name); - } - } - _previousEnableDebugIKTargets = context.getEnableDebugDrawIKTargets(); if (targets.empty()) { @@ -478,25 +458,52 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars { PROFILE_RANGE_EX(simulation_animation, "ik/shiftHips", 0xffff00ff, 0); - // shift hips according to the _hipsOffset from the previous frame - float offsetLength = glm::length(_hipsOffset); - const float MIN_HIPS_OFFSET_LENGTH = 0.03f; - if (offsetLength > MIN_HIPS_OFFSET_LENGTH && _hipsIndex >= 0) { - // but only if offset is long enough - float scaleFactor = ((offsetLength - MIN_HIPS_OFFSET_LENGTH) / offsetLength); - if (_hipsParentIndex == -1) { - // the hips are the root so _hipsOffset is in the correct frame - _relativePoses[_hipsIndex].trans() = underPoses[_hipsIndex].trans() + scaleFactor * _hipsOffset; - } else { - // the hips are NOT the root so we need to transform _hipsOffset into hips local-frame - glm::quat hipsFrameRotation = _relativePoses[_hipsParentIndex].rot(); - int index = _skeleton->getParentIndex(_hipsParentIndex); - while (index != -1) { - hipsFrameRotation *= _relativePoses[index].rot(); - index = _skeleton->getParentIndex(index); + // AJT: TODO only need abs poses below hips. + AnimPoseVec absolutePoses; + absolutePoses.resize(_relativePoses.size()); + computeAbsolutePoses(absolutePoses); + + for (auto& target: targets) { + if (target.getType() == IKTarget::Type::RotationAndPosition && target.getIndex() == _hipsIndex) { + AnimPose absPose = target.getPose(); + int parentIndex = _skeleton->getParentIndex(target.getIndex()); + if (parentIndex != -1) { + _relativePoses[_hipsIndex] = absolutePoses[parentIndex].inverse() * absPose; + } else { + _relativePoses[_hipsIndex] = absPose; } - _relativePoses[_hipsIndex].trans() = underPoses[_hipsIndex].trans() - + glm::inverse(glm::normalize(hipsFrameRotation)) * (scaleFactor * _hipsOffset); + } + } + + for (auto& target: targets) { + if (target.getType() == IKTarget::Type::HipsRelativeRotationAndPosition) { + AnimPose pose = target.getPose(); + pose.trans() = pose.trans() + (_relativePoses[_hipsIndex].trans() - underPoses[_hipsIndex].trans()); + target.setPose(pose.rot(), pose.trans()); + } + } + } + + { + PROFILE_RANGE_EX(simulation_animation, "ik/debugDraw", 0xffff00ff, 0); + + // debug render ik targets + if (context.getEnableDebugDrawIKTargets()) { + const vec4 WHITE(1.0f); + glm::mat4 rigToAvatarMat = createMatFromQuatAndPos(Quaternions::Y_180, glm::vec3()); + + for (auto& target : targets) { + glm::mat4 geomTargetMat = createMatFromQuatAndPos(target.getRotation(), target.getTranslation()); + glm::mat4 avatarTargetMat = rigToAvatarMat * context.getGeometryToRigMatrix() * geomTargetMat; + + QString name = QString("ikTarget%1").arg(target.getIndex()); + DebugDraw::getInstance().addMyAvatarMarker(name, glmExtractRotation(avatarTargetMat), extractTranslation(avatarTargetMat), WHITE); + } + } else if (context.getEnableDebugDrawIKTargets() != _previousEnableDebugIKTargets) { + // remove markers if they were added last frame. + for (auto& target : targets) { + QString name = QString("ikTarget%1").arg(target.getIndex()); + DebugDraw::getInstance().removeMyAvatarMarker(name); } } } @@ -505,60 +512,6 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars PROFILE_RANGE_EX(simulation_animation, "ik/ccd", 0xffff00ff, 0); solveWithCyclicCoordinateDescent(targets); } - - { - PROFILE_RANGE_EX(simulation_animation, "ik/measureHipsOffset", 0xffff00ff, 0); - - // measure new _hipsOffset for next frame - // by looking for discrepancies between where a targeted endEffector is - // and where it wants to be (after IK solutions are done) - glm::vec3 newHipsOffset = Vectors::ZERO; - for (auto& target: targets) { - int targetIndex = target.getIndex(); - if (targetIndex == _headIndex && _headIndex != -1) { - // special handling for headTarget - if (target.getType() == IKTarget::Type::RotationOnly) { - // we want to shift the hips to bring the underPose closer - // to where the head happens to be (overpose) - glm::vec3 under = _skeleton->getAbsolutePose(_headIndex, underPoses).trans(); - glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans(); - const float HEAD_OFFSET_SLAVE_FACTOR = 0.65f; - newHipsOffset += HEAD_OFFSET_SLAVE_FACTOR * (actual - under); - } else if (target.getType() == IKTarget::Type::HmdHead) { - // we want to shift the hips to bring the head to its designated position - glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans(); - _hipsOffset += target.getTranslation() - actual; - // and ignore all other targets - newHipsOffset = _hipsOffset; - break; - } else if (target.getType() == IKTarget::Type::RotationAndPosition) { - glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans(); - glm::vec3 targetPosition = target.getTranslation(); - newHipsOffset += targetPosition - actualPosition; - - // Add downward pressure on the hips - newHipsOffset *= 0.95f; - newHipsOffset -= 1.0f; - } - } else if (target.getType() == IKTarget::Type::RotationAndPosition) { - glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans(); - glm::vec3 targetPosition = target.getTranslation(); - newHipsOffset += targetPosition - actualPosition; - } - } - - // smooth transitions by relaxing _hipsOffset toward the new value - const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.10f; - float tau = dt < HIPS_OFFSET_SLAVE_TIMESCALE ? dt / HIPS_OFFSET_SLAVE_TIMESCALE : 1.0f; - _hipsOffset += (newHipsOffset - _hipsOffset) * tau; - - // clamp the hips offset - float hipsOffsetLength = glm::length(_hipsOffset); - if (hipsOffsetLength > _maxHipsOffsetLength) { - _hipsOffset *= _maxHipsOffsetLength / hipsOffsetLength; - } - - } } } return _relativePoses; diff --git a/libraries/animation/src/AnimManipulator.cpp b/libraries/animation/src/AnimManipulator.cpp index 111501898a..070949ab3b 100644 --- a/libraries/animation/src/AnimManipulator.cpp +++ b/libraries/animation/src/AnimManipulator.cpp @@ -12,6 +12,16 @@ #include "AnimUtil.h" #include "AnimationLogging.h" +AnimManipulator::JointVar::JointVar(const QString& jointNameIn, Type rotationTypeIn, Type translationTypeIn, + const QString& rotationVarIn, const QString& translationVarIn) : + jointName(jointNameIn), + rotationType(rotationTypeIn), + translationType(translationTypeIn), + rotationVar(rotationVarIn), + translationVar(translationVarIn), + jointIndex(-1), + hasPerformedJointLookup(false) {} + AnimManipulator::AnimManipulator(const QString& id, float alpha) : AnimNode(AnimNode::Type::Manipulator, id), _alpha(alpha) { @@ -36,7 +46,10 @@ const AnimPoseVec& AnimManipulator::overlay(const AnimVariantMap& animVars, cons } for (auto& jointVar : _jointVars) { + if (!jointVar.hasPerformedJointLookup) { + + // map from joint name to joint index and cache the result. jointVar.jointIndex = _skeleton->nameToJointIndex(jointVar.jointName); if (jointVar.jointIndex < 0) { qCWarning(animation) << "AnimManipulator could not find jointName" << jointVar.jointName << "in skeleton"; @@ -100,34 +113,62 @@ AnimPose AnimManipulator::computeRelativePoseFromJointVar(const AnimVariantMap& AnimPose defaultAbsPose = _skeleton->getAbsolutePose(jointVar.jointIndex, underPoses); - if (jointVar.type == JointVar::Type::AbsoluteRotation || jointVar.type == JointVar::Type::AbsolutePosition) { + // compute relative translation + glm::vec3 relTrans; + switch (jointVar.translationType) { + case JointVar::Type::Absolute: { + glm::vec3 absTrans = animVars.lookupRigToGeometry(jointVar.translationVar, defaultAbsPose.trans()); - if (jointVar.type == JointVar::Type::AbsoluteRotation) { - defaultAbsPose.rot() = animVars.lookupRigToGeometry(jointVar.var, defaultAbsPose.rot()); - } else if (jointVar.type == JointVar::Type::AbsolutePosition) { - defaultAbsPose.trans() = animVars.lookupRigToGeometry(jointVar.var, defaultAbsPose.trans()); + // convert to from absolute to relative. + AnimPose parentAbsPose; + int parentIndex = _skeleton->getParentIndex(jointVar.jointIndex); + if (parentIndex >= 0) { + parentAbsPose = _skeleton->getAbsolutePose(parentIndex, underPoses); + } + + // convert from absolute to relative + relTrans = transformPoint(parentAbsPose.inverse(), absTrans); + break; } - - // because jointVar is absolute, we must use an absolute parent frame to convert into a relative pose. - AnimPose parentAbsPose = AnimPose::identity; - int parentIndex = _skeleton->getParentIndex(jointVar.jointIndex); - if (parentIndex >= 0) { - parentAbsPose = _skeleton->getAbsolutePose(parentIndex, underPoses); - } - - // convert from absolute to relative - return parentAbsPose.inverse() * defaultAbsPose; - - } else { - - // override the default rel pose - AnimPose relPose = defaultRelPose; - if (jointVar.type == JointVar::Type::RelativeRotation) { - relPose.rot() = animVars.lookupRigToGeometry(jointVar.var, defaultRelPose.rot()); - } else if (jointVar.type == JointVar::Type::RelativePosition) { - relPose.trans() = animVars.lookupRigToGeometry(jointVar.var, defaultRelPose.trans()); - } - - return relPose; + case JointVar::Type::Relative: + relTrans = animVars.lookupRigToGeometryVector(jointVar.translationVar, defaultRelPose.trans()); + break; + case JointVar::Type::UnderPose: + relTrans = underPoses[jointVar.jointIndex].trans(); + break; + case JointVar::Type::Default: + default: + relTrans = defaultRelPose.trans(); + break; } + + glm::quat relRot; + switch (jointVar.rotationType) { + case JointVar::Type::Absolute: { + glm::quat absRot = animVars.lookupRigToGeometry(jointVar.translationVar, defaultAbsPose.rot()); + + // convert to from absolute to relative. + AnimPose parentAbsPose; + int parentIndex = _skeleton->getParentIndex(jointVar.jointIndex); + if (parentIndex >= 0) { + parentAbsPose = _skeleton->getAbsolutePose(parentIndex, underPoses); + } + + // convert from absolute to relative + relRot = glm::inverse(parentAbsPose.rot()) * absRot; + break; + } + case JointVar::Type::Relative: + relRot = animVars.lookupRigToGeometry(jointVar.translationVar, defaultRelPose.rot()); + break; + case JointVar::Type::UnderPose: + relRot = underPoses[jointVar.jointIndex].rot(); + break; + case JointVar::Type::Default: + default: + relRot = defaultRelPose.rot(); + break; + } + + return AnimPose(glm::vec3(1), relRot, relTrans); } diff --git a/libraries/animation/src/AnimManipulator.h b/libraries/animation/src/AnimManipulator.h index 26f50a7dd9..1134f75da9 100644 --- a/libraries/animation/src/AnimManipulator.h +++ b/libraries/animation/src/AnimManipulator.h @@ -31,17 +31,20 @@ public: struct JointVar { enum class Type { - AbsoluteRotation = 0, - AbsolutePosition, - RelativeRotation, - RelativePosition, + Absolute, + Relative, + UnderPose, + Default, NumTypes }; - JointVar(const QString& varIn, const QString& jointNameIn, Type typeIn) : var(varIn), jointName(jointNameIn), type(typeIn), jointIndex(-1), hasPerformedJointLookup(false) {} - QString var = ""; + JointVar(const QString& jointNameIn, Type rotationType, Type translationType, const QString& rotationVarIn, const QString& translationVarIn); QString jointName = ""; - Type type = Type::AbsoluteRotation; + Type rotationType = Type::Absolute; + Type translationType = Type::Absolute; + QString rotationVar = ""; + QString translationVar = ""; + int jointIndex = -1; bool hasPerformedJointLookup = false; bool isRelative = false; diff --git a/libraries/animation/src/AnimNodeLoader.cpp b/libraries/animation/src/AnimNodeLoader.cpp index 876913fc58..bda4541f36 100644 --- a/libraries/animation/src/AnimNodeLoader.cpp +++ b/libraries/animation/src/AnimNodeLoader.cpp @@ -79,10 +79,10 @@ static AnimStateMachine::InterpType stringToInterpType(const QString& str) { static const char* animManipulatorJointVarTypeToString(AnimManipulator::JointVar::Type type) { switch (type) { - case AnimManipulator::JointVar::Type::AbsoluteRotation: return "absoluteRotation"; - case AnimManipulator::JointVar::Type::AbsolutePosition: return "absolutePosition"; - case AnimManipulator::JointVar::Type::RelativeRotation: return "relativeRotation"; - case AnimManipulator::JointVar::Type::RelativePosition: return "relativePosition"; + case AnimManipulator::JointVar::Type::Absolute: return "absolute"; + case AnimManipulator::JointVar::Type::Relative: return "relative"; + case AnimManipulator::JointVar::Type::UnderPose: return "underPose"; + case AnimManipulator::JointVar::Type::Default: return "default"; case AnimManipulator::JointVar::Type::NumTypes: return nullptr; }; return nullptr; @@ -339,7 +339,8 @@ static const char* boneSetStrings[AnimOverlay::NumBoneSets] = { "spineOnly", "empty", "leftHand", - "rightHand" + "rightHand", + "hipsOnly" }; static AnimOverlay::BoneSet stringToBoneSetEnum(const QString& str) { @@ -406,17 +407,25 @@ static AnimNode::Pointer loadManipulatorNode(const QJsonObject& jsonObj, const Q } auto jointObj = jointValue.toObject(); - READ_STRING(type, jointObj, id, jsonUrl, nullptr); READ_STRING(jointName, jointObj, id, jsonUrl, nullptr); - READ_STRING(var, jointObj, id, jsonUrl, nullptr); + READ_STRING(rotationType, jointObj, id, jsonUrl, nullptr); + READ_STRING(translationType, jointObj, id, jsonUrl, nullptr); + READ_STRING(rotationVar, jointObj, id, jsonUrl, nullptr); + READ_STRING(translationVar, jointObj, id, jsonUrl, nullptr); - AnimManipulator::JointVar::Type jointVarType = stringToAnimManipulatorJointVarType(type); - if (jointVarType == AnimManipulator::JointVar::Type::NumTypes) { - qCCritical(animation) << "AnimNodeLoader, bad type in \"joints\", id =" << id << ", url =" << jsonUrl.toDisplayString(); - return nullptr; + AnimManipulator::JointVar::Type jointVarRotationType = stringToAnimManipulatorJointVarType(rotationType); + if (jointVarRotationType == AnimManipulator::JointVar::Type::NumTypes) { + qCWarning(animation) << "AnimNodeLoader, bad rotationType in \"joints\", id =" << id << ", url =" << jsonUrl.toDisplayString(); + jointVarRotationType = AnimManipulator::JointVar::Type::Default; } - AnimManipulator::JointVar jointVar(var, jointName, jointVarType); + AnimManipulator::JointVar::Type jointVarTranslationType = stringToAnimManipulatorJointVarType(translationType); + if (jointVarTranslationType == AnimManipulator::JointVar::Type::NumTypes) { + qCWarning(animation) << "AnimNodeLoader, bad translationType in \"joints\", id =" << id << ", url =" << jsonUrl.toDisplayString(); + jointVarTranslationType = AnimManipulator::JointVar::Type::Default; + } + + AnimManipulator::JointVar jointVar(jointName, jointVarRotationType, jointVarTranslationType, rotationVar, translationVar); node->addJointVar(jointVar); }; diff --git a/libraries/animation/src/AnimOverlay.cpp b/libraries/animation/src/AnimOverlay.cpp index dbc635af66..e086413dde 100644 --- a/libraries/animation/src/AnimOverlay.cpp +++ b/libraries/animation/src/AnimOverlay.cpp @@ -34,6 +34,7 @@ void AnimOverlay::buildBoneSet(BoneSet boneSet) { case SpineOnlyBoneSet: buildSpineOnlyBoneSet(); break; case LeftHandBoneSet: buildLeftHandBoneSet(); break; case RightHandBoneSet: buildRightHandBoneSet(); break; + case HipsOnlyBoneSet: buildHipsOnlyBoneSet(); break; default: case EmptyBoneSet: buildEmptyBoneSet(); break; } @@ -188,6 +189,13 @@ void AnimOverlay::buildRightHandBoneSet() { }); } +void AnimOverlay::buildHipsOnlyBoneSet() { + assert(_skeleton); + buildEmptyBoneSet(); + int hipsJoint = _skeleton->nameToJointIndex("Hips"); + _boneSetVec[hipsJoint] = 1.0f; +} + // for AnimDebugDraw rendering const AnimPoseVec& AnimOverlay::getPosesInternal() const { return _poses; diff --git a/libraries/animation/src/AnimOverlay.h b/libraries/animation/src/AnimOverlay.h index 2f34c07309..ed9439feb7 100644 --- a/libraries/animation/src/AnimOverlay.h +++ b/libraries/animation/src/AnimOverlay.h @@ -37,6 +37,7 @@ public: EmptyBoneSet, LeftHandBoneSet, RightHandBoneSet, + HipsOnlyBoneSet, NumBoneSets }; @@ -75,6 +76,7 @@ public: void buildEmptyBoneSet(); void buildLeftHandBoneSet(); void buildRightHandBoneSet(); + void buildHipsOnlyBoneSet(); // no copies AnimOverlay(const AnimOverlay&) = delete; diff --git a/libraries/animation/src/AnimVariant.h b/libraries/animation/src/AnimVariant.h index 3466013ff6..d383b5abb8 100644 --- a/libraries/animation/src/AnimVariant.h +++ b/libraries/animation/src/AnimVariant.h @@ -165,6 +165,15 @@ public: } } + glm::vec3 lookupRigToGeometryVector(const QString& key, const glm::vec3& defaultValue) const { + if (key.isEmpty()) { + return defaultValue; + } else { + auto iter = _map.find(key); + return iter != _map.end() ? transformVectorFast(_rigToGeometryMat, iter->second.getVec3()) : defaultValue; + } + } + const glm::quat& lookupRaw(const QString& key, const glm::quat& defaultValue) const { if (key.isEmpty()) { return defaultValue; diff --git a/libraries/animation/src/IKTarget.h b/libraries/animation/src/IKTarget.h index 9ea34a6165..acb01d9861 100644 --- a/libraries/animation/src/IKTarget.h +++ b/libraries/animation/src/IKTarget.h @@ -21,13 +21,14 @@ public: RotationOnly, HmdHead, HipsRelativeRotationAndPosition, - Unknown, + Unknown }; IKTarget() {} const glm::vec3& getTranslation() const { return _pose.trans(); } const glm::quat& getRotation() const { return _pose.rot(); } + const AnimPose& getPose() const { return _pose; } int getIndex() const { return _index; } Type getType() const { return _type; } diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index fb0867e2de..adc40d6e81 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1024,6 +1024,15 @@ void Rig::updateFromHeadParameters(const HeadParameters& params, float dt) { _animVars.set("isTalking", params.isTalking); _animVars.set("notIsTalking", !params.isTalking); + + // AJT: + if (params.hipsEnabled) { + _animVars.set("hipsType", (int)IKTarget::Type::RotationAndPosition); + _animVars.set("hipsPosition", extractTranslation(params.hipsMatrix)); + _animVars.set("hipsRotation", glmExtractRotation(params.hipsMatrix) * Quaternions::Y_180); + } else { + _animVars.set("hipsType", (int)IKTarget::Type::Unknown); + } } void Rig::updateFromEyeParameters(const EyeParameters& params) { @@ -1094,7 +1103,7 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) { _animVars.set("headPosition", headPos); _animVars.set("headRotation", headRot); - _animVars.set("headType", (int)IKTarget::Type::HmdHead); + _animVars.set("headType", (int)IKTarget::Type::RotationAndPosition); _animVars.set("neckPosition", neckPos); _animVars.set("neckRotation", neckRot); _animVars.set("neckType", (int)IKTarget::Type::Unknown); // 'Unknown' disables the target diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 2cd20c2704..89f0d624f9 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -45,6 +45,8 @@ public: glm::quat worldHeadOrientation = glm::quat(); // world space (-z forward) glm::quat rigHeadOrientation = glm::quat(); // rig space (-z forward) glm::vec3 rigHeadPosition = glm::vec3(); // rig space + glm::mat4 hipsMatrix = glm::mat4(); // rig space + bool hipsEnabled = false; bool isInHMD = false; int neckJointIndex = -1; bool isTalking = false;