AnimVars are now in avatar/rig space

This makes it much simpler for code out side of the rig to manipulate AnimVars

* Removed mat4 type from AnimVars
* AnimVariantMap now has a _rigToGeometryTransform matrix
  used to transform positions and rotations into the correct coordinate frame.
* Moved AnimPose code to extract a quat from a scaled matrix into GLMHelpers
This commit is contained in:
Anthony J. Thibault 2015-11-20 18:29:17 -08:00
parent 4f8cd6930d
commit 54408a9c87
10 changed files with 102 additions and 101 deletions

View file

@ -1749,12 +1749,10 @@ 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));
localEyes = rotY180 * (((DEFAULT_RIGHT_EYE_POS + DEFAULT_LEFT_EYE_POS) / 2.0f) - DEFAULT_HIPS_POS);
localNeck = rotY180 * (DEFAULT_NECK_POS - DEFAULT_HIPS_POS);
localEyes = (((DEFAULT_RIGHT_EYE_POS + DEFAULT_LEFT_EYE_POS) / 2.0f) - DEFAULT_HIPS_POS);
localNeck = (DEFAULT_NECK_POS - DEFAULT_HIPS_POS);
} else {
// TODO: At the moment MyAvatar does not have access to the rig, which has the skeleton, which has the bind poses.
// for now use the _debugDrawSkeleton, which is initialized with the same FBX model as the rig.
@ -1765,17 +1763,13 @@ glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const {
int neckIndex = _debugDrawSkeleton->nameToJointIndex("Neck");
int hipsIndex = _debugDrawSkeleton->nameToJointIndex("Hips");
// AJT: TODO: perhaps expose default gets from rig?
// so this can become _rig->getAbsoluteDefaultPose(rightEyeIndex)...
glm::vec3 absRightEyePos = rightEyeIndex != -1 ? _rig->getAbsoluteDefaultPose(rightEyeIndex).trans : DEFAULT_RIGHT_EYE_POS;
glm::vec3 absLeftEyePos = leftEyeIndex != -1 ? _rig->getAbsoluteDefaultPose(leftEyeIndex).trans : DEFAULT_LEFT_EYE_POS;
glm::vec3 absNeckPos = neckIndex != -1 ? _rig->getAbsoluteDefaultPose(neckIndex).trans : DEFAULT_NECK_POS;
glm::vec3 absHipsPos = neckIndex != -1 ? _rig->getAbsoluteDefaultPose(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);
localNeck = rotY180 * (absNeckPos - absHipsPos);
localEyes = (((absRightEyePos + absLeftEyePos) / 2.0f) - absHipsPos);
localNeck = (absNeckPos - absHipsPos);
}
// apply simplistic head/neck model

View file

@ -98,8 +98,8 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::
target.setType(animVars.lookup(targetVar.typeVar, (int)IKTarget::Type::RotationAndPosition));
if (target.getType() != IKTarget::Type::Unknown) {
AnimPose defaultPose = _skeleton->getAbsolutePose(targetVar.jointIndex, underPoses);
glm::quat rotation = animVars.lookup(targetVar.rotationVar, defaultPose.rot);
glm::vec3 translation = animVars.lookup(targetVar.positionVar, defaultPose.trans);
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;
}

View file

@ -103,9 +103,9 @@ AnimPose AnimManipulator::computeRelativePoseFromJointVar(const AnimVariantMap&
if (jointVar.type == JointVar::Type::AbsoluteRotation || jointVar.type == JointVar::Type::AbsolutePosition) {
if (jointVar.type == JointVar::Type::AbsoluteRotation) {
defaultAbsPose.rot = animVars.lookup(jointVar.var, defaultAbsPose.rot);
defaultAbsPose.rot = animVars.lookupRigToGeometry(jointVar.var, defaultAbsPose.rot);
} else if (jointVar.type == JointVar::Type::AbsolutePosition) {
defaultAbsPose.trans = animVars.lookup(jointVar.var, defaultAbsPose.trans);
defaultAbsPose.trans = animVars.lookupRigToGeometry(jointVar.var, defaultAbsPose.trans);
}
// because jointVar is absolute, we must use an absolute parent frame to convert into a relative pose.
@ -123,9 +123,9 @@ AnimPose AnimManipulator::computeRelativePoseFromJointVar(const AnimVariantMap&
// override the default rel pose
AnimPose relPose = defaultRelPose;
if (jointVar.type == JointVar::Type::RelativeRotation) {
relPose.rot = animVars.lookup(jointVar.var, defaultRelPose.rot);
relPose.rot = animVars.lookupRigToGeometry(jointVar.var, defaultRelPose.rot);
} else if (jointVar.type == JointVar::Type::RelativePosition) {
relPose.trans = animVars.lookup(jointVar.var, defaultRelPose.trans);
relPose.trans = animVars.lookupRigToGeometry(jointVar.var, defaultRelPose.trans);
}
return relPose;

View file

@ -10,7 +10,6 @@
#include "AnimPose.h"
#include <GLMHelpers.h>
#include <glm/gtc/matrix_transform.hpp>
#include <algorithm>
const AnimPose AnimPose::identity = AnimPose(glm::vec3(1.0f),
@ -19,14 +18,7 @@ const AnimPose AnimPose::identity = AnimPose(glm::vec3(1.0f),
AnimPose::AnimPose(const glm::mat4& mat) {
scale = extractScale(mat);
float maxScale = std::max(std::max(scale.x, scale.y), scale.z);
if (maxScale > 1.01f || maxScale <= 0.99f) {
// quat_cast doesn't work so well with scaled matrices, so cancel it out.
mat4 tmp = glm::scale(mat, 1.0f / scale);
rot = glm::normalize(glm::quat_cast(tmp));
} else {
rot = glm::normalize(glm::quat_cast(mat));
}
rot = glmExtractRotation(mat);
trans = extractTranslation(mat);
}

View file

@ -43,7 +43,7 @@ QScriptValue AnimVariantMap::animVariantMapToScriptValue(QScriptEngine* engine,
target.setProperty(name, quatToScriptValue(engine, value.getQuat()));
break;
default:
// Note that we don't do mat4 in Javascript currently, and there's not yet a reason to start now.
// Unknown type
assert(QString("AnimVariant::Type") == QString("valid"));
}
};

View file

@ -18,8 +18,9 @@
#include <map>
#include <set>
#include <QScriptValue>
#include <StreamUtils.h>
#include <GLMHelpers.h>
#include "AnimationLogging.h"
#include "StreamUtils.h"
class AnimVariant {
public:
@ -29,7 +30,6 @@ public:
Float,
Vec3,
Quat,
Mat4,
String,
NumTypes
};
@ -40,7 +40,6 @@ public:
AnimVariant(float value) : _type(Type::Float) { _val.floats[0] = value; }
AnimVariant(const glm::vec3& value) : _type(Type::Vec3) { *reinterpret_cast<glm::vec3*>(&_val) = value; }
AnimVariant(const glm::quat& value) : _type(Type::Quat) { *reinterpret_cast<glm::quat*>(&_val) = value; }
AnimVariant(const glm::mat4& value) : _type(Type::Mat4) { *reinterpret_cast<glm::mat4*>(&_val) = value; }
AnimVariant(const QString& value) : _type(Type::String) { _stringVal = value; }
bool isBool() const { return _type == Type::Bool; }
@ -48,7 +47,6 @@ public:
bool isFloat() const { return _type == Type::Float; }
bool isVec3() const { return _type == Type::Vec3; }
bool isQuat() const { return _type == Type::Quat; }
bool isMat4() const { return _type == Type::Mat4; }
bool isString() const { return _type == Type::String; }
Type getType() const { return _type; }
@ -57,7 +55,6 @@ public:
void setFloat(float value) { assert(_type == Type::Float); _val.floats[0] = value; }
void setVec3(const glm::vec3& value) { assert(_type == Type::Vec3); *reinterpret_cast<glm::vec3*>(&_val) = value; }
void setQuat(const glm::quat& value) { assert(_type == Type::Quat); *reinterpret_cast<glm::quat*>(&_val) = value; }
void setMat4(const glm::mat4& value) { assert(_type == Type::Mat4); *reinterpret_cast<glm::mat4*>(&_val) = value; }
void setString(const QString& value) { assert(_type == Type::String); _stringVal = value; }
bool getBool() const { assert(_type == Type::Bool); return _val.boolVal; }
@ -66,7 +63,6 @@ public:
const glm::vec3& getVec3() const { assert(_type == Type::Vec3); return *reinterpret_cast<const glm::vec3*>(&_val); }
const glm::quat& getQuat() const { assert(_type == Type::Quat); return *reinterpret_cast<const glm::quat*>(&_val); }
const glm::mat4& getMat4() const { assert(_type == Type::Mat4); return *reinterpret_cast<const glm::mat4*>(&_val); }
const QString& getString() const { assert(_type == Type::String); return _stringVal; }
protected:
@ -112,7 +108,7 @@ public:
}
}
const glm::vec3& lookup(const QString& key, const glm::vec3& defaultValue) const {
const glm::vec3& lookupRaw(const QString& key, const glm::vec3& defaultValue) const {
if (key.isEmpty()) {
return defaultValue;
} else {
@ -121,7 +117,16 @@ public:
}
}
const glm::quat& lookup(const QString& key, const glm::quat& defaultValue) const {
glm::vec3 lookupRigToGeometry(const QString& key, const glm::vec3& defaultValue) const {
if (key.isEmpty()) {
return defaultValue;
} else {
auto iter = _map.find(key);
return iter != _map.end() ? transformPoint(_rigToGeometryMat, iter->second.getVec3()) : defaultValue;
}
}
const glm::quat& lookupRaw(const QString& key, const glm::quat& defaultValue) const {
if (key.isEmpty()) {
return defaultValue;
} else {
@ -130,12 +135,12 @@ public:
}
}
const glm::mat4& lookup(const QString& key, const glm::mat4& defaultValue) const {
glm::quat lookupRigToGeometry(const QString& key, const glm::quat& defaultValue) const {
if (key.isEmpty()) {
return defaultValue;
} else {
auto iter = _map.find(key);
return iter != _map.end() ? iter->second.getMat4() : defaultValue;
return iter != _map.end() ? _rigToGeometryRot * iter->second.getQuat() : defaultValue;
}
}
@ -153,13 +158,17 @@ public:
void set(const QString& key, float value) { _map[key] = AnimVariant(value); }
void set(const QString& key, const glm::vec3& value) { _map[key] = AnimVariant(value); }
void set(const QString& key, const glm::quat& value) { _map[key] = AnimVariant(value); }
void set(const QString& key, const glm::mat4& value) { _map[key] = AnimVariant(value); }
void set(const QString& key, const QString& value) { _map[key] = AnimVariant(value); }
void unset(const QString& key) { _map.erase(key); }
void setTrigger(const QString& key) { _triggers.insert(key); }
void clearTriggers() { _triggers.clear(); }
void setRigToGeometryTransform(const glm::mat4& rigToGeometry) {
_rigToGeometryMat = rigToGeometry;
_rigToGeometryRot = glmExtractRotation(rigToGeometry);
}
void clearMap() { _map.clear(); }
bool hasKey(const QString& key) const { return _map.find(key) != _map.end(); }
@ -189,9 +198,6 @@ public:
case AnimVariant::Type::Quat:
qCDebug(animation) << " " << pair.first << "=" << pair.second.getQuat();
break;
case AnimVariant::Type::Mat4:
qCDebug(animation) << " " << pair.first << "=" << pair.second.getMat4();
break;
case AnimVariant::Type::String:
qCDebug(animation) << " " << pair.first << "=" << pair.second.getString();
break;
@ -205,6 +211,8 @@ public:
protected:
std::map<QString, AnimVariant> _map;
std::set<QString> _triggers;
glm::mat4 _rigToGeometryMat;
glm::quat _rigToGeometryRot;
};
typedef std::function<void(QScriptValue)> AnimVariantResultHandler;

View file

@ -236,12 +236,17 @@ int Rig::getJointStateCount() const {
return _relativePoses.size();
}
int Rig::indexOfJoint(const QString& jointName) {
int Rig::indexOfJoint(const QString& jointName) const {
return _animSkeleton->nameToJointIndex(jointName);
}
void Rig::setModelOffset(const glm::mat4& modelOffset) {
_modelOffset = AnimPose(modelOffset);
// compute geometryToAvatarTransforms
glm::quat yFlip180 = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
_geometryToRigTransform = AnimPose(glm::vec3(1), yFlip180, glm::vec3()) * _modelOffset * _geometryOffset;
_rigToGeometryTransform = glm::inverse(_geometryToRigTransform);
}
bool Rig::getJointStateRotation(int index, glm::quat& rotation) const {
@ -322,9 +327,9 @@ void Rig::restoreJointTranslation(int index, float fraction, float priority) {
// AJT: NOTE old code did not have 180 flip!
bool Rig::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position, glm::vec3 translation, glm::quat rotation) const {
glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
if (jointIndex >= 0 && jointIndex < (int)_absolutePoses.size()) {
position = (rotation * yFlip * _absolutePoses[jointIndex].trans) + translation;
glm::quat yFlip180 = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
position = (rotation * yFlip180 * _absolutePoses[jointIndex].trans) + translation;
return true;
} else {
return false;
@ -333,9 +338,9 @@ bool Rig::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position, glm:
// AJT: NOTE old code did not have 180 flip!
bool Rig::getJointPosition(int jointIndex, glm::vec3& position) const {
glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
if (jointIndex >= 0 && jointIndex < (int)_absolutePoses.size()) {
position = yFlip * _absolutePoses[jointIndex].trans;
glm::quat yFlip180 = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
position = yFlip180 * _absolutePoses[jointIndex].trans;
return true;
} else {
return false;
@ -419,6 +424,14 @@ void Rig::computeEyesInRootFrame(const AnimPoseVec& poses) {
}
}
AnimPose Rig::getAbsoluteDefaultPose(int index) const {
if (_animSkeleton && index >= 0 && index < _animSkeleton->getNumJoints()) {
return AnimPose(_geometryToRigTransform) * _animSkeleton->getAbsoluteDefaultPose(index);
} else {
return AnimPose::identity;
}
}
// animation reference speeds.
static const std::vector<float> FORWARD_SPEEDS = { 0.4f, 1.4f, 4.5f }; // m/s
static const std::vector<float> BACKWARD_SPEEDS = { 0.6f, 1.45f }; // m/s
@ -682,13 +695,14 @@ void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) {
if (_animNode) {
updateAnimationStateHandlers();
_animVars.setRigToGeometryTransform(_rigToGeometryTransform);
// evaluate the animation
AnimNode::Triggers triggersOut;
_relativePoses = _animNode->evaluate(_animVars, deltaTime, triggersOut);
if ((int)_relativePoses.size() != _animSkeleton->getNumJoints()) {
// animations haven't fully loaded yet.
_relativePoses = _animSkeleton->getRelativeBindPoses();
_relativePoses = _animSkeleton->getRelativeDefaultPoses();
}
_animVars.clearTriggers();
for (auto& trigger : triggersOut) {
@ -781,27 +795,23 @@ void Rig::updateLeanJoint(int index, float leanSideways, float leanForward, floa
}
}
static void computeHeadNeckAnimVars(AnimSkeleton::ConstPointer skeleton, const AnimPose& geometryHMDPose,
glm::vec3& headPositionOut, glm::quat& headOrientationOut,
glm::vec3& neckPositionOut, glm::quat& neckOrientationOut) {
void Rig::computeHeadNeckAnimVars(const AnimPose& hmdPose, glm::vec3& headPositionOut, glm::quat& headOrientationOut,
glm::vec3& neckPositionOut, glm::quat& neckOrientationOut) const {
// the input hmd values are in avatar space
// we need to transform them into bone space.
AnimPose hmdPose = geometryHMDPose;
// the input hmd values are in avatar/rig space
const glm::vec3 hmdPosition = hmdPose.trans;
const glm::quat hmdOrientation = hmdPose.rot;
// TODO: cache jointIndices
int rightEyeIndex = skeleton->nameToJointIndex("RightEye");
int leftEyeIndex = skeleton->nameToJointIndex("LeftEye");
int headIndex = skeleton->nameToJointIndex("Head");
int neckIndex = skeleton->nameToJointIndex("Neck");
int rightEyeIndex = indexOfJoint("RightEye");
int leftEyeIndex = indexOfJoint("LeftEye");
int headIndex = indexOfJoint("Head");
int neckIndex = indexOfJoint("Neck");
// Use absolute bindPose positions just in case the relBindPose have rotations we don't expect.
glm::vec3 absRightEyePos = rightEyeIndex != -1 ? skeleton->getAbsoluteBindPose(rightEyeIndex).trans : DEFAULT_RIGHT_EYE_POS;
glm::vec3 absLeftEyePos = leftEyeIndex != -1 ? skeleton->getAbsoluteBindPose(leftEyeIndex).trans : DEFAULT_LEFT_EYE_POS;
glm::vec3 absHeadPos = headIndex != -1 ? skeleton->getAbsoluteBindPose(headIndex).trans : DEFAULT_HEAD_POS;
glm::vec3 absNeckPos = neckIndex != -1 ? skeleton->getAbsoluteBindPose(neckIndex).trans : DEFAULT_NECK_POS;
glm::vec3 absRightEyePos = rightEyeIndex != -1 ? getAbsoluteDefaultPose(rightEyeIndex).trans : DEFAULT_RIGHT_EYE_POS;
glm::vec3 absLeftEyePos = leftEyeIndex != -1 ? getAbsoluteDefaultPose(leftEyeIndex).trans : DEFAULT_LEFT_EYE_POS;
glm::vec3 absHeadPos = headIndex != -1 ? getAbsoluteDefaultPose(headIndex).trans : DEFAULT_HEAD_POS;
glm::vec3 absNeckPos = neckIndex != -1 ? getAbsoluteDefaultPose(neckIndex).trans : DEFAULT_NECK_POS;
glm::vec3 absCenterEyePos = (absRightEyePos + absLeftEyePos) / 2.0f;
glm::vec3 eyeOffset = absCenterEyePos - absHeadPos;
@ -816,18 +826,19 @@ static void computeHeadNeckAnimVars(AnimSkeleton::ConstPointer skeleton, const A
// neck
neckPositionOut = hmdPosition - hmdOrientation * (headOffset + eyeOffset);
// slerp between bind orientation and hmdOrientation
neckOrientationOut = safeMix(hmdOrientation, skeleton->getRelativeBindPose(skeleton->nameToJointIndex("Neck")).rot, 0.5f);
// slerp between default orientation and hmdOrientation
neckOrientationOut = safeMix(hmdOrientation, _animSkeleton->getRelativeDefaultPose(neckIndex).rot, 0.5f);
}
void Rig::updateNeckJoint(int index, const HeadParameters& params) {
if (_animSkeleton && index >= 0 && index < _animSkeleton->getNumJoints()) {
glm::quat yFlip180 = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
if (params.isInHMD) {
glm::vec3 headPos, neckPos;
glm::quat headRot, neckRot;
AnimPose hmdPose(glm::vec3(1.0f), avatarToGeometryNegZForward(params.localHeadOrientation), avatarToGeometry(params.localHeadPosition));
computeHeadNeckAnimVars(_animSkeleton, hmdPose, headPos, headRot, neckPos, neckRot);
AnimPose hmdPose(glm::vec3(1.0f), params.localHeadOrientation * yFlip180, params.localHeadPosition);
computeHeadNeckAnimVars(hmdPose, headPos, headRot, neckPos, neckRot);
// debug rendering
#ifdef DEBUG_RENDERING
@ -852,7 +863,7 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) {
} else {
_animVars.unset("headPosition");
_animVars.set("headRotation", avatarToGeometryNegZForward(params.localHeadOrientation));
_animVars.set("headRotation", params.localHeadOrientation * yFlip180);
_animVars.set("headAndNeckType", (int)IKTarget::Type::RotationOnly);
_animVars.set("headType", (int)IKTarget::Type::RotationOnly);
_animVars.unset("neckPosition");
@ -886,31 +897,12 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm
*/
}
glm::vec3 Rig::avatarToGeometry(const glm::vec3& pos) const {
glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
AnimPose geometryToAvatarTransform = AnimPose(glm::vec3(1), yFlip, glm::vec3()) * _modelOffset * _geometryOffset;
glm::vec3 result = geometryToAvatarTransform.inverse() * pos;
return result;
}
glm::quat Rig::avatarToGeometryNegZForward(const glm::quat& quat) const {
AnimPose yFlip(glm::vec3(1), glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)), glm::vec3());
AnimPose geometryToAvatarTransform = yFlip * _modelOffset * _geometryOffset;
return (geometryToAvatarTransform.inverse() * AnimPose(glm::vec3(1), quat, glm::vec3()) * yFlip).rot;
}
glm::quat Rig::avatarToGeometryZForward(const glm::quat& quat) const {
AnimPose yFlip(glm::vec3(1), glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)), glm::vec3());
AnimPose geometryToAvatarTransform = yFlip * _modelOffset * _geometryOffset;
return (geometryToAvatarTransform.inverse() * AnimPose(glm::vec3(1), quat, glm::vec3())).rot;
}
void Rig::updateFromHandParameters(const HandParameters& params, float dt) {
if (_animSkeleton && _animNode) {
if (params.isLeftEnabled) {
_animVars.set("leftHandPosition", avatarToGeometry(params.leftPosition));
_animVars.set("leftHandRotation", avatarToGeometryZForward(params.leftOrientation));
_animVars.set("leftHandPosition", params.leftPosition);
_animVars.set("leftHandRotation", params.leftOrientation);
_animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition);
} else {
_animVars.unset("leftHandPosition");
@ -918,8 +910,8 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) {
_animVars.set("leftHandType", (int)IKTarget::Type::HipsRelativeRotationAndPosition);
}
if (params.isRightEnabled) {
_animVars.set("rightHandPosition", avatarToGeometry(params.rightPosition));
_animVars.set("rightHandRotation", avatarToGeometryZForward(params.rightOrientation));
_animVars.set("rightHandPosition", params.rightPosition);
_animVars.set("rightHandRotation", params.rightOrientation);
_animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition);
} else {
_animVars.unset("rightHandPosition");
@ -986,7 +978,7 @@ void Rig::initAnimGraph(const QUrl& url) {
bool Rig::getModelRegistrationPoint(glm::vec3& modelRegistrationPointOut) const {
if (_animSkeleton && _rootJointIndex >= 0) {
modelRegistrationPointOut = _geometryOffset * -_animSkeleton->getAbsoluteBindPose(_rootJointIndex).trans;
modelRegistrationPointOut = _geometryOffset * -_animSkeleton->getAbsoluteDefaultPose(_rootJointIndex).trans;
return true;
} else {
return false;

View file

@ -85,10 +85,9 @@ public:
void reset(const FBXGeometry& geometry);
bool jointStatesEmpty();
int getJointStateCount() const;
int indexOfJoint(const QString& jointName);
int indexOfJoint(const QString& jointName) const;
void setModelOffset(const glm::mat4& modelOffset);
const AnimPose& getGeometryOffset() const { return _geometryOffset; }
bool getJointStateRotation(int index, glm::quat& rotation) const;
bool getJointStateTranslation(int index, glm::vec3& translation) const;
@ -146,6 +145,8 @@ public:
const glm::vec3& getEyesInRootFrame() const { return _eyesInRootFrame; }
AnimPose getAbsoluteDefaultPose(int index) const; // avatar space
void copyJointsIntoJointData(QVector<JointData>& jointDataVec) const;
void copyJointsFromJointData(const QVector<JointData>& jointDataVec);
@ -156,15 +157,13 @@ public:
void updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist);
void updateNeckJoint(int index, const HeadParameters& params);
void computeHeadNeckAnimVars(const AnimPose& hmdPose, glm::vec3& headPositionOut, glm::quat& headOrientationOut,
glm::vec3& neckPositionOut, glm::quat& neckOrientationOut) const;
void updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAt, const glm::vec3& saccade);
void calcAnimAlpha(float speed, const std::vector<float>& referenceSpeeds, float* alphaOut) const;
void computeEyesInRootFrame(const AnimPoseVec& poses);
glm::vec3 avatarToGeometry(const glm::vec3& pos) const;
glm::quat avatarToGeometryZForward(const glm::quat& quat) const;
glm::quat avatarToGeometryNegZForward(const glm::quat& quat) const;
AnimPose _modelOffset; // model to avatar space (without 180 flip)
AnimPose _geometryOffset; // geometry to model space (includes unit offset & fst offsets)
AnimPoseVec _relativePoses; // geometry space relative to parent.
@ -172,6 +171,9 @@ public:
AnimPoseVec _overridePoses; // geometry space relative to parent.
std::vector<bool> _overrideFlags;
glm::mat4 _geometryToRigTransform;
glm::mat4 _rigToGeometryTransform;
int _rootJointIndex { -1 };
int _leftHandJointIndex { -1 };

View file

@ -10,7 +10,7 @@
//
#include "GLMHelpers.h"
#include <glm/gtc/matrix_transform.hpp>
#include "NumericalConstants.h"
const vec3 Vectors::UNIT_X{ 1.0f, 0.0f, 0.0f };
@ -276,6 +276,18 @@ glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) {
0.5f * sqrtf(z2) * (upper[0][1] >= upper[1][0] ? 1.0f : -1.0f)));
}
glm::quat glmExtractRotation(const glm::mat4& matrix) {
glm::vec3 scale = extractScale(matrix);
float maxScale = std::max(std::max(scale.x, scale.y), scale.z);
if (maxScale > 1.01f || maxScale <= 0.99f) {
// quat_cast doesn't work so well with scaled matrices, so cancel it out.
glm::mat4 tmp = glm::scale(matrix, 1.0f / scale);
return glm::normalize(glm::quat_cast(tmp));
} else {
return glm::normalize(glm::quat_cast(matrix));
}
}
glm::vec3 extractScale(const glm::mat4& matrix) {
return glm::vec3(glm::length(matrix[0]), glm::length(matrix[1]), glm::length(matrix[2]));
}

View file

@ -131,6 +131,7 @@ glm::vec3 extractTranslation(const glm::mat4& matrix);
void setTranslation(glm::mat4& matrix, const glm::vec3& translation);
glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal = false);
glm::quat glmExtractRotation(const glm::mat4& matrix);
glm::vec3 extractScale(const glm::mat4& matrix);