mirror of
https://github.com/lubosz/overte.git
synced 2025-04-15 18:48:32 +02:00
Removed JointStates! You won't be missed.
This commit is contained in:
parent
a4116e633a
commit
a77ea8da43
17 changed files with 180 additions and 1182 deletions
|
@ -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);
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) << "[";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include <Transform.h>
|
||||
|
||||
#include "GeometryCache.h"
|
||||
#include "JointState.h"
|
||||
#include "TextureCache.h"
|
||||
#include "Rig.h"
|
||||
|
||||
|
|
Loading…
Reference in a new issue