Removed JointStates! You won't be missed.

This commit is contained in:
Anthony J. Thibault 2015-11-20 14:15:37 -08:00
parent a4116e633a
commit a77ea8da43
17 changed files with 180 additions and 1182 deletions

View file

@ -246,7 +246,7 @@ bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) {
const float HEAD_SPHERE_RADIUS = 0.1f;
glm::vec3 theirLookAt = dynamic_pointer_cast<Avatar>(avatar)->getHead()->getLookAtPosition();
glm::vec3 myEyePosition = getHead()->getEyePosition();
return glm::distance(theirLookAt, myEyePosition) <= (HEAD_SPHERE_RADIUS * getScale());
}
@ -496,8 +496,8 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
eyeDiameter = DEFAULT_EYE_DIAMETER;
}
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphereInstance(batch,
Transform(transform).postScale(eyeDiameter * _scale / 2.0f + RADIUS_INCREMENT),
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphereInstance(batch,
Transform(transform).postScale(eyeDiameter * _scale / 2.0f + RADIUS_INCREMENT),
glm::vec4(LOOKING_AT_ME_COLOR, alpha));
position = getHead()->getRightEyePosition();
@ -507,7 +507,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
eyeDiameter = DEFAULT_EYE_DIAMETER;
}
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphereInstance(batch,
Transform(transform).postScale(eyeDiameter * _scale / 2.0f + RADIUS_INCREMENT),
Transform(transform).postScale(eyeDiameter * _scale / 2.0f + RADIUS_INCREMENT),
glm::vec4(LOOKING_AT_ME_COLOR, alpha));
}
@ -555,7 +555,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
if (!isMyAvatar() || cameraMode != CAMERA_MODE_FIRST_PERSON) {
auto& frustum = *renderArgs->_viewFrustum;
auto textPosition = getDisplayNamePosition();
if (frustum.pointInFrustum(textPosition, true) == ViewFrustum::INSIDE) {
renderDisplayName(batch, frustum, textPosition);
}
@ -611,7 +611,7 @@ void Avatar::fixupModelsInScene() {
void Avatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel) {
fixupModelsInScene();
{
if (_shouldRenderBillboard || !(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) {
// render the billboard until both models are loaded
@ -675,7 +675,7 @@ void Avatar::renderBillboard(RenderArgs* renderArgs) {
glm::quat rotation = getOrientation();
glm::vec3 cameraVector = glm::inverse(rotation) * (qApp->getCamera()->getPosition() - _position);
rotation = rotation * glm::angleAxis(atan2f(-cameraVector.x, -cameraVector.z), glm::vec3(0.0f, 1.0f, 0.0f));
// compute the size from the billboard camera parameters and scale
float size = getBillboardSize();
@ -688,7 +688,7 @@ void Avatar::renderBillboard(RenderArgs* renderArgs) {
glm::vec2 bottomRight(1.0f, 1.0f);
glm::vec2 texCoordTopLeft(0.0f, 0.0f);
glm::vec2 texCoordBottomRight(1.0f, 1.0f);
gpu::Batch& batch = *renderArgs->_batch;
PROFILE_RANGE_BATCH(batch, __FUNCTION__);
batch.setResourceTexture(0, _billboardTexture->getGPUTexture());
@ -721,29 +721,29 @@ glm::vec3 Avatar::getDisplayNamePosition() const {
glm::vec3 namePosition(0.0f);
glm::vec3 bodyUpDirection = getBodyUpDirection();
DEBUG_VALUE("bodyUpDirection =", bodyUpDirection);
if (getSkeletonModel().getNeckPosition(namePosition)) {
float headHeight = getHeadHeight();
DEBUG_VALUE("namePosition =", namePosition);
DEBUG_VALUE("headHeight =", headHeight);
static const float SLIGHTLY_ABOVE = 1.1f;
namePosition += bodyUpDirection * headHeight * SLIGHTLY_ABOVE;
} else {
const float HEAD_PROPORTION = 0.75f;
float billboardSize = getBillboardSize();
DEBUG_VALUE("_position =", _position);
DEBUG_VALUE("billboardSize =", billboardSize);
namePosition = _position + bodyUpDirection * (billboardSize * HEAD_PROPORTION);
}
if (glm::any(glm::isnan(namePosition)) || glm::any(glm::isinf(namePosition))) {
qCWarning(interfaceapp) << "Invalid display name position" << namePosition
<< ", setting is to (0.0f, 0.5f, 0.0f)";
namePosition = glm::vec3(0.0f, 0.5f, 0.0f);
}
return namePosition;
}
@ -751,16 +751,16 @@ Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& frustum, cons
Q_ASSERT_X(frustum.pointInFrustum(textPosition, true) == ViewFrustum::INSIDE,
"Avatar::calculateDisplayNameTransform", "Text not in viewfrustum.");
glm::vec3 toFrustum = frustum.getPosition() - textPosition;
// Compute orientation
// If x and z are 0, atan(x, z) adais undefined, so default to 0 degrees
const float yawRotation = (toFrustum.x == 0.0f && toFrustum.z == 0.0f) ? 0.0f : glm::atan(toFrustum.x, toFrustum.z);
glm::quat orientation = glm::quat(glm::vec3(0.0f, yawRotation, 0.0f));
// Compute correct scale to apply
static const float DESIRED_HEIGHT_RAD = glm::radians(1.5f);
float scale = glm::length(toFrustum) * glm::tan(DESIRED_HEIGHT_RAD);
// Set transform
Transform result;
result.setTranslation(textPosition);
@ -768,7 +768,7 @@ Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& frustum, cons
result.setScale(scale);
// raise by half the scale up so that textPosition be the bottom
result.postTranslate(Vectors::UP / 2.0f);
return result;
}
@ -796,14 +796,14 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, co
}
renderedDisplayName += statsFormat.arg(QString::number(kilobitsPerSecond, 'f', 2)).arg(getReceiveRate());
}
// Compute display name extent/position offset
const glm::vec2 extent = renderer->computeExtent(renderedDisplayName);
if (!glm::any(glm::isCompNull(extent, EPSILON))) {
const QRect nameDynamicRect = QRect(0, 0, (int)extent.x, (int)extent.y);
const int text_x = -nameDynamicRect.width() / 2;
const int text_y = -nameDynamicRect.height() / 2;
// Compute background position/size
static const float SLIGHTLY_IN_FRONT = 0.1f;
static const float BORDER_RELATIVE_SIZE = 0.1f;
@ -814,12 +814,12 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, co
const int width = nameDynamicRect.width() + 2.0f * border;
const int height = nameDynamicRect.height() + 2.0f * border;
const int bevelDistance = BEVEL_FACTOR * height;
// Display name and background colors
glm::vec4 textColor(0.93f, 0.93f, 0.93f, _displayNameAlpha);
glm::vec4 backgroundColor(0.2f, 0.2f, 0.2f,
(_displayNameAlpha / DISPLAYNAME_ALPHA) * DISPLAYNAME_BACKGROUND_ALPHA);
// Compute display name transform
auto textTransform = calculateDisplayNameTransform(frustum, textPosition);
// Test on extent above insures abs(height) > 0.0f
@ -835,7 +835,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, co
// Render actual name
QByteArray nameUTF8 = renderedDisplayName.toLocal8Bit();
// Render text slightly in front to avoid z-fighting
textTransform.postTranslate(glm::vec3(0.0f, 0.0f, SLIGHTLY_IN_FRONT * renderer->getFontSize()));
batch.setModelTransform(textTransform);
@ -937,52 +937,6 @@ glm::vec3 Avatar::getJointPosition(const QString& name) const {
return position;
}
glm::quat Avatar::getJointCombinedRotation(int index) const {
if (QThread::currentThread() != thread()) {
glm::quat rotation;
QMetaObject::invokeMethod(const_cast<Avatar*>(this), "getJointCombinedRotation", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(glm::quat, rotation), Q_ARG(const int, index));
return rotation;
}
glm::quat rotation;
_skeletonModel.getJointCombinedRotation(index, rotation);
return rotation;
}
glm::quat Avatar::getJointCombinedRotation(const QString& name) const {
if (QThread::currentThread() != thread()) {
glm::quat rotation;
QMetaObject::invokeMethod(const_cast<Avatar*>(this), "getJointCombinedRotation", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(glm::quat, rotation), Q_ARG(const QString&, name));
return rotation;
}
glm::quat rotation;
_skeletonModel.getJointCombinedRotation(getJointIndex(name), rotation);
return rotation;
}
const float SCRIPT_PRIORITY = DEFAULT_PRIORITY + 1.0f;
void Avatar::setJointModelPositionAndOrientation(int index, glm::vec3 position, const glm::quat& rotation) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(const_cast<Avatar*>(this), "setJointModelPositionAndOrientation",
Qt::AutoConnection, Q_ARG(const int, index), Q_ARG(const glm::vec3, position),
Q_ARG(const glm::quat&, rotation));
} else {
_skeletonModel.inverseKinematics(index, position, rotation, SCRIPT_PRIORITY);
}
}
void Avatar::setJointModelPositionAndOrientation(const QString& name, glm::vec3 position, const glm::quat& rotation) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(const_cast<Avatar*>(this), "setJointModelPositionAndOrientation",
Qt::AutoConnection, Q_ARG(const QString&, name), Q_ARG(const glm::vec3, position),
Q_ARG(const glm::quat&, rotation));
} else {
_skeletonModel.inverseKinematics(getJointIndex(name), position, rotation, SCRIPT_PRIORITY);
}
}
void Avatar::scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const {
//Scale a world space vector as if it was relative to the position
positionToScale = _position + _scale * (positionToScale - _position);

View file

@ -66,7 +66,7 @@ public:
typedef render::Payload<AvatarData> Payload;
typedef std::shared_ptr<render::Item::PayloadInterface> PayloadPointer;
void init();
void simulate(float deltaTime);
@ -101,20 +101,20 @@ public:
float getLODDistance() const;
virtual bool isMyAvatar() const { return false; }
virtual QVector<glm::quat> getJointRotations() const;
virtual glm::quat getJointRotation(int index) const;
virtual glm::vec3 getJointTranslation(int index) const;
virtual int getJointIndex(const QString& name) const;
virtual QStringList getJointNames() const;
virtual void setFaceModelURL(const QUrl& faceModelURL);
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData);
virtual void setBillboard(const QByteArray& billboard);
void setShowDisplayName(bool showDisplayName);
virtual int parseDataFromBuffer(const QByteArray& buffer);
static void renderJointConnectingCone( gpu::Batch& batch, glm::vec3 position1, glm::vec3 position2,
@ -125,16 +125,9 @@ public:
Q_INVOKABLE void setSkeletonOffset(const glm::vec3& offset);
Q_INVOKABLE glm::vec3 getSkeletonOffset() { return _skeletonOffset; }
virtual glm::vec3 getSkeletonPosition() const;
Q_INVOKABLE glm::vec3 getJointPosition(int index) const;
Q_INVOKABLE glm::vec3 getJointPosition(const QString& name) const;
Q_INVOKABLE glm::quat getJointCombinedRotation(int index) const;
Q_INVOKABLE glm::quat getJointCombinedRotation(const QString& name) const;
Q_INVOKABLE void setJointModelPositionAndOrientation(int index, const glm::vec3 position, const glm::quat& rotation);
Q_INVOKABLE void setJointModelPositionAndOrientation(const QString& name, const glm::vec3 position,
const glm::quat& rotation);
Q_INVOKABLE glm::vec3 getNeckPosition() const;
Q_INVOKABLE glm::vec3 getAcceleration() const { return _acceleration; }
@ -195,9 +188,9 @@ protected:
glm::vec3 _worldUpDirection;
float _stringLength;
bool _moving; ///< set when position is changing
bool isLookingAtMe(AvatarSharedPointer avatar);
// protected methods...
glm::vec3 getBodyRightDirection() const { return getOrientation() * IDENTITY_RIGHT; }
glm::vec3 getBodyUpDirection() const { return getOrientation() * IDENTITY_UP; }

View file

@ -897,8 +897,8 @@ glm::vec3 MyAvatar::getDefaultEyePosition() const {
return getPosition() + getWorldAlignedOrientation() * _skeletonModel.getDefaultEyeModelPosition();
}
const float SCRIPT_PRIORITY = DEFAULT_PRIORITY + 1.0f;
const float RECORDER_PRIORITY = SCRIPT_PRIORITY + 1.0f;
const float SCRIPT_PRIORITY = 1.0f + 1.0f;
const float RECORDER_PRIORITY = 1.0f + 1.0f;
void MyAvatar::setJointRotations(QVector<glm::quat> jointRotations) {
int numStates = glm::min(_skeletonModel.getJointStateCount(), jointRotations.size());

View file

@ -44,23 +44,7 @@ void SkeletonModel::initJointStates() {
const FBXGeometry& geometry = _geometry->getFBXGeometry();
glm::mat4 geometryOffset = geometry.offset;
glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset);
int rootJointIndex = geometry.rootJointIndex;
int leftHandJointIndex = geometry.leftHandJointIndex;
int leftElbowJointIndex = leftHandJointIndex >= 0 ? geometry.joints.at(leftHandJointIndex).parentIndex : -1;
int leftShoulderJointIndex = leftElbowJointIndex >= 0 ? geometry.joints.at(leftElbowJointIndex).parentIndex : -1;
int rightHandJointIndex = geometry.rightHandJointIndex;
int rightElbowJointIndex = rightHandJointIndex >= 0 ? geometry.joints.at(rightHandJointIndex).parentIndex : -1;
int rightShoulderJointIndex = rightElbowJointIndex >= 0 ? geometry.joints.at(rightElbowJointIndex).parentIndex : -1;
_rig->initJointStates(geometry, modelOffset,
rootJointIndex,
leftHandJointIndex,
leftElbowJointIndex,
leftShoulderJointIndex,
rightHandJointIndex,
rightElbowJointIndex,
rightShoulderJointIndex);
_rig->initJointStates(geometry, modelOffset);
// Determine the default eye position for avatar scale = 1.0
int headJointIndex = _geometry->getFBXGeometry().headJointIndex;
@ -100,7 +84,6 @@ void SkeletonModel::initJointStates() {
emit skeletonLoaded();
}
const float PALM_PRIORITY = DEFAULT_PRIORITY;
// Called within Model::simulate call, below.
void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
Head* head = _owningAvatar->getHead();

View file

@ -23,13 +23,6 @@ AnimSkeleton::AnimSkeleton(const FBXGeometry& fbxGeometry) {
for (auto& joint : fbxGeometry.joints) {
joints.push_back(joint);
}
// AJT: REMOVE
/*
AnimPose geometryOffset(fbxGeometry.offset);
buildSkeletonFromJoints(joints, geometryOffset);
*/
buildSkeletonFromJoints(joints);
}
@ -147,37 +140,8 @@ void AnimSkeleton::buildSkeletonFromJoints(const std::vector<FBXJoint>& joints)
}
}
}
// AJT: REMOVE
/*
// now we want to normalize scale from geometryOffset to all poses.
// This will ensure our bone translations will be in meters, even if the model was authored with some other unit of mesure.
normalizeScale(geometryOffset, _relativeBindPoses, _absoluteBindPoses);
normalizeScale(geometryOffset, _relativeDefaultPoses, _absoluteDefaultPoses);
*/
}
/*
// AJT: REMOVE
void AnimSkeleton::normalizeScale(const AnimPose& geometryOffset, AnimPoseVec& relPoses, AnimPoseVec& absPoses) const {
for (auto& absPose : absPoses) {
absPose.trans = (geometryOffset * absPose).trans;
}
// re-compute relative poses based on the modified absolute poses.
for (size_t i = 0; i < relPoses.size(); i++) {
int parentIndex = getParentIndex(i);
if (parentIndex >= 0) {
relPoses[i] = absPoses[parentIndex].inverse() * absPoses[i];
} else {
relPoses[i] = absPoses[i];
}
}
}
*/
#define DUMP_FBX_JOINTS
#ifndef NDEBUG
void AnimSkeleton::dump() const {
qCDebug(animation) << "[";

View file

@ -55,8 +55,6 @@ public:
protected:
void buildSkeletonFromJoints(const std::vector<FBXJoint>& joints);
// AJT: REMOVE
//void normalizeScale(const AnimPose& geometryOffset, AnimPoseVec& relPoses, AnimPoseVec& absPoses) const;
std::vector<FBXJoint> _joints;
AnimPoseVec _absoluteBindPoses;

View file

@ -11,86 +11,7 @@
#include "AvatarRig.h"
// AJT: REMOVE, this should no longer be used
void AvatarRig::setHandPosition(int jointIndex,
const glm::vec3& position, const glm::quat& rotation,
float scale, float priority) {
bool rightHand = (jointIndex == _rightHandJointIndex);
int elbowJointIndex = rightHand ? _rightElbowJointIndex : _leftElbowJointIndex;
int shoulderJointIndex = rightHand ? _rightShoulderJointIndex : _leftShoulderJointIndex;
// this algorithm is from sample code from sixense
if (elbowJointIndex == -1 || shoulderJointIndex == -1) {
return;
}
glm::vec3 shoulderPosition;
if (!getJointPosition(shoulderJointIndex, shoulderPosition)) {
return;
}
// precomputed lengths
float upperArmLength = _jointStates[elbowJointIndex].getDistanceToParent() * scale;
float lowerArmLength = _jointStates[jointIndex].getDistanceToParent() * scale;
// first set wrist position
glm::vec3 wristPosition = position;
glm::vec3 shoulderToWrist = wristPosition - shoulderPosition;
float distanceToWrist = glm::length(shoulderToWrist);
// prevent gimbal lock
if (distanceToWrist > upperArmLength + lowerArmLength - EPSILON) {
distanceToWrist = upperArmLength + lowerArmLength - EPSILON;
shoulderToWrist = glm::normalize(shoulderToWrist) * distanceToWrist;
wristPosition = shoulderPosition + shoulderToWrist;
}
// cosine of angle from upper arm to hand vector
float cosA = (upperArmLength * upperArmLength + distanceToWrist * distanceToWrist - lowerArmLength * lowerArmLength) /
(2 * upperArmLength * distanceToWrist);
float mid = upperArmLength * cosA;
float height = sqrt(upperArmLength * upperArmLength + mid * mid - 2 * upperArmLength * mid * cosA);
// direction of the elbow
glm::vec3 handNormal = glm::cross(rotation * glm::vec3(0.0f, 1.0f, 0.0f), shoulderToWrist); // elbow rotating with wrist
glm::vec3 relaxedNormal = glm::cross(glm::vec3(0.0f, 1.0f, 0.0f), shoulderToWrist); // elbow pointing straight down
const float NORMAL_WEIGHT = 0.5f;
glm::vec3 finalNormal = glm::mix(relaxedNormal, handNormal, NORMAL_WEIGHT);
if (rightHand ? (finalNormal.y > 0.0f) : (finalNormal.y < 0.0f)) {
finalNormal.y = 0.0f; // dont allow elbows to point inward (y is vertical axis)
}
glm::vec3 tangent = glm::normalize(glm::cross(shoulderToWrist, finalNormal));
// ik solution
glm::vec3 elbowPosition = shoulderPosition + glm::normalize(shoulderToWrist) * mid - tangent * height;
glm::vec3 forwardVector(rightHand ? -1.0f : 1.0f, 0.0f, 0.0f);
glm::quat shoulderRotation = rotationBetween(forwardVector, elbowPosition - shoulderPosition);
setJointRotationInBindFrame(shoulderJointIndex, shoulderRotation, priority);
setJointRotationInBindFrame(elbowJointIndex,
rotationBetween(shoulderRotation * forwardVector, wristPosition - elbowPosition) *
shoulderRotation, priority);
setJointRotationInBindFrame(jointIndex, rotation, priority);
}
void AvatarRig::setJointTranslation(int index, bool valid, const glm::vec3& translation, float priority) {
// AJT: LEGACY
{
if (index != -1 && index < _jointStates.size()) {
JointState& state = _jointStates[index];
if (valid) {
state.setTranslation(translation, priority);
} else {
state.restoreTranslation(1.0f, priority);
}
}
}
if (index >= 0 && index < (int)_overrideFlags.size()) {
if (valid) {
assert(_overrideFlags.size() == _overridePoses.size());
@ -100,23 +21,7 @@ void AvatarRig::setJointTranslation(int index, bool valid, const glm::vec3& tran
}
}
void AvatarRig::setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation, float priority) {
// AJT: LEGACY
{
if (index != -1 && index < _jointStates.size()) {
JointState& state = _jointStates[index];
if (valid) {
state.setRotationInConstrainedFrame(rotation, priority);
state.setTranslation(translation, priority);
} else {
state.restoreRotation(1.0f, priority);
state.restoreTranslation(1.0f, priority);
}
}
}
if (index >= 0 && index < (int)_overrideFlags.size()) {
assert(_overrideFlags.size() == _overridePoses.size());
_overrideFlags[index] = true;

View file

@ -21,8 +21,6 @@ class AvatarRig : public Rig {
public:
~AvatarRig() {}
virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation,
float scale, float priority);
virtual void setJointTranslation(int index, bool valid, const glm::vec3& translation, float priority);
virtual void setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation, float priority);
};

View file

@ -12,20 +12,6 @@
#include "EntityRig.h"
void EntityRig::setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation, float priority) {
// AJT: LEGACY
{
if (index != -1 && index < _jointStates.size()) {
JointState& state = _jointStates[index];
if (valid) {
state.setRotationInConstrainedFrame(rotation, priority);
// state.setTranslation(translation, priority);
} else {
state.restoreRotation(1.0f, priority);
// state.restoreTranslation(1.0f, priority);
}
}
}
if (index >= 0 && index < (int)_overrideFlags.size()) {
assert(_overrideFlags.size() == _overridePoses.size());
_overrideFlags[index] = true;

View file

@ -21,8 +21,6 @@ class EntityRig : public Rig {
public:
~EntityRig() {}
virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation,
float scale, float priority) {}
virtual void setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation, float priority);
};

View file

@ -1,228 +0,0 @@
//
// JointState.cpp
// libraries/animation/src/
//
// Created by Andrzej Kapolka on 10/18/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <glm/gtx/norm.hpp>
#include <QThreadPool>
#include <SharedUtil.h>
#include "JointState.h"
JointState::~JointState() {
}
void JointState::copyState(const JointState& other) {
_transformChanged = other._transformChanged;
_transform = other._transform;
_rotationIsValid = other._rotationIsValid;
_rotation = other._rotation;
_rotationInConstrainedFrame = other._rotationInConstrainedFrame;
_positionInParentFrame = other._positionInParentFrame;
_distanceToParent = other._distanceToParent;
_animationPriority = other._animationPriority;
_name = other._name;
_isFree = other._isFree;
_parentIndex = other._parentIndex;
_defaultRotation = other._defaultRotation;
_defaultTranslation = other._defaultTranslation;
_inverseDefaultRotation = other._inverseDefaultRotation;
_translation = other._translation;
_preRotation = other._preRotation;
_postRotation = other._postRotation;
_preTransform = other._preTransform;
_postTransform = other._postTransform;
_inverseBindRotation = other._inverseBindRotation;
}
JointState::JointState(const FBXJoint& joint) {
_rotationInConstrainedFrame = joint.rotation;
_name = joint.name;
_isFree = joint.isFree;
_parentIndex = joint.parentIndex;
_translation = joint.translation;
_defaultRotation = joint.rotation;
_defaultTranslation = _translation;
_inverseDefaultRotation = joint.inverseDefaultRotation;
_preRotation = joint.preRotation;
_postRotation = joint.postRotation;
_preTransform = joint.preTransform;
_postTransform = joint.postTransform;
_inverseBindRotation = joint.inverseBindRotation;
}
void JointState::buildConstraint() {
}
glm::quat JointState::getRotation() const {
if (!_rotationIsValid) {
const_cast<JointState*>(this)->_rotation = extractRotation(_transform);
const_cast<JointState*>(this)->_rotationIsValid = true;
}
return _rotation;
}
void JointState::initTransform(const glm::mat4& parentTransform) {
//_unitsScale = extractScale(parentTransform);
computeTransform(parentTransform);
_positionInParentFrame = glm::inverse(extractRotation(parentTransform)) * (extractTranslation(_transform) - extractTranslation(parentTransform));
_distanceToParent = glm::length(_positionInParentFrame);
}
void JointState::computeTransform(const glm::mat4& parentTransform, bool parentTransformChanged, bool synchronousRotationCompute) {
if (!parentTransformChanged && !_transformChanged) {
return;
}
glm::quat rotationInParentFrame = _preRotation * _rotationInConstrainedFrame * _postRotation;
glm::mat4 transformInParentFrame = _preTransform * glm::mat4_cast(rotationInParentFrame) * _postTransform;
glm::mat4 newTransform = parentTransform * glm::translate(_translation) * transformInParentFrame;
if (newTransform != _transform) {
_transform = newTransform;
_transformChanged = true;
_rotationIsValid = false;
}
}
glm::quat JointState::getRotationInBindFrame() const {
return getRotation() * _inverseBindRotation;
}
glm::quat JointState::getRotationInParentFrame() const {
return _preRotation * _rotationInConstrainedFrame * _postRotation;
}
void JointState::restoreRotation(float fraction, float priority) {
if (priority == _animationPriority || _animationPriority == 0.0f) {
setRotationInConstrainedFrameInternal(safeMix(_rotationInConstrainedFrame, _defaultRotation, fraction));
_animationPriority = 0.0f;
}
}
void JointState::restoreTranslation(float fraction, float priority) {
if (priority == _animationPriority || _animationPriority == 0.0f) {
_translation = _translation * (1.0f - fraction) + _defaultTranslation * fraction;
_animationPriority = 0.0f;
}
}
void JointState::setRotationInBindFrame(const glm::quat& rotation, float priority) {
// rotation is from bind- to model-frame
if (priority >= _animationPriority) {
glm::quat targetRotation = _rotationInConstrainedFrame * glm::inverse(getRotation()) * rotation * glm::inverse(_inverseBindRotation);
setRotationInConstrainedFrameInternal(targetRotation);
_animationPriority = priority;
}
}
void JointState::setRotationInModelFrame(const glm::quat& rotationInModelFrame, float priority) {
// rotation is from bind- to model-frame
if (priority >= _animationPriority) {
glm::quat parentRotation = computeParentRotation();
// R = Rp * Rpre * r * Rpost
// R' = Rp * Rpre * r' * Rpost
// r' = (Rp * Rpre)^ * R' * Rpost^
glm::quat targetRotation = glm::inverse(parentRotation * _preRotation) * rotationInModelFrame * glm::inverse(_postRotation);
_rotationInConstrainedFrame = glm::normalize(targetRotation);
_transformChanged = true;
_animationPriority = priority;
}
}
void JointState::clearTransformTranslation() {
_transform[3][0] = 0.0f;
_transform[3][1] = 0.0f;
_transform[3][2] = 0.0f;
_transformChanged = true;
}
void JointState::applyRotationDelta(const glm::quat& delta, float priority) {
// NOTE: delta is in model-frame
if (priority < _animationPriority || delta == glm::quat()) {
return;
}
_animationPriority = priority;
glm::quat targetRotation = _rotationInConstrainedFrame * glm::inverse(getRotation()) * delta * getRotation();
setRotationInConstrainedFrameInternal(targetRotation);
}
/// Applies delta rotation to joint but mixes a little bit of the default pose as well.
/// This helps keep an IK solution stable.
void JointState::mixRotationDelta(const glm::quat& delta, float mixFactor, float priority) {
// NOTE: delta is in model-frame
if (priority < _animationPriority) {
return;
}
_animationPriority = priority;
glm::quat targetRotation = _rotationInConstrainedFrame * glm::inverse(getRotation()) * delta * getRotation();
if (mixFactor > 0.0f && mixFactor <= 1.0f) {
targetRotation = safeMix(targetRotation, _defaultRotation, mixFactor);
}
setRotationInConstrainedFrameInternal(targetRotation);
}
glm::quat JointState::computeParentRotation() const {
// R = Rp * Rpre * r * Rpost
// Rp = R * (Rpre * r * Rpost)^
return getRotation() * glm::inverse(_preRotation * _rotationInConstrainedFrame * _postRotation);
}
void JointState::setRotationInConstrainedFrame(glm::quat targetRotation, float priority, float mix) {
if (priority >= _animationPriority || _animationPriority == 0.0f) {
auto rotation = (mix == 1.0f) ? targetRotation : safeMix(getRotationInConstrainedFrame(), targetRotation, mix);
setRotationInConstrainedFrameInternal(rotation);
_animationPriority = priority;
}
}
void JointState::setTranslation(const glm::vec3& translation, float priority) {
if (priority >= _animationPriority || _animationPriority == 0.0f) {
_translation = translation / _unitsScale;
_transformChanged = true;
_animationPriority = priority;
}
}
void JointState::setRotationInConstrainedFrameInternal(const glm::quat& targetRotation) {
if (_rotationInConstrainedFrame != targetRotation) {
glm::quat parentRotation = computeParentRotation();
_rotationInConstrainedFrame = targetRotation;
_transformChanged = true;
// R' = Rp * Rpre * r' * Rpost
_rotation = parentRotation * _preRotation * _rotationInConstrainedFrame * _postRotation;
}
}
bool JointState::rotationIsDefault(const glm::quat& rotation, float tolerance) const {
glm::quat defaultRotation = _defaultRotation;
return glm::abs(rotation.x - defaultRotation.x) < tolerance &&
glm::abs(rotation.y - defaultRotation.y) < tolerance &&
glm::abs(rotation.z - defaultRotation.z) < tolerance &&
glm::abs(rotation.w - defaultRotation.w) < tolerance;
}
bool JointState::translationIsDefault(const glm::vec3& translation, float tolerance) const {
return glm::distance(_defaultTranslation * _unitsScale, translation) < tolerance;
}
glm::quat JointState::getDefaultRotationInParentFrame() const {
// NOTE: the result is constant and could be cached
return _preRotation * _defaultRotation * _postRotation;
}
glm::vec3 JointState::getDefaultTranslationInConstrainedFrame() const {
return _defaultTranslation * _unitsScale;
}

View file

@ -1,148 +0,0 @@
//
// JointState.h
// libraries/animation/src/
//
// Created by Andrzej Kapolka on 10/18/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_JointState_h
#define hifi_JointState_h
#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>
#include <glm/gtx/transform.hpp>
#include <FBXReader.h>
#include <GLMHelpers.h>
#include <NumericalConstants.h>
const float DEFAULT_PRIORITY = 3.0f;
class JointState {
public:
JointState() {}
JointState(const JointState& other) { copyState(other); }
JointState(const FBXJoint& joint);
~JointState();
JointState& operator=(const JointState& other) { copyState(other); return *this; }
void copyState(const JointState& state);
void buildConstraint();
void initTransform(const glm::mat4& parentTransform);
// if synchronousRotationCompute is true, then _transform is still computed synchronously,
// but _rotation will be asynchronously extracted
void computeTransform(const glm::mat4& parentTransform, bool parentTransformChanged = true, bool synchronousRotationCompute = false);
const glm::mat4& getTransform() const { return _transform; }
void resetTransformChanged() { _transformChanged = false; }
bool getTransformChanged() const { return _transformChanged; }
glm::quat getRotation() const;
glm::vec3 getPosition() const { return extractTranslation(_transform); }
/// \return rotation from bind to model frame
glm::quat getRotationInBindFrame() const;
glm::quat getRotationInParentFrame() const;
const glm::vec3& getPositionInParentFrame() const { return _positionInParentFrame; }
float getDistanceToParent() const { return _distanceToParent; }
int getParentIndex() const { return _parentIndex; }
/// \param delta is in the model-frame
void applyRotationDelta(const glm::quat& delta, float priority = 1.0f);
/// Applies delta rotation to joint but mixes a little bit of the default pose as well.
/// This helps keep an IK solution stable.
/// \param delta rotation change in model-frame
/// \param mixFactor fraction in range [0,1] of how much default pose to blend in (0 is none, 1 is all)
/// \param priority priority level of this animation blend
void mixRotationDelta(const glm::quat& delta, float mixFactor, float priority = 1.0f);
/// Blends a fraciton of default pose into joint rotation.
/// \param fraction fraction in range [0,1] of how much default pose to blend in (0 is none, 1 is all)
/// \param priority priority level of this animation blend
void restoreRotation(float fraction, float priority);
void restoreTranslation(float fraction, float priority);
/// \param rotation is from bind- to model-frame
/// computes and sets new _rotationInConstrainedFrame
/// NOTE: the JointState's model-frame transform/rotation are NOT updated!
void setRotationInBindFrame(const glm::quat& rotation, float priority);
/// \param rotationInModelRame is in model-frame
/// computes and sets new _rotationInConstrainedFrame to match rotationInModelFrame
/// NOTE: the JointState's model-frame transform/rotation are NOT updated!
void setRotationInModelFrame(const glm::quat& rotationInModelFrame, float priority);
void setTranslation(const glm::vec3& translation, float priority);
void setRotationInConstrainedFrame(glm::quat targetRotation, float priority, float mix = 1.0f);
const glm::quat& getRotationInConstrainedFrame() const { return _rotationInConstrainedFrame; }
bool rotationIsDefault(const glm::quat& rotation, float tolerance = EPSILON) const;
bool translationIsDefault(const glm::vec3& translation, float tolerance = EPSILON) const;
glm::quat getDefaultRotationInParentFrame() const;
glm::vec3 getDefaultTranslationInConstrainedFrame() const;
void clearTransformTranslation();
/// \return parent model-frame rotation
// (used to keep _rotation consistent when modifying _rotationInWorldFrame directly)
glm::quat computeParentRotation() const;
void setTransform(const glm::mat4& transform) { _transform = transform; }
glm::vec3 getTranslation() const { return _translation * _unitsScale; }
const glm::mat4& getPreTransform() const { return _preTransform; }
const glm::mat4& getPostTransform() const { return _postTransform; }
const glm::quat& getPreRotation() const { return _preRotation; }
const glm::quat& getPostRotation() const { return _postRotation; }
const glm::quat& getDefaultRotation() const { return _defaultRotation; }
glm::vec3 getDefaultTranslation() const { return _defaultTranslation * _unitsScale; }
const glm::quat& getInverseDefaultRotation() const { return _inverseDefaultRotation; }
const QString& getName() const { return _name; }
bool getIsFree() const { return _isFree; }
float getAnimationPriority() const { return _animationPriority; }
void setAnimationPriority(float priority) { _animationPriority = priority; }
private:
void setRotationInConstrainedFrameInternal(const glm::quat& targetRotation);
/// debug helper function
void loadBindRotation();
bool _transformChanged {true};
bool _rotationIsValid {false};
glm::vec3 _positionInParentFrame {0.0f}; // only changes when the Model is scaled
float _animationPriority {0.0f}; // the priority of the animation affecting this joint
float _distanceToParent {0.0f};
glm::mat4 _transform; // joint- to model-frame
glm::quat _rotation; // joint- to model-frame
glm::quat _rotationInConstrainedFrame; // rotation in frame where angular constraints would be applied
glm::quat _defaultRotation; // Not necessarilly bind rotation. See FBXJoint transform/bindTransform
glm::quat _inverseDefaultRotation;
glm::vec3 _defaultTranslation;
glm::vec3 _translation;
QString _name;
int _parentIndex;
bool _isFree;
glm::quat _preRotation;
glm::quat _postRotation;
glm::mat4 _preTransform;
glm::mat4 _postTransform;
glm::quat _inverseBindRotation;
glm::vec3 _unitsScale{1.0f, 1.0f, 1.0f};
};
#endif // hifi_JointState_h

View file

@ -46,8 +46,6 @@ static bool isEqual(const glm::quat& p, const glm::quat& q) {
} while (0)
#endif
static bool AJT_HACK_USE_JOINT_STATES = false;
/*
const glm::vec3 DEFAULT_RIGHT_EYE_POS(-0.3f, 1.6f, 0.0f);
const glm::vec3 DEFAULT_LEFT_EYE_POS(0.3f, 1.6f, 0.0f);
@ -176,16 +174,12 @@ void Rig::destroyAnimGraph() {
_overrideFlags.clear();
}
void Rig::initJointStates(const FBXGeometry& geometry, glm::mat4 modelOffset, int rootJointIndex,
int leftHandJointIndex, int leftElbowJointIndex, int leftShoulderJointIndex,
int rightHandJointIndex, int rightElbowJointIndex, int rightShoulderJointIndex) {
void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOffset) {
setModelOffset(modelOffset);
_geometryOffset = AnimPose(geometry.offset);
_animSkeleton = std::make_shared<AnimSkeleton>(geometry);
//_animSkeleton->dump();
computeEyesInRootFrame(_animSkeleton->getRelativeDefaultPoses());
_relativePoses.clear();
@ -200,41 +194,44 @@ void Rig::initJointStates(const FBXGeometry& geometry, glm::mat4 modelOffset, in
_overrideFlags.clear();
_overrideFlags.resize(_animSkeleton->getNumJoints(), false);
// AJT: LEGACY
{
// was Model::createJointStates
_jointStates.clear();
for (int i = 0; i < geometry.joints.size(); ++i) {
const FBXJoint& joint = geometry.joints[i];
// store a pointer to the FBXJoint in the JointState
JointState state(joint);
_jointStates.append(state);
}
_rootJointIndex = geometry.rootJointIndex;
_leftHandJointIndex = geometry.leftHandJointIndex;
_leftElbowJointIndex = _leftHandJointIndex >= 0 ? geometry.joints.at(_leftHandJointIndex).parentIndex : -1;
_leftShoulderJointIndex = _leftElbowJointIndex >= 0 ? geometry.joints.at(_leftElbowJointIndex).parentIndex : -1;
_rightHandJointIndex = geometry.rightHandJointIndex;
_rightElbowJointIndex = _rightHandJointIndex >= 0 ? geometry.joints.at(_rightHandJointIndex).parentIndex : -1;
_rightShoulderJointIndex = _rightElbowJointIndex >= 0 ? geometry.joints.at(_rightElbowJointIndex).parentIndex : -1;
}
// was old Rig::initJointStates
// compute model transforms
glm::mat4 rootTransform = (glm::mat4)(_modelOffset * _geometryOffset);
int numStates = _animSkeleton->getNumJoints();
for (int i = 0; i < numStates; ++i) {
JointState& state = _jointStates[i];
int parentIndex = state.getParentIndex();
if (parentIndex == -1) {
state.initTransform(rootTransform);
} else {
const JointState& parentState = _jointStates.at(parentIndex);
state.initTransform(parentState.getTransform());
}
}
void Rig::reset(const FBXGeometry& geometry) {
_geometryOffset = AnimPose(geometry.offset);
_animSkeleton = std::make_shared<AnimSkeleton>(geometry);
computeEyesInRootFrame(_animSkeleton->getRelativeDefaultPoses());
_relativePoses.clear();
_relativePoses = _animSkeleton->getRelativeDefaultPoses();
_absolutePoses.clear();
_absolutePoses = _animSkeleton->getAbsoluteDefaultPoses();
_overridePoses.clear();
_overridePoses = _animSkeleton->getRelativeDefaultPoses();
_overrideFlags.clear();
_overrideFlags.resize(_animSkeleton->getNumJoints(), false);
_rootJointIndex = geometry.rootJointIndex;
_leftHandJointIndex = geometry.leftHandJointIndex;
_leftElbowJointIndex = _leftHandJointIndex >= 0 ? geometry.joints.at(_leftHandJointIndex).parentIndex : -1;
_leftShoulderJointIndex = _leftElbowJointIndex >= 0 ? geometry.joints.at(_leftElbowJointIndex).parentIndex : -1;
_rightHandJointIndex = geometry.rightHandJointIndex;
_rightElbowJointIndex = _rightHandJointIndex >= 0 ? geometry.joints.at(_rightHandJointIndex).parentIndex : -1;
_rightShoulderJointIndex = _rightElbowJointIndex >= 0 ? geometry.joints.at(_rightElbowJointIndex).parentIndex : -1;
if (!_animGraphURL.isEmpty()) {
initAnimGraph(_animGraphURL);
}
// AJT: TODO: we could probaly just look these up by name?
_rootJointIndex = rootJointIndex;
_leftHandJointIndex = leftHandJointIndex;
_leftElbowJointIndex = leftElbowJointIndex;
_leftShoulderJointIndex = leftShoulderJointIndex;
_rightHandJointIndex = rightHandJointIndex;
_rightElbowJointIndex = rightElbowJointIndex;
_rightShoulderJointIndex = rightShoulderJointIndex;
}
bool Rig::jointStatesEmpty() {
@ -245,80 +242,15 @@ int Rig::getJointStateCount() const {
return _relativePoses.size();
}
// We could build and cache a dictionary, too....
// Should we be using .fst mapping instead/also?
int Rig::indexOfJoint(const QString& jointName) {
for (int i = 0; i < _jointStates.count(); i++) {
if (_jointStates[i].getName() == jointName) {
return i;
}
}
return -1;
return _animSkeleton->nameToJointIndex(jointName);
}
void Rig::setModelOffset(const glm::mat4& modelOffset) {
// AJT: LEGACY
{
_legacyModelOffset = modelOffset;
}
_modelOffset = AnimPose(modelOffset);
}
// AJT: REMOVE
/*
void Rig::initJointTransforms(glm::mat4 rootTransform) {
// compute model transforms
int numStates = _jointStates.size();
for (int i = 0; i < numStates; ++i) {
JointState& state = _jointStates[i];
int parentIndex = state.getParentIndex();
if (parentIndex == -1) {
state.initTransform(rootTransform);
} else {
const JointState& parentState = _jointStates.at(parentIndex);
state.initTransform(parentState.getTransform());
}
}
}
*/
void Rig::clearJointTransformTranslation(int jointIndex) {
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
return;
}
_jointStates[jointIndex].clearTransformTranslation();
}
void Rig::reset(const QVector<FBXJoint>& fbxJoints) {
if (_jointStates.isEmpty()) {
return;
}
for (int i = 0; i < _jointStates.size(); i++) {
_jointStates[i].setRotationInConstrainedFrame(fbxJoints.at(i).rotation, 0.0f);
_jointStates[i].setTranslation(fbxJoints.at(i).translation, 0.0f);
}
}
// AJT: REMOVE
/*
JointState Rig::getJointState(int jointIndex) const {
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
return JointState();
}
return _jointStates[jointIndex];
}
*/
bool Rig::getJointStateRotation(int index, glm::quat& rotation) const {
if (AJT_HACK_USE_JOINT_STATES) { // AJT: LEGACY
if (index == -1 || index >= _jointStates.size()) {
return false;
}
const JointState& state = _jointStates.at(index);
rotation = state.getRotationInConstrainedFrame();
return !state.rotationIsDefault(rotation);
}
if (index >= 0 && index < (int)_relativePoses.size()) {
rotation = _relativePoses[index].rot;
return !isEqual(rotation, _animSkeleton->getRelativeDefaultPose(index).rot);
@ -328,15 +260,6 @@ bool Rig::getJointStateRotation(int index, glm::quat& rotation) const {
}
bool Rig::getJointStateTranslation(int index, glm::vec3& translation) const {
if (AJT_HACK_USE_JOINT_STATES) { // AJT: LEGACY
if (index == -1 || index >= _jointStates.size()) {
return false;
}
const JointState& state = _jointStates.at(index);
translation = state.getTranslation();
return !state.translationIsDefault(translation);
}
if (index >= 0 && index < (int)_relativePoses.size()) {
translation = _relativePoses[index].trans;
return !isEqual(translation, _animSkeleton->getRelativeDefaultPose(index).trans);
@ -346,36 +269,17 @@ bool Rig::getJointStateTranslation(int index, glm::vec3& translation) const {
}
void Rig::clearJointState(int index) {
if (index != -1 && index < _jointStates.size()) {
// AJT: REMOVE
/*
JointState& state = _jointStates[index];
state.setRotationInConstrainedFrame(glm::quat(), 0.0f);
state.setTranslation(state.getDefaultTranslationInConstrainedFrame(), 0.0f);
*/
if (index >= 0 && index < (int)_relativePoses.size()) {
_overrideFlags[index] = false;
}
}
void Rig::clearJointStates() {
// AJT: LEGACY
/*
{
_jointStates.clear();
}
*/
_overrideFlags.clear();
_overrideFlags.resize(_animSkeleton->getNumJoints());
}
void Rig::clearJointAnimationPriority(int index) {
// AJT: legacy
{
if (index != -1 && index < _jointStates.size()) {
_jointStates[index].setAnimationPriority(0.0f);
}
}
if (index >= 0 && index < (int)_overrideFlags.size()) {
_overrideFlags[index] = false;
}
@ -384,21 +288,9 @@ void Rig::clearJointAnimationPriority(int index) {
// Deprecated.
// WARNING: this is not symmetric with getJointRotation. It's historical. Use the appropriate specific variation.
void Rig::setJointRotation(int index, bool valid, const glm::quat& rotation, float priority) {
// AJT: legacy
{
if (index != -1 && index < _jointStates.size()) {
JointState& state = _jointStates[index];
if (valid) {
state.setRotationInConstrainedFrame(rotation, priority);
} else {
state.restoreRotation(1.0f, priority);
}
}
}
if (index >= 0 && index < (int)_overrideFlags.size()) {
if (valid) {
assert(_overrideFlags.size() == _overridePoses.size());
ASSERT(_overrideFlags.size() == _overridePoses.size());
_overrideFlags[index] = true;
_overridePoses[index].rot = rotation;
}
@ -406,56 +298,49 @@ void Rig::setJointRotation(int index, bool valid, const glm::quat& rotation, flo
}
void Rig::restoreJointRotation(int index, float fraction, float priority) {
if (index != -1 && index < _jointStates.size()) {
_jointStates[index].restoreRotation(fraction, priority);
}
// AJT: DEAD CODE?
ASSERT(false);
}
void Rig::restoreJointTranslation(int index, float fraction, float priority) {
if (index != -1 && index < _jointStates.size()) {
_jointStates[index].restoreTranslation(fraction, priority);
}
// AJT: DEAD CODE?
ASSERT(false);
}
bool Rig::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position,
glm::vec3 translation, glm::quat rotation) const {
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
// 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;
return true;
} else {
return false;
}
// position is in world-frame
position = translation + rotation * _jointStates[jointIndex].getPosition();
return true;
}
// AJT: NOTE old code did not have 180 flip!
bool Rig::getJointPosition(int jointIndex, glm::vec3& position) const {
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
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;
return true;
} else {
return false;
}
// position is in model-frame
position = extractTranslation(_jointStates[jointIndex].getTransform());
return true;
}
bool Rig::getJointRotationInWorldFrame(int jointIndex, glm::quat& result, const glm::quat& rotation) const {
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
if (jointIndex >= 0 && jointIndex < (int)_absolutePoses.size()) {
result = rotation * _absolutePoses[jointIndex].rot;
return true;
} else {
return false;
}
result = rotation * _jointStates[jointIndex].getRotation();
return true;
}
// Deprecated.
// WARNING: this is not symmetric with setJointRotation. It's historical. Use the appropriate specific variation.
bool Rig::getJointRotation(int jointIndex, glm::quat& rotation) const {
// AJT: LEGACY
{
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
return false;
}
rotation = _jointStates[jointIndex].getRotation();
}
if (jointIndex >= 0 && jointIndex < (int)_relativePoses.size()) {
rotation = _relativePoses[jointIndex].rot;
return true;
@ -465,14 +350,6 @@ bool Rig::getJointRotation(int jointIndex, glm::quat& rotation) const {
}
bool Rig::getJointTranslation(int jointIndex, glm::vec3& translation) const {
// AJT: LEGACY
{
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
return false;
}
translation = _jointStates[jointIndex].getTranslation();
}
if (jointIndex >= 0 && jointIndex < (int)_relativePoses.size()) {
translation = _relativePoses[jointIndex].trans;
return true;
@ -482,11 +359,9 @@ bool Rig::getJointTranslation(int jointIndex, glm::vec3& translation) const {
}
bool Rig::getJointCombinedRotation(int jointIndex, glm::quat& result, const glm::quat& rotation) const {
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
return false;
}
result = rotation * _jointStates[jointIndex].getRotation();
return true;
// AJT: WTF IS THIS?
ASSERT(false);
return false;
}
void Rig::calcAnimAlpha(float speed, const std::vector<float>& referenceSpeeds, float* alphaOut) const {
@ -807,236 +682,56 @@ void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) {
_animVars.setTrigger(trigger);
}
// AJT: LEGACY
if (AJT_HACK_USE_JOINT_STATES) {
clearJointStatePriorities();
// copy poses into jointStates
const float PRIORITY = 1.0f;
for (size_t i = 0; i < _relativePoses.size(); i++) {
setJointRotationInConstrainedFrame((int)i, glm::inverse(_animSkeleton->getRelativeBindPose(i).rot) * _relativePoses[i].rot, PRIORITY, 1.0f);
setJointTranslation((int)i, true, _relativePoses[i].trans, PRIORITY);
}
}
computeEyesInRootFrame(_relativePoses);
}
applyOverridePoses();
buildAbsolutePoses();
// AJT: LEGACY
{
for (int i = 0; i < _jointStates.size(); i++) {
_jointStates[i].resetTransformChanged();
}
}
}
void Rig::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm::quat& targetRotation, float priority,
const QVector<int>& freeLineage, glm::mat4 rootTransform) {
// NOTE: targetRotation is from in model-frame
if (endIndex == -1 || _jointStates.isEmpty()) {
return;
}
if (freeLineage.isEmpty()) {
return;
}
// store and remember topmost parent transform
glm::mat4 topParentTransform;
{
int index = freeLineage.last();
const JointState& state = _jointStates.at(index);
int parentIndex = state.getParentIndex();
if (parentIndex == -1) {
topParentTransform = rootTransform;
} else {
topParentTransform = _jointStates[parentIndex].getTransform();
}
}
// relax toward default rotation
// NOTE: ideally this should use dt and a relaxation timescale to compute how much to relax
int numFree = freeLineage.size();
for (int j = 0; j < numFree; j++) {
int nextIndex = freeLineage.at(j);
JointState& nextState = _jointStates[nextIndex];
if (! nextState.getIsFree()) {
continue;
}
// Apply the zero rotationDelta, but use mixRotationDelta() which blends a bit of the default pose
// in the process. This provides stability to the IK solution for most models.
float mixFactor = 0.08f;
nextState.mixRotationDelta(glm::quat(), mixFactor, priority);
}
// this is a cyclic coordinate descent algorithm: see
// http://www.ryanjuckett.com/programming/animation/21-cyclic-coordinate-descent-in-2d
// keep track of the position of the end-effector
JointState& endState = _jointStates[endIndex];
glm::vec3 endPosition = endState.getPosition();
float distanceToGo = glm::distance(targetPosition, endPosition);
const int MAX_ITERATION_COUNT = 3;
const float ACCEPTABLE_IK_ERROR = 0.005f; // 5mm
int numIterations = 0;
do {
++numIterations;
// moving up, rotate each free joint to get endPosition closer to target
for (int j = 1; j < numFree; j++) {
int nextIndex = freeLineage.at(j);
JointState& nextState = _jointStates[nextIndex];
if (! nextState.getIsFree()) {
continue;
}
glm::vec3 pivot = nextState.getPosition();
glm::vec3 leverArm = endPosition - pivot;
float leverLength = glm::length(leverArm);
if (leverLength < EPSILON) {
continue;
}
glm::quat deltaRotation = rotationBetween(leverArm, targetPosition - pivot);
// We want to mix the shortest rotation with one that will pull the system down with gravity
// so that limbs don't float unrealistically. To do this we compute a simplified center of mass
// where each joint has unit mass and we don't bother averaging it because we only need direction.
if (j > 1) {
glm::vec3 centerOfMass(0.0f);
for (int k = 0; k < j; ++k) {
int massIndex = freeLineage.at(k);
centerOfMass += _jointStates[massIndex].getPosition() - pivot;
}
// the gravitational effect is a rotation that tends to align the two cross products
const glm::vec3 worldAlignment = glm::vec3(0.0f, -1.0f, 0.0f);
glm::quat gravityDelta = rotationBetween(glm::cross(centerOfMass, leverArm),
glm::cross(worldAlignment, leverArm));
float gravityAngle = glm::angle(gravityDelta);
const float MIN_GRAVITY_ANGLE = 0.1f;
float mixFactor = 0.1f;
if (gravityAngle < MIN_GRAVITY_ANGLE) {
// the final rotation is a mix of the two
mixFactor = 0.5f * gravityAngle / MIN_GRAVITY_ANGLE;
}
deltaRotation = safeMix(deltaRotation, gravityDelta, mixFactor);
}
// Apply the rotation delta.
glm::quat oldNextRotation = nextState.getRotation();
nextState.applyRotationDelta(deltaRotation, priority);
// measure the result of the rotation which may have been modified by blending
glm::quat actualDelta = nextState.getRotation() * glm::inverse(oldNextRotation);
endPosition = pivot + actualDelta * leverArm;
}
// recompute transforms from the top down
glm::mat4 currentParentTransform = topParentTransform;
for (int j = numFree - 1; j >= 0; --j) {
JointState& freeState = _jointStates[freeLineage.at(j)];
freeState.computeTransform(currentParentTransform);
currentParentTransform = freeState.getTransform();
}
// measure our success
endPosition = endState.getPosition();
distanceToGo = glm::distance(targetPosition, endPosition);
} while (numIterations < MAX_ITERATION_COUNT && distanceToGo > ACCEPTABLE_IK_ERROR);
// set final rotation of the end joint
endState.setRotationInModelFrame(targetRotation, priority);
ASSERT(false);
}
bool Rig::restoreJointPosition(int jointIndex, float fraction, float priority, const QVector<int>& freeLineage) {
if (jointIndex == -1 || _jointStates.isEmpty()) {
return false;
}
foreach (int index, freeLineage) {
JointState& state = _jointStates[index];
state.restoreRotation(fraction, priority);
state.restoreTranslation(fraction, priority);
}
return true;
ASSERT(false);
return false;
}
float Rig::getLimbLength(int jointIndex, const QVector<int>& freeLineage,
const glm::vec3 scale, const QVector<FBXJoint>& fbxJoints) const {
if (jointIndex == -1 || _jointStates.isEmpty()) {
return 0.0f;
}
float length = 0.0f;
float lengthScale = (scale.x + scale.y + scale.z) / 3.0f;
for (int i = freeLineage.size() - 2; i >= 0; i--) {
length += fbxJoints.at(freeLineage.at(i)).distanceToParent * lengthScale;
}
return length;
ASSERT(false);
return 1.0f;
}
glm::quat Rig::setJointRotationInBindFrame(int jointIndex, const glm::quat& rotation, float priority) {
glm::quat endRotation;
if (jointIndex == -1 || _jointStates.isEmpty()) {
return endRotation;
}
JointState& state = _jointStates[jointIndex];
state.setRotationInBindFrame(rotation, priority);
endRotation = state.getRotationInBindFrame();
return endRotation;
ASSERT(false);
return glm::quat();
}
glm::vec3 Rig::getJointDefaultTranslationInConstrainedFrame(int jointIndex) {
if (jointIndex == -1 || _jointStates.isEmpty()) {
return glm::vec3();
}
return _jointStates[jointIndex].getDefaultTranslationInConstrainedFrame();
ASSERT(false);
return glm::vec3();
}
glm::quat Rig::setJointRotationInConstrainedFrame(int jointIndex, glm::quat targetRotation, float priority, float mix) {
glm::quat endRotation;
if (jointIndex == -1 || _jointStates.isEmpty()) {
return endRotation;
}
JointState& state = _jointStates[jointIndex];
state.setRotationInConstrainedFrame(targetRotation, priority, mix);
endRotation = state.getRotationInConstrainedFrame();
return endRotation;
ASSERT(false);
return glm::quat();
}
bool Rig::getJointRotationInConstrainedFrame(int jointIndex, glm::quat& quatOut) const {
if (jointIndex == -1 || _jointStates.isEmpty()) {
return false;
}
quatOut = _jointStates[jointIndex].getRotationInConstrainedFrame();
return true;
ASSERT(false);
return false;
}
void Rig::clearJointStatePriorities() {
for (int i = 0; i < _jointStates.size(); i++) {
_jointStates[i].setAnimationPriority(0.0f);
}
ASSERT(false);
}
/*
void Rig::applyJointRotationDelta(int jointIndex, const glm::quat& delta, float priority) {
if (jointIndex == -1 || _jointStates.isEmpty()) {
return;
}
_jointStates[jointIndex].applyRotationDelta(delta, priority);
}
*/
glm::quat Rig::getJointDefaultRotationInParentFrame(int jointIndex) {
if (jointIndex == -1 || _jointStates.isEmpty()) {
return glm::quat();
}
return _jointStates[jointIndex].getDefaultRotationInParentFrame();
ASSERT(false);
return glm::quat();
}
void Rig::updateFromHeadParameters(const HeadParameters& params, float dt) {
@ -1063,7 +758,7 @@ static const glm::vec3 Y_AXIS(0.0f, 1.0f, 0.0f);
static const glm::vec3 Z_AXIS(0.0f, 0.0f, 1.0f);
void Rig::updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist) {
if (index >= 0 && _jointStates[index].getParentIndex() >= 0) {
if (index >= 0 && index) {
if (_animSkeleton) {
glm::quat absRot = (glm::angleAxis(-RADIANS_PER_DEGREE * leanSideways, Z_AXIS) *
glm::angleAxis(-RADIANS_PER_DEGREE * leanForward, X_AXIS) *
@ -1113,82 +808,69 @@ static void computeHeadNeckAnimVars(AnimSkeleton::ConstPointer skeleton, const A
}
void Rig::updateNeckJoint(int index, const HeadParameters& params) {
if (index >= 0 && _jointStates[index].getParentIndex() >= 0) {
if (_animSkeleton) {
if (_animSkeleton && index >= 0 && index < _animSkeleton->getNumJoints()) {
if (params.isInHMD) {
glm::vec3 headPos, neckPos;
glm::quat headRot, neckRot;
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), avatarToGeometryNegZForward(params.localHeadOrientation), avatarToGeometry(params.localHeadPosition));
computeHeadNeckAnimVars(_animSkeleton, hmdPose, headPos, headRot, neckPos, neckRot);
// debug rendering
// debug rendering
#ifdef DEBUG_RENDERING
const glm::vec4 red(1.0f, 0.0f, 0.0f, 1.0f);
const glm::vec4 green(0.0f, 1.0f, 0.0f, 1.0f);
const glm::vec4 red(1.0f, 0.0f, 0.0f, 1.0f);
const glm::vec4 green(0.0f, 1.0f, 0.0f, 1.0f);
// transform from bone into avatar space
AnimPose headPose(glm::vec3(1), headRot, headPos);
DebugDraw::getInstance().addMyAvatarMarker("headTarget", headPose.rot, headPose.trans, red);
// transform from bone into avatar space
AnimPose headPose(glm::vec3(1), headRot, headPos);
DebugDraw::getInstance().addMyAvatarMarker("headTarget", headPose.rot, headPose.trans, red);
// transform from bone into avatar space
AnimPose neckPose(glm::vec3(1), neckRot, neckPos);
DebugDraw::getInstance().addMyAvatarMarker("neckTarget", neckPose.rot, neckPose.trans, green);
// transform from bone into avatar space
AnimPose neckPose(glm::vec3(1), neckRot, neckPos);
DebugDraw::getInstance().addMyAvatarMarker("neckTarget", neckPose.rot, neckPose.trans, green);
#endif
_animVars.set("headPosition", headPos);
_animVars.set("headRotation", headRot);
_animVars.set("headType", (int)IKTarget::Type::HmdHead);
_animVars.set("neckPosition", neckPos);
_animVars.set("neckRotation", neckRot);
//_animVars.set("neckType", (int)IKTarget::Type::RotationOnly);
_animVars.set("neckType", (int)IKTarget::Type::Unknown); // 'Unknown' disables the target
_animVars.set("headPosition", headPos);
_animVars.set("headRotation", headRot);
_animVars.set("headType", (int)IKTarget::Type::HmdHead);
_animVars.set("neckPosition", neckPos);
_animVars.set("neckRotation", neckRot);
_animVars.set("neckType", (int)IKTarget::Type::Unknown); // 'Unknown' disables the target
} else {
/*
// the params.localHeadOrientation is composed incorrectly, so re-compose it correctly from pitch, yaw and roll.
glm::quat realLocalHeadOrientation = (glm::angleAxis(glm::radians(-params.localHeadRoll), Z_AXIS) *
glm::angleAxis(glm::radians(params.localHeadYaw), Y_AXIS) *
glm::angleAxis(glm::radians(-params.localHeadPitch), X_AXIS));
*/
_animVars.unset("headPosition");
/*
qCDebug(animation) << "AJT: input orientation " << params.localHeadOrientation;
qCDebug(animation) << "AJT: after transform" << avatarToGeometry(params.localHeadOrientation);
*/
_animVars.set("headRotation", avatarToGeometryNegZForward(params.localHeadOrientation));
_animVars.set("headAndNeckType", (int)IKTarget::Type::RotationOnly);
_animVars.set("headType", (int)IKTarget::Type::RotationOnly);
_animVars.unset("neckPosition");
_animVars.unset("neckRotation");
_animVars.set("neckType", (int)IKTarget::Type::RotationOnly);
}
} else {
_animVars.unset("headPosition");
_animVars.set("headRotation", avatarToGeometryNegZForward(params.localHeadOrientation));
_animVars.set("headAndNeckType", (int)IKTarget::Type::RotationOnly);
_animVars.set("headType", (int)IKTarget::Type::RotationOnly);
_animVars.unset("neckPosition");
_animVars.unset("neckRotation");
_animVars.set("neckType", (int)IKTarget::Type::RotationOnly);
}
}
}
void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade) {
if (index >= 0 && _jointStates[index].getParentIndex() >= 0) {
auto& state = _jointStates[index];
auto& parentState = _jointStates[state.getParentIndex()];
// AJT: TODO: fix eye tracking!
/*
{
if (index >= 0 && _jointStates[index].getParentIndex() >= 0) {
auto& state = _jointStates[index];
auto& parentState = _jointStates[state.getParentIndex()];
// NOTE: at the moment we do the math in the world-frame, hence the inverse transform is more complex than usual.
glm::mat4 inverse = glm::inverse(glm::mat4_cast(modelRotation) * parentState.getTransform() *
glm::translate(state.getDefaultTranslationInConstrainedFrame()) *
state.getPreTransform() * glm::mat4_cast(state.getPreRotation() * state.getDefaultRotation()));
glm::vec3 front = glm::vec3(inverse * glm::vec4(worldHeadOrientation * IDENTITY_FRONT, 0.0f));
glm::vec3 lookAtDelta = lookAtSpot - modelTranslation;
glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(lookAtDelta + glm::length(lookAtDelta) * saccade, 1.0f));
glm::quat between = rotationBetween(front, lookAt);
const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE;
state.setRotationInConstrainedFrame(glm::angleAxis(glm::clamp(glm::angle(between), -MAX_ANGLE, MAX_ANGLE), glm::axis(between)) *
state.getDefaultRotation(), DEFAULT_PRIORITY);
// NOTE: at the moment we do the math in the world-frame, hence the inverse transform is more complex than usual.
glm::mat4 inverse = glm::inverse(glm::mat4_cast(modelRotation) * parentState.getTransform() *
glm::translate(state.getDefaultTranslationInConstrainedFrame()) *
state.getPreTransform() * glm::mat4_cast(state.getPreRotation() * state.getDefaultRotation()));
glm::vec3 front = glm::vec3(inverse * glm::vec4(worldHeadOrientation * IDENTITY_FRONT, 0.0f));
glm::vec3 lookAtDelta = lookAtSpot - modelTranslation;
glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(lookAtDelta + glm::length(lookAtDelta) * saccade, 1.0f));
glm::quat between = rotationBetween(front, lookAt);
const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE;
state.setRotationInConstrainedFrame(glm::angleAxis(glm::clamp(glm::angle(between), -MAX_ANGLE, MAX_ANGLE), glm::axis(between)) *
state.getDefaultRotation(), DEFAULT_PRIORITY);
}
}
*/
}
glm::vec3 Rig::avatarToGeometry(const glm::vec3& pos) const {
@ -1279,6 +961,9 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) {
}
void Rig::initAnimGraph(const QUrl& url) {
_animGraphURL = url;
_animNode.reset();
// load the anim graph
_animLoader.reset(new AnimNodeLoader(url));
@ -1337,70 +1022,13 @@ void Rig::buildAbsolutePoses() {
for (int i = 0; i < (int)_absolutePoses.size(); i++) {
_absolutePoses[i] = rootTransform * _absolutePoses[i];
}
// AJT: LEGACY
{
// Build the joint states
glm::mat4 rootTransform = (glm::mat4)(_modelOffset * _geometryOffset);
for (int i = 0; i < (int)_animSkeleton->getNumJoints(); i++) {
JointState& state = _jointStates[i];
// compute model transforms
int parentIndex = state.getParentIndex();
if (parentIndex == -1) {
state.computeTransform(rootTransform);
} else {
// guard against out-of-bounds access to _jointStates
if (parentIndex >= 0 && parentIndex < _jointStates.size()) {
const JointState& parentState = _jointStates.at(parentIndex);
state.computeTransform(parentState.getTransform(), parentState.getTransformChanged());
}
}
}
}
}
glm::mat4 Rig::getJointTransform(int jointIndex) const {
if (jointIndex == -1 || jointIndex >= _jointStates.size()) {
return glm::mat4();
}
// check for differences between jointStates and _absolutePoses!
// AJT: TODO REMOVE
if (false) {
glm::mat4 oldMat = _jointStates[jointIndex].getTransform();
AnimPose oldPose(oldMat);
glm::mat4 newMat = _absolutePoses[jointIndex];
AnimPose newPose(newMat);
bool badTrans = !isEqual(newPose.trans, oldPose.trans);
bool badScale = !isEqual(newPose.scale, oldPose.scale);
bool badRot = !isEqual(newPose.rot, oldPose.rot);
if (badTrans || badScale || badRot) {
qCDebug(animation).nospace() << "AJT: mismatch for " << _animSkeleton->getJointName(jointIndex) << ", joint[" << jointIndex << "]";
if (badTrans) {
qCDebug(animation) << "AJT: oldTrans = " << oldPose.trans;
qCDebug(animation) << "AJT: newTrans = " << newPose.trans;
}
if (badRot) {
qCDebug(animation) << "AJT: oldRot = " << oldPose.rot << "log =" << glm::log(oldPose.rot);
qCDebug(animation) << "AJT: newRot = " << newPose.rot << "log =" << glm::log(newPose.rot);
}
if (badScale) {
qCDebug(animation) << "AJT: oldScale = " << oldPose.scale;
qCDebug(animation) << "AJT: newScale = " << newPose.scale;
}
}
}
// AJT: LEGACY
if (AJT_HACK_USE_JOINT_STATES) {
return _jointStates[jointIndex].getTransform();
} else {
if (jointIndex >= 0 && jointIndex < (int)_absolutePoses.size()) {
return _absolutePoses[jointIndex];
} else {
return glm::mat4();
}
}

View file

@ -20,8 +20,6 @@
#include <vector>
#include <JointData.h>
#include "JointState.h" // We might want to change this (later) to something that doesn't depend on gpu, fbx and model. -HRS
#include "AnimNode.h"
#include "AnimNodeLoader.h"
#include "SimpleMovingAverage.h"
@ -76,7 +74,6 @@ public:
virtual ~Rig() {}
void destroyAnimGraph();
void overrideAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame);
void restoreAnimation();
QStringList getAnimationRoles() const;
@ -84,9 +81,8 @@ public:
void restoreRoleAnimation(const QString& role);
void prefetchAnimation(const QString& url);
void initJointStates(const FBXGeometry& geometry, glm::mat4 modelOffset, int rootJointIndex,
int leftHandJointIndex, int leftElbowJointIndex, int leftShoulderJointIndex,
int rightHandJointIndex, int rightElbowJointIndex, int rightShoulderJointIndex);
void initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOffset);
void reset(const FBXGeometry& geometry);
bool jointStatesEmpty();
int getJointStateCount() const;
int indexOfJoint(const QString& jointName);
@ -94,19 +90,9 @@ public:
void setModelOffset(const glm::mat4& modelOffset);
const AnimPose& getGeometryOffset() const { return _geometryOffset; }
// AJT: REMOVE
/*
void initJointTransforms(glm::mat4 rootTransform);
*/
void clearJointTransformTranslation(int jointIndex);
void reset(const QVector<FBXJoint>& fbxJoints);
bool getJointStateRotation(int index, glm::quat& rotation) const;
bool getJointStateTranslation(int index, glm::vec3& translation) const;
// AJT: REMOVE
/*
void applyJointRotationDelta(int jointIndex, const glm::quat& delta, float priority);
JointState getJointState(int jointIndex) const; // XXX
*/
void clearJointState(int index);
void clearJointStates();
void clearJointAnimationPriority(int index);
@ -151,9 +137,6 @@ public:
void updateFromEyeParameters(const EyeParameters& params);
void updateFromHandParameters(const HandParameters& params, float dt);
virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation,
float scale, float priority) = 0;
void initAnimGraph(const QUrl& url);
AnimNode::ConstPointer getAnimNode() const { return _animNode; }
@ -185,16 +168,11 @@ public:
glm::quat avatarToGeometryZForward(const glm::quat& quat) const;
glm::quat avatarToGeometryNegZForward(const glm::quat& quat) const;
// AJT: TODO: LEGACY
QVector<JointState> _jointStates;
glm::mat4 _legacyModelOffset;
// AJT: TODO document these better
AnimPose _modelOffset; // model to avatar space (without 180 flip)
AnimPose _geometryOffset; // geometry to model space (includes unit offset & fst offsets)
AnimPoseVec _relativePoses; // in fbx model space relative to parent.
AnimPoseVec _absolutePoses; // in fbx model space after _modelOffset is applied.
AnimPoseVec _overridePoses; // in fbx model space relative to parent.
AnimPoseVec _relativePoses; // geometry space relative to parent.
AnimPoseVec _absolutePoses; // avatar space, not relative to parent.
AnimPoseVec _overridePoses; // geometry space relative to parent.
std::vector<bool> _overrideFlags;
int _rootJointIndex { -1 };
@ -212,6 +190,7 @@ public:
glm::vec3 _lastVelocity;
glm::vec3 _eyesInRootFrame { Vectors::ZERO };
QUrl _animGraphURL;
std::shared_ptr<AnimNode> _animNode;
std::shared_ptr<AnimSkeleton> _animSkeleton;
std::unique_ptr<AnimNodeLoader> _animLoader;

View file

@ -13,6 +13,7 @@
#include <QObject>
#include <QByteArray>
#include <QtConcurrent/QtConcurrentRun>
#include <glm/gtx/transform.hpp>
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push

View file

@ -87,6 +87,8 @@ void Model::setScale(const glm::vec3& scale) {
_scaledToFit = false;
}
const float METERS_PER_MILLIMETER = 0.01f;
void Model::setScaleInternal(const glm::vec3& scale) {
if (glm::distance(_scale, scale) > METERS_PER_MILLIMETER) {
_scale = scale;
@ -117,7 +119,7 @@ void Model::init() {
void Model::reset() {
if (_geometry && _geometry->isLoaded()) {
const FBXGeometry& geometry = _geometry->getFBXGeometry();
_rig->reset(geometry.joints);
_rig->reset(geometry);
}
}
@ -162,22 +164,7 @@ void Model::initJointStates() {
const FBXGeometry& geometry = _geometry->getFBXGeometry();
glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset);
int rootJointIndex = geometry.rootJointIndex;
int leftHandJointIndex = geometry.leftHandJointIndex;
int leftElbowJointIndex = leftHandJointIndex >= 0 ? geometry.joints.at(leftHandJointIndex).parentIndex : -1;
int leftShoulderJointIndex = leftElbowJointIndex >= 0 ? geometry.joints.at(leftElbowJointIndex).parentIndex : -1;
int rightHandJointIndex = geometry.rightHandJointIndex;
int rightElbowJointIndex = rightHandJointIndex >= 0 ? geometry.joints.at(rightHandJointIndex).parentIndex : -1;
int rightShoulderJointIndex = rightElbowJointIndex >= 0 ? geometry.joints.at(rightElbowJointIndex).parentIndex : -1;
_rig->initJointStates(geometry, modelOffset,
rootJointIndex,
leftHandJointIndex,
leftElbowJointIndex,
leftShoulderJointIndex,
rightHandJointIndex,
rightElbowJointIndex,
rightShoulderJointIndex);
_rig->initJointStates(geometry, modelOffset);
}
bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance,
@ -818,6 +805,7 @@ void Blender::run() {
const float NORMAL_COEFFICIENT_SCALE = 0.01f;
for (int i = 0, n = qMin(_blendshapeCoefficients.size(), mesh.blendshapes.size()); i < n; i++) {
float vertexCoefficient = _blendshapeCoefficients.at(i);
const float EPSILON = 0.0001f;
if (vertexCoefficient < EPSILON) {
continue;
}

View file

@ -29,7 +29,6 @@
#include <Transform.h>
#include "GeometryCache.h"
#include "JointState.h"
#include "TextureCache.h"
#include "Rig.h"