First pass at having an explicit Hips IK target.

Also, AnimManipulator nodes support setting position and rotation on a single joint.
This commit is contained in:
Anthony J. Thibault 2017-04-04 17:26:00 -07:00
parent 6a6800b8c3
commit a10b157aff
13 changed files with 205 additions and 148 deletions

View file

@ -50,6 +50,12 @@
"type": "inverseKinematics", "type": "inverseKinematics",
"data": { "data": {
"targets": [ "targets": [
{
"jointName": "Hips",
"positionVar": "hipsPosition",
"rotationVar": "hipsRotation",
"typeVar": "hipsType"
},
{ {
"jointName": "RightHand", "jointName": "RightHand",
"positionVar": "rightHandPosition", "positionVar": "rightHandPosition",
@ -91,20 +97,27 @@
"children": [] "children": []
}, },
{ {
"id": "manipulatorOverlay", "id": "hipsManipulatorOverlay",
"type": "overlay", "type": "overlay",
"data": { "data": {
"alpha": 1.0, "alpha": 0.0,
"boneSet": "spineOnly" "boneSet": "hipsOnly"
}, },
"children": [ "children": [
{ {
"id": "spineLean", "id": "hipsManipulator",
"type": "manipulator", "type": "manipulator",
"data": { "data": {
"alpha": 0.0, "alpha": 0.0,
"alphaVar": "hipsManipulatorAlpha",
"joints": [ "joints": [
{ "type": "absoluteRotation", "jointName": "Spine", "var": "lean" } {
"jointName": "Hips",
"rotationType": "absolute",
"translationType": "absolute",
"rotationVar": "hipsManipulatorRotation",
"translationVar": "hipsManipulatorPosition"
}
] ]
}, },
"children": [] "children": []

View file

@ -553,9 +553,12 @@ private:
void setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visiblity); 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. // derive avatar body position and orientation from the current HMD Sensor location.
// results are in HMD frame // results are in HMD frame
glm::mat4 deriveBodyFromHMDSensor() const; glm::mat4 deriveBodyFromHMDSensor() const;
private:
virtual void updatePalms() override {} virtual void updatePalms() override {}
void lateUpdatePalms(); void lateUpdatePalms();

View file

@ -119,7 +119,11 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
headParams.rigHeadPosition = extractTranslation(rigHMDMat); headParams.rigHeadPosition = extractTranslation(rigHMDMat);
headParams.rigHeadOrientation = extractRotation(rigHMDMat); headParams.rigHeadOrientation = extractRotation(rigHMDMat);
headParams.worldHeadOrientation = extractRotation(worldHMDMat); headParams.worldHeadOrientation = extractRotation(worldHMDMat);
headParams.hipsMatrix = worldToRig * myAvatar->getSensorToWorldMatrix() * myAvatar->deriveBodyFromHMDSensor();
headParams.hipsEnabled = true;
} else { } else {
headParams.hipsEnabled = false;
headParams.isInHMD = false; headParams.isInHMD = false;
// We don't have a valid localHeadPosition. // We don't have a valid localHeadPosition.

View file

@ -87,6 +87,7 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::
// build a list of valid targets from _targetVarVec and animVars // build a list of valid targets from _targetVarVec and animVars
_maxTargetIndex = -1; _maxTargetIndex = -1;
bool removeUnfoundJoints = false; bool removeUnfoundJoints = false;
for (auto& targetVar : _targetVarVec) { for (auto& targetVar : _targetVarVec) {
if (targetVar.jointIndex == -1) { if (targetVar.jointIndex == -1) {
// this targetVar hasn't been validated yet... // 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); AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses);
glm::quat rotation = animVars.lookupRigToGeometry(targetVar.rotationVar, defaultPose.rot()); glm::quat rotation = animVars.lookupRigToGeometry(targetVar.rotationVar, defaultPose.rot());
glm::vec3 translation = animVars.lookupRigToGeometry(targetVar.positionVar, defaultPose.trans()); glm::vec3 translation = animVars.lookupRigToGeometry(targetVar.positionVar, defaultPose.trans());
if (target.getType() == IKTarget::Type::HipsRelativeRotationAndPosition) { AnimPose absPose(glm::vec3(1.0f), rotation, translation);
translation += _hipsOffset;
}
target.setPose(rotation, translation); target.setPose(rotation, translation);
target.setIndex(targetVar.jointIndex); target.setIndex(targetVar.jointIndex);
targets.push_back(target); targets.push_back(target);
@ -441,26 +441,6 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
computeTargets(animVars, targets, underPoses); 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(); _previousEnableDebugIKTargets = context.getEnableDebugDrawIKTargets();
if (targets.empty()) { if (targets.empty()) {
@ -478,25 +458,52 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
{ {
PROFILE_RANGE_EX(simulation_animation, "ik/shiftHips", 0xffff00ff, 0); PROFILE_RANGE_EX(simulation_animation, "ik/shiftHips", 0xffff00ff, 0);
// shift hips according to the _hipsOffset from the previous frame // AJT: TODO only need abs poses below hips.
float offsetLength = glm::length(_hipsOffset); AnimPoseVec absolutePoses;
const float MIN_HIPS_OFFSET_LENGTH = 0.03f; absolutePoses.resize(_relativePoses.size());
if (offsetLength > MIN_HIPS_OFFSET_LENGTH && _hipsIndex >= 0) { computeAbsolutePoses(absolutePoses);
// but only if offset is long enough
float scaleFactor = ((offsetLength - MIN_HIPS_OFFSET_LENGTH) / offsetLength); for (auto& target: targets) {
if (_hipsParentIndex == -1) { if (target.getType() == IKTarget::Type::RotationAndPosition && target.getIndex() == _hipsIndex) {
// the hips are the root so _hipsOffset is in the correct frame AnimPose absPose = target.getPose();
_relativePoses[_hipsIndex].trans() = underPoses[_hipsIndex].trans() + scaleFactor * _hipsOffset; int parentIndex = _skeleton->getParentIndex(target.getIndex());
} else { if (parentIndex != -1) {
// the hips are NOT the root so we need to transform _hipsOffset into hips local-frame _relativePoses[_hipsIndex] = absolutePoses[parentIndex].inverse() * absPose;
glm::quat hipsFrameRotation = _relativePoses[_hipsParentIndex].rot(); } else {
int index = _skeleton->getParentIndex(_hipsParentIndex); _relativePoses[_hipsIndex] = absPose;
while (index != -1) {
hipsFrameRotation *= _relativePoses[index].rot();
index = _skeleton->getParentIndex(index);
} }
_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); PROFILE_RANGE_EX(simulation_animation, "ik/ccd", 0xffff00ff, 0);
solveWithCyclicCoordinateDescent(targets); 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; return _relativePoses;

View file

@ -12,6 +12,16 @@
#include "AnimUtil.h" #include "AnimUtil.h"
#include "AnimationLogging.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) : AnimManipulator::AnimManipulator(const QString& id, float alpha) :
AnimNode(AnimNode::Type::Manipulator, id), AnimNode(AnimNode::Type::Manipulator, id),
_alpha(alpha) { _alpha(alpha) {
@ -36,7 +46,10 @@ const AnimPoseVec& AnimManipulator::overlay(const AnimVariantMap& animVars, cons
} }
for (auto& jointVar : _jointVars) { for (auto& jointVar : _jointVars) {
if (!jointVar.hasPerformedJointLookup) { if (!jointVar.hasPerformedJointLookup) {
// map from joint name to joint index and cache the result.
jointVar.jointIndex = _skeleton->nameToJointIndex(jointVar.jointName); jointVar.jointIndex = _skeleton->nameToJointIndex(jointVar.jointName);
if (jointVar.jointIndex < 0) { if (jointVar.jointIndex < 0) {
qCWarning(animation) << "AnimManipulator could not find jointName" << jointVar.jointName << "in skeleton"; 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); 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) { // convert to from absolute to relative.
defaultAbsPose.rot() = animVars.lookupRigToGeometry(jointVar.var, defaultAbsPose.rot()); AnimPose parentAbsPose;
} else if (jointVar.type == JointVar::Type::AbsolutePosition) { int parentIndex = _skeleton->getParentIndex(jointVar.jointIndex);
defaultAbsPose.trans() = animVars.lookupRigToGeometry(jointVar.var, defaultAbsPose.trans()); if (parentIndex >= 0) {
parentAbsPose = _skeleton->getAbsolutePose(parentIndex, underPoses);
}
// convert from absolute to relative
relTrans = transformPoint(parentAbsPose.inverse(), absTrans);
break;
} }
case JointVar::Type::Relative:
// because jointVar is absolute, we must use an absolute parent frame to convert into a relative pose. relTrans = animVars.lookupRigToGeometryVector(jointVar.translationVar, defaultRelPose.trans());
AnimPose parentAbsPose = AnimPose::identity; break;
int parentIndex = _skeleton->getParentIndex(jointVar.jointIndex); case JointVar::Type::UnderPose:
if (parentIndex >= 0) { relTrans = underPoses[jointVar.jointIndex].trans();
parentAbsPose = _skeleton->getAbsolutePose(parentIndex, underPoses); break;
} case JointVar::Type::Default:
default:
// convert from absolute to relative relTrans = defaultRelPose.trans();
return parentAbsPose.inverse() * defaultAbsPose; break;
} 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;
} }
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);
} }

View file

@ -31,17 +31,20 @@ public:
struct JointVar { struct JointVar {
enum class Type { enum class Type {
AbsoluteRotation = 0, Absolute,
AbsolutePosition, Relative,
RelativeRotation, UnderPose,
RelativePosition, Default,
NumTypes NumTypes
}; };
JointVar(const QString& varIn, const QString& jointNameIn, Type typeIn) : var(varIn), jointName(jointNameIn), type(typeIn), jointIndex(-1), hasPerformedJointLookup(false) {} JointVar(const QString& jointNameIn, Type rotationType, Type translationType, const QString& rotationVarIn, const QString& translationVarIn);
QString var = "";
QString jointName = ""; QString jointName = "";
Type type = Type::AbsoluteRotation; Type rotationType = Type::Absolute;
Type translationType = Type::Absolute;
QString rotationVar = "";
QString translationVar = "";
int jointIndex = -1; int jointIndex = -1;
bool hasPerformedJointLookup = false; bool hasPerformedJointLookup = false;
bool isRelative = false; bool isRelative = false;

View file

@ -79,10 +79,10 @@ static AnimStateMachine::InterpType stringToInterpType(const QString& str) {
static const char* animManipulatorJointVarTypeToString(AnimManipulator::JointVar::Type type) { static const char* animManipulatorJointVarTypeToString(AnimManipulator::JointVar::Type type) {
switch (type) { switch (type) {
case AnimManipulator::JointVar::Type::AbsoluteRotation: return "absoluteRotation"; case AnimManipulator::JointVar::Type::Absolute: return "absolute";
case AnimManipulator::JointVar::Type::AbsolutePosition: return "absolutePosition"; case AnimManipulator::JointVar::Type::Relative: return "relative";
case AnimManipulator::JointVar::Type::RelativeRotation: return "relativeRotation"; case AnimManipulator::JointVar::Type::UnderPose: return "underPose";
case AnimManipulator::JointVar::Type::RelativePosition: return "relativePosition"; case AnimManipulator::JointVar::Type::Default: return "default";
case AnimManipulator::JointVar::Type::NumTypes: return nullptr; case AnimManipulator::JointVar::Type::NumTypes: return nullptr;
}; };
return nullptr; return nullptr;
@ -339,7 +339,8 @@ static const char* boneSetStrings[AnimOverlay::NumBoneSets] = {
"spineOnly", "spineOnly",
"empty", "empty",
"leftHand", "leftHand",
"rightHand" "rightHand",
"hipsOnly"
}; };
static AnimOverlay::BoneSet stringToBoneSetEnum(const QString& str) { static AnimOverlay::BoneSet stringToBoneSetEnum(const QString& str) {
@ -406,17 +407,25 @@ static AnimNode::Pointer loadManipulatorNode(const QJsonObject& jsonObj, const Q
} }
auto jointObj = jointValue.toObject(); auto jointObj = jointValue.toObject();
READ_STRING(type, jointObj, id, jsonUrl, nullptr);
READ_STRING(jointName, 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); AnimManipulator::JointVar::Type jointVarRotationType = stringToAnimManipulatorJointVarType(rotationType);
if (jointVarType == AnimManipulator::JointVar::Type::NumTypes) { if (jointVarRotationType == AnimManipulator::JointVar::Type::NumTypes) {
qCCritical(animation) << "AnimNodeLoader, bad type in \"joints\", id =" << id << ", url =" << jsonUrl.toDisplayString(); qCWarning(animation) << "AnimNodeLoader, bad rotationType in \"joints\", id =" << id << ", url =" << jsonUrl.toDisplayString();
return nullptr; 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); node->addJointVar(jointVar);
}; };

View file

@ -34,6 +34,7 @@ void AnimOverlay::buildBoneSet(BoneSet boneSet) {
case SpineOnlyBoneSet: buildSpineOnlyBoneSet(); break; case SpineOnlyBoneSet: buildSpineOnlyBoneSet(); break;
case LeftHandBoneSet: buildLeftHandBoneSet(); break; case LeftHandBoneSet: buildLeftHandBoneSet(); break;
case RightHandBoneSet: buildRightHandBoneSet(); break; case RightHandBoneSet: buildRightHandBoneSet(); break;
case HipsOnlyBoneSet: buildHipsOnlyBoneSet(); break;
default: default:
case EmptyBoneSet: buildEmptyBoneSet(); break; 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 // for AnimDebugDraw rendering
const AnimPoseVec& AnimOverlay::getPosesInternal() const { const AnimPoseVec& AnimOverlay::getPosesInternal() const {
return _poses; return _poses;

View file

@ -37,6 +37,7 @@ public:
EmptyBoneSet, EmptyBoneSet,
LeftHandBoneSet, LeftHandBoneSet,
RightHandBoneSet, RightHandBoneSet,
HipsOnlyBoneSet,
NumBoneSets NumBoneSets
}; };
@ -75,6 +76,7 @@ public:
void buildEmptyBoneSet(); void buildEmptyBoneSet();
void buildLeftHandBoneSet(); void buildLeftHandBoneSet();
void buildRightHandBoneSet(); void buildRightHandBoneSet();
void buildHipsOnlyBoneSet();
// no copies // no copies
AnimOverlay(const AnimOverlay&) = delete; AnimOverlay(const AnimOverlay&) = delete;

View file

@ -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 { const glm::quat& lookupRaw(const QString& key, const glm::quat& defaultValue) const {
if (key.isEmpty()) { if (key.isEmpty()) {
return defaultValue; return defaultValue;

View file

@ -21,13 +21,14 @@ public:
RotationOnly, RotationOnly,
HmdHead, HmdHead,
HipsRelativeRotationAndPosition, HipsRelativeRotationAndPosition,
Unknown, Unknown
}; };
IKTarget() {} IKTarget() {}
const glm::vec3& getTranslation() const { return _pose.trans(); } const glm::vec3& getTranslation() const { return _pose.trans(); }
const glm::quat& getRotation() const { return _pose.rot(); } const glm::quat& getRotation() const { return _pose.rot(); }
const AnimPose& getPose() const { return _pose; }
int getIndex() const { return _index; } int getIndex() const { return _index; }
Type getType() const { return _type; } Type getType() const { return _type; }

View file

@ -1024,6 +1024,15 @@ void Rig::updateFromHeadParameters(const HeadParameters& params, float dt) {
_animVars.set("isTalking", params.isTalking); _animVars.set("isTalking", params.isTalking);
_animVars.set("notIsTalking", !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) { void Rig::updateFromEyeParameters(const EyeParameters& params) {
@ -1094,7 +1103,7 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) {
_animVars.set("headPosition", headPos); _animVars.set("headPosition", headPos);
_animVars.set("headRotation", headRot); _animVars.set("headRotation", headRot);
_animVars.set("headType", (int)IKTarget::Type::HmdHead); _animVars.set("headType", (int)IKTarget::Type::RotationAndPosition);
_animVars.set("neckPosition", neckPos); _animVars.set("neckPosition", neckPos);
_animVars.set("neckRotation", neckRot); _animVars.set("neckRotation", neckRot);
_animVars.set("neckType", (int)IKTarget::Type::Unknown); // 'Unknown' disables the target _animVars.set("neckType", (int)IKTarget::Type::Unknown); // 'Unknown' disables the target

View file

@ -45,6 +45,8 @@ public:
glm::quat worldHeadOrientation = glm::quat(); // world space (-z forward) glm::quat worldHeadOrientation = glm::quat(); // world space (-z forward)
glm::quat rigHeadOrientation = glm::quat(); // rig space (-z forward) glm::quat rigHeadOrientation = glm::quat(); // rig space (-z forward)
glm::vec3 rigHeadPosition = glm::vec3(); // rig space glm::vec3 rigHeadPosition = glm::vec3(); // rig space
glm::mat4 hipsMatrix = glm::mat4(); // rig space
bool hipsEnabled = false;
bool isInHMD = false; bool isInHMD = false;
int neckJointIndex = -1; int neckJointIndex = -1;
bool isTalking = false; bool isTalking = false;