mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 16:33:33 +02:00
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:
parent
4f8cd6930d
commit
54408a9c87
10 changed files with 102 additions and 101 deletions
interface/src/avatar
libraries
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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]));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue