From 6f4fc24fb6082c06c86b528aea97deae3f0b9aab Mon Sep 17 00:00:00 2001 From: Bennett Goble Date: Sun, 30 Aug 2015 12:05:56 -0400 Subject: [PATCH 1/8] NodeConnectionData QDataStream #include --- domain-server/src/NodeConnectionData.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/domain-server/src/NodeConnectionData.cpp b/domain-server/src/NodeConnectionData.cpp index 3c75e8faad..80cb5950be 100644 --- a/domain-server/src/NodeConnectionData.cpp +++ b/domain-server/src/NodeConnectionData.cpp @@ -11,6 +11,8 @@ #include "NodeConnectionData.h" +#include + NodeConnectionData NodeConnectionData::fromDataStream(QDataStream& dataStream, const HifiSockAddr& senderSockAddr, bool isConnectRequest) { NodeConnectionData newHeader; From a907c5757b63b9da6592f0ee642f727a2356d4ef Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Mon, 31 Aug 2015 11:09:28 -0700 Subject: [PATCH 2/8] Do not reset animation frame when restarting while we're fading out. Keeps it smooth if we're oscillating on some theshold between running and not.) --- libraries/animation/src/AnimationHandle.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/animation/src/AnimationHandle.cpp b/libraries/animation/src/AnimationHandle.cpp index 1f4c886a06..ad09e0736d 100644 --- a/libraries/animation/src/AnimationHandle.cpp +++ b/libraries/animation/src/AnimationHandle.cpp @@ -10,7 +10,7 @@ // #include "AnimationHandle.h" - +#include "AnimationLogging.h" void AnimationHandle::setURL(const QUrl& url) { if (_url != url) { @@ -51,8 +51,8 @@ void AnimationHandle::setMaskedJoints(const QStringList& maskedJoints) { } void AnimationHandle::setRunning(bool running, bool doRestoreJoints) { - if (running && isRunning()) { - // if we're already running, this is the same as a restart + if (running && isRunning() && (getFadePerSecond() >= 0.0f)) { + // if we're already running, this is the same as a restart -- unless we're fading out. setFrameIndex(getFirstFrame()); return; } From 2dbfa5ce9f1d0adeb97e0ce86bdc90ff23eb564c Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Mon, 31 Aug 2015 11:10:05 -0700 Subject: [PATCH 3/8] Be more uniform in deciding animation movement, and incorporate HMD standing mode (which sets position, but not velocity). --- libraries/animation/src/Rig.cpp | 40 ++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 3e466b94d6..24a86aa81a 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -418,9 +418,30 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos } bool isMoving = false; glm::vec3 front = worldRotation * IDENTITY_FRONT; - float forwardSpeed = glm::dot(worldVelocity, front); - float rightLateralSpeed = glm::dot(worldVelocity, worldRotation * IDENTITY_RIGHT); - float rightTurningSpeed = glm::orientedAngle(front, _lastFront, IDENTITY_UP) / deltaTime; + glm::vec3 right = worldRotation * IDENTITY_RIGHT; + const float PERCEPTIBLE_DELTA = 0.001f; + const float PERCEPTIBLE_SPEED = 0.1f; + // It can be more accurate/smooth to use velocity rather than position, + // but some modes (e.g., hmd standing) update position without updating velocity. + // It's very hard to debug hmd standing. (Look down at yourself, or have a second person observe. HMD third person is a bit undefined...) + // So, let's create our own workingVelocity from the worldPosition... + glm::vec3 positionDelta = worldPosition - _lastPosition; + glm::vec3 workingVelocity = positionDelta / deltaTime; + // But for smoothest (non-hmd standing) results, go ahead and use velocity: +#if !WANT_DEBUG + // Note: Separately, we've arranged for starting/stopping animations by role (as we've done here) to pick up where they've left off when fading, + // so that you wouldn't notice the start/stop if it happens fast enough (e.g., one frame). But the print below would still be noisy. + if (!positionDelta.x && !positionDelta.y && !positionDelta.z) { + workingVelocity = worldVelocity; + } +#endif + + float forwardSpeed = glm::dot(workingVelocity, front); + float rightLateralSpeed = glm::dot(workingVelocity, right); + float rightTurningDelta = glm::orientedAngle(front, _lastFront, IDENTITY_UP); + float rightTurningSpeed = rightTurningDelta / deltaTime; + bool isTurning = (std::abs(rightTurningDelta) > PERCEPTIBLE_DELTA) && (std::abs(rightTurningSpeed) > PERCEPTIBLE_SPEED); + bool isStrafing = std::abs(rightLateralSpeed) > PERCEPTIBLE_SPEED; auto updateRole = [&](const QString& role, bool isOn) { isMoving = isMoving || isOn; if (isOn) { @@ -435,14 +456,13 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos } } }; - updateRole("walk", forwardSpeed > 0.01f); - updateRole("backup", forwardSpeed < -0.01f); - bool isTurning = std::abs(rightTurningSpeed) > 0.5f; - updateRole("rightTurn", isTurning && (rightTurningSpeed > 0)); - updateRole("leftTurn", isTurning && (rightTurningSpeed < 0)); - bool isStrafing = !isTurning && (std::abs(rightLateralSpeed) > 0.01f); + updateRole("walk", forwardSpeed > PERCEPTIBLE_SPEED); + updateRole("backup", forwardSpeed < -PERCEPTIBLE_SPEED); + updateRole("rightTurn", isTurning && (rightTurningSpeed > 0.0f)); + updateRole("leftTurn", isTurning && (rightTurningSpeed < 0.0f)); + isStrafing = isStrafing && !isMoving; updateRole("rightStrafe", isStrafing && (rightLateralSpeed > 0.0f)); - updateRole("leftStrafe", isStrafing && (rightLateralSpeed < 0.0f)); + updateRole("leftStrafe", isStrafing && (rightLateralSpeed < 0.0f)); updateRole("idle", !isMoving); // Must be last, as it makes isMoving bogus. _lastFront = front; _lastPosition = worldPosition; From 4a7a384c650f811cb5066470846da3b8a1da6026 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 1 Sep 2015 14:12:14 -0700 Subject: [PATCH 4/8] avoid bad joints when computing bounding capsule --- interface/src/avatar/SkeletonModel.cpp | 109 +++++++++++++++++++------ interface/src/avatar/SkeletonModel.h | 3 +- libraries/animation/src/Rig.cpp | 23 +++--- libraries/fbx/src/FBXReader.cpp | 16 +++- 4 files changed, 110 insertions(+), 41 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index a2e5908477..90c30b41ee 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -86,7 +86,7 @@ void SkeletonModel::initJointStates(QVector states) { _rig->updateJointState(i, rootTransform); } - buildShapes(); + computeBoundingShape(); Extents meshExtents = getMeshExtents(); _headClipDistance = -(meshExtents.minimum.z / _scale.z - _defaultEyeModelPosition.z); @@ -248,6 +248,7 @@ void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position) rotationBetween(handRotation * glm::vec3(-sign, 0.0f, 0.0f), forearmVector), true, PALM_PRIORITY); } + void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { if (jointIndex == -1 || jointIndex >= _rig->getJointStateCount()) { return; @@ -346,9 +347,9 @@ void SkeletonModel::renderOrientationDirections(gpu::Batch& batch, int jointInde } OrientationLineIDs& jointLineIDs = _jointOrientationLines[jointIndex]; - glm::vec3 pRight = position + orientation * IDENTITY_RIGHT * size; - glm::vec3 pUp = position + orientation * IDENTITY_UP * size; - glm::vec3 pFront = position + orientation * IDENTITY_FRONT * size; + glm::vec3 pRight = position + orientation * IDENTITY_RIGHT * size; + glm::vec3 pUp = position + orientation * IDENTITY_UP * size; + glm::vec3 pFront = position + orientation * IDENTITY_FRONT * size; glm::vec3 red(1.0f, 0.0f, 0.0f); geometryCache->renderLine(batch, position, pRight, red, jointLineIDs._right); @@ -466,7 +467,7 @@ float MIN_JOINT_MASS = 1.0f; float VERY_BIG_MASS = 1.0e6f; // virtual -void SkeletonModel::buildShapes() { +void SkeletonModel::computeBoundingShape() { if (_geometry == NULL || _rig->jointStatesEmpty()) { return; } @@ -476,36 +477,87 @@ void SkeletonModel::buildShapes() { // rootJointIndex == -1 if the avatar model has no skeleton return; } - computeBoundingShape(geometry); -} -void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { - // compute default joint transforms - int numStates = _rig->getJointStateCount(); - QVector transforms; - transforms.fill(glm::mat4(), numStates); + // BOUNDING SHAPE HACK: before we measure the bounds of the joints we use IK to put the + // hands and feet into positions that are more correct than the default pose. + + // Measure limb lengths so we can specify IK targets that will pull hands and feet tight to body + QVector endEffectors; + endEffectors.push_back("RightHand"); + endEffectors.push_back("LeftHand"); + endEffectors.push_back("RightFoot"); + endEffectors.push_back("LeftFoot"); + + QVector baseJoints; + baseJoints.push_back("RightArm"); + baseJoints.push_back("LeftArm"); + baseJoints.push_back("RightUpLeg"); + baseJoints.push_back("LeftUpLeg"); + + for (int i = 0; i < endEffectors.size(); ++i) { + QString tipName = endEffectors[i]; + QString baseName = baseJoints[i]; + float limbLength = 0.0f; + int tipIndex = _rig->indexOfJoint(tipName); + if (tipIndex == -1) { + continue; + } + // save tip's relative rotation for later + glm::quat tipRotation = _rig->getJointState(tipIndex).getRotationInConstrainedFrame(); + + // IK on each endpoint + int jointIndex = tipIndex; + QVector freeLineage; + float priority = 1.0f; + while (jointIndex > -1) { + JointState limbJoint = _rig->getJointState(jointIndex); + freeLineage.push_back(jointIndex); + if (limbJoint.getName() == baseName) { + glm::vec3 targetPosition = limbJoint.getPosition() - glm::vec3(0.0f, 1.5f * limbLength, 0.0f); + // do IK a few times to make sure the endpoint gets close to its target + for (int j = 0; j < 5; ++j) { + _rig->inverseKinematics(tipIndex, + targetPosition, + glm::quat(), + priority, + freeLineage, + glm::mat4()); + } + const JointState& movedState = _rig->getJointState(tipIndex); + break; + } + limbLength += limbJoint.getDistanceToParent(); + jointIndex = limbJoint.getParentIndex(); + } + + // since this IK target is totally bogus we restore the tip's relative rotation + _rig->setJointRotationInConstrainedFrame(tipIndex, tipRotation, priority); + } + + // recompute all joint model-frame transforms + glm::mat4 rootTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; + for (int i = 0; i < _rig->getJointStateCount(); i++) { + _rig->updateJointState(i, rootTransform); + } + // END BOUNDING SHAPE HACK // compute bounding box that encloses all shapes Extents totalExtents; totalExtents.reset(); totalExtents.addPoint(glm::vec3(0.0f)); + int numStates = _rig->getJointStateCount(); for (int i = 0; i < numStates; i++) { // compute the default transform of this joint const JointState& state = _rig->getJointState(i); - int parentIndex = state.getParentIndex(); - if (parentIndex == -1) { - transforms[i] = _rig->getJointTransform(i); - } else { - glm::quat modifiedRotation = state.getPreRotation() * state.getDefaultRotation() * state.getPostRotation(); - transforms[i] = transforms[parentIndex] * glm::translate(state.getTranslation()) - * state.getPreTransform() * glm::mat4_cast(modifiedRotation) * state.getPostTransform(); - } - // Each joint contributes a sphere at its position - glm::vec3 axis(state.getBoneRadius()); - glm::vec3 jointPosition = extractTranslation(transforms[i]); - totalExtents.addPoint(jointPosition + axis); - totalExtents.addPoint(jointPosition - axis); + // HACK WORKAROUND: ignore joints that may have bad translation (e.g. have been flagged as such with zero radius) + if (state.getBoneRadius() > 0.0f) { + // Each joint contributes a sphere at its position + glm::vec3 axis(state.getBoneRadius()); + glm::vec3 jointPosition = state.getPosition(); + totalExtents.addPoint(jointPosition + axis); + totalExtents.addPoint(jointPosition - axis); + } } // compute bounding shape parameters @@ -517,6 +569,11 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { glm::vec3 rootPosition = _rig->getJointState(geometry.rootJointIndex).getPosition(); _boundingCapsuleLocalOffset = 0.5f * (totalExtents.maximum + totalExtents.minimum) - rootPosition; + + // RECOVER FROM BOUNINDG SHAPE HACK: now that we're all done, restore the default pose + for (int i = 0; i < numStates; i++) { + _rig->restoreJointRotation(i, 1.0f, 1.0f); + } } void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha) { @@ -535,7 +592,7 @@ void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha glm::vec4(0.6f, 0.6f, 0.8f, alpha)); // draw a yellow sphere at the capsule bottom point - glm::vec3 bottomPoint = topPoint - glm::vec3(0.0f, -_boundingCapsuleHeight, 0.0f); + glm::vec3 bottomPoint = topPoint - glm::vec3(0.0f, _boundingCapsuleHeight, 0.0f); glm::vec3 axis = topPoint - bottomPoint; transform.setTranslation(bottomPoint); batch.setModelTransform(transform); diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 4ae615eadd..75ad728d46 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -94,7 +94,6 @@ public: /// \return whether or not the head was found. glm::vec3 getDefaultEyeModelPosition() const; - void computeBoundingShape(const FBXGeometry& geometry); void renderBoundingCollisionShapes(gpu::Batch& batch, float alpha); float getBoundingCapsuleRadius() const { return _boundingCapsuleRadius; } float getBoundingCapsuleHeight() const { return _boundingCapsuleHeight; } @@ -112,7 +111,7 @@ signals: protected: - void buildShapes(); + void computeBoundingShape(); /// \param jointIndex index of joint in model /// \param position position of joint in model-frame diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index d536bcb608..556953e6e7 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -9,30 +9,31 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "Rig.h" + #include #include #include "AnimationHandle.h" #include "AnimationLogging.h" -#include "Rig.h" void Rig::HeadParameters::dump() const { qCDebug(animation, "HeadParameters ="); - qCDebug(animation, " leanSideways = %0.5f", leanSideways); - qCDebug(animation, " leanForward = %0.5f", leanForward); - qCDebug(animation, " torsoTwist = %0.5f", torsoTwist); + qCDebug(animation, " leanSideways = %0.5f", (double)leanSideways); + qCDebug(animation, " leanForward = %0.5f", (double)leanForward); + qCDebug(animation, " torsoTwist = %0.5f", (double)torsoTwist); glm::vec3 axis = glm::axis(localHeadOrientation); float theta = glm::angle(localHeadOrientation); - qCDebug(animation, " localHeadOrientation axis = (%.5f, %.5f, %.5f), theta = %0.5f", axis.x, axis.y, axis.z, theta); + qCDebug(animation, " localHeadOrientation axis = (%.5f, %.5f, %.5f), theta = %0.5f", (double)axis.x, (double)axis.y, (double)axis.z, (double)theta); axis = glm::axis(worldHeadOrientation); theta = glm::angle(worldHeadOrientation); - qCDebug(animation, " worldHeadOrientation axis = (%.5f, %.5f, %.5f), theta = %0.5f", axis.x, axis.y, axis.z, theta); + qCDebug(animation, " worldHeadOrientation axis = (%.5f, %.5f, %.5f), theta = %0.5f", (double)axis.x, (double)axis.y, (double)axis.z, (double)theta); axis = glm::axis(modelRotation); theta = glm::angle(modelRotation); - qCDebug(animation, " modelRotation axis = (%.5f, %.5f, %.5f), theta = %0.5f", axis.x, axis.y, axis.z, theta); - qCDebug(animation, " modelTranslation = (%.5f, %.5f, %.5f)", modelTranslation.x, modelTranslation.y, modelTranslation.z); - qCDebug(animation, " eyeLookAt = (%.5f, %.5f, %.5f)", eyeLookAt.x, eyeLookAt.y, eyeLookAt.z); - qCDebug(animation, " eyeSaccade = (%.5f, %.5f, %.5f)", eyeSaccade.x, eyeSaccade.y, eyeSaccade.z); + qCDebug(animation, " modelRotation axis = (%.5f, %.5f, %.5f), theta = %0.5f", (double)axis.x, (double)axis.y, (double)axis.z, (double)theta); + qCDebug(animation, " modelTranslation = (%.5f, %.5f, %.5f)", (double)modelTranslation.x, (double)modelTranslation.y, (double)modelTranslation.z); + qCDebug(animation, " eyeLookAt = (%.5f, %.5f, %.5f)", (double)eyeLookAt.x, (double)eyeLookAt.y, (double)eyeLookAt.z); + qCDebug(animation, " eyeSaccade = (%.5f, %.5f, %.5f)", (double)eyeSaccade.x, (double)eyeSaccade.y, (double)eyeSaccade.z); qCDebug(animation, " leanJointIndex = %.d", leanJointIndex); qCDebug(animation, " neckJointIndex = %.d", neckJointIndex); qCDebug(animation, " leftEyeJointIndex = %.d", leftEyeJointIndex); @@ -103,7 +104,7 @@ AnimationHandlePointer Rig::addAnimationByRole(const QString& role, const QStrin const QString& base = "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/"; if (role == "walk") { standard = base + "walk_fwd.fbx"; - } else if (role == "backup") { + } else if (role == "backup") { standard = base + "walk_bwd.fbx"; } else if (role == "leftTurn") { standard = base + "turn_left.fbx"; diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 8bbe8dafd8..6d83a87a1c 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -2677,8 +2677,21 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping foreach (const glm::vec3& vertex, extracted.mesh.vertices) { averageRadius += glm::distance(vertex, averageVertex); } - jointShapeInfo.averageRadius = averageRadius * radiusScale; + jointShapeInfo.averageRadius = averageRadius * radiusScale / (float)jointShapeInfo.numVertices; } + + // BUG: the boneBegin and/or boneEnd are incorrect for meshes that are "connected + // under the bone" without weights. Unfortunately we haven't been able to find it yet. + // Although the the mesh vertices are correct in the model-frame, the joint's transform + // in the same frame is just BAD. + // + // HACK WORKAROUND: prevent these shapes from contributing to the collision capsule by setting + // some key members of jointShapeInfo to zero: + jointShapeInfo.numVertices = 0; + jointShapeInfo.sumVertexWeights = 0.0f; + jointShapeInfo.numVertexWeights = 0; + jointShapeInfo.boneBegin = glm::vec3(0.0f); + jointShapeInfo.averageRadius = 0.0f; } extracted.mesh.isEye = (maxJointIndex == geometry.leftEyeJointIndex || maxJointIndex == geometry.rightEyeJointIndex); @@ -2728,7 +2741,6 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping // the average radius to the average point. if (jointShapeInfo.numVertexWeights == 0 && jointShapeInfo.numVertices > 0) { - jointShapeInfo.averageRadius /= (float)jointShapeInfo.numVertices; joint.boneRadius = jointShapeInfo.averageRadius; } } From a7d57d7c60d0d865df2ae60ac055a32c11c9785c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 1 Sep 2015 14:31:47 -0700 Subject: [PATCH 5/8] cleanup whitespace --- interface/src/avatar/SkeletonModel.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 90c30b41ee..567f9b30ac 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -347,9 +347,9 @@ void SkeletonModel::renderOrientationDirections(gpu::Batch& batch, int jointInde } OrientationLineIDs& jointLineIDs = _jointOrientationLines[jointIndex]; - glm::vec3 pRight = position + orientation * IDENTITY_RIGHT * size; - glm::vec3 pUp = position + orientation * IDENTITY_UP * size; - glm::vec3 pFront = position + orientation * IDENTITY_FRONT * size; + glm::vec3 pRight = position + orientation * IDENTITY_RIGHT * size; + glm::vec3 pU = position + orientation * IDENTITY_UP * size; + glm::vec3 pFront = position + orientation * IDENTITY_FRONT * size; glm::vec3 red(1.0f, 0.0f, 0.0f); geometryCache->renderLine(batch, position, pRight, red, jointLineIDs._right); @@ -478,7 +478,7 @@ void SkeletonModel::computeBoundingShape() { return; } - // BOUNDING SHAPE HACK: before we measure the bounds of the joints we use IK to put the + // BOUNDING SHAPE HACK: before we measure the bounds of the joints we use IK to put the // hands and feet into positions that are more correct than the default pose. // Measure limb lengths so we can specify IK targets that will pull hands and feet tight to body From eb78b39bea5de68b060188283d0e2b9391c8110e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 2 Sep 2015 11:31:05 -0700 Subject: [PATCH 6/8] fix typo that broke build and remove warning --- interface/src/avatar/SkeletonModel.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 567f9b30ac..c7fa674d80 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -348,7 +348,7 @@ void SkeletonModel::renderOrientationDirections(gpu::Batch& batch, int jointInde OrientationLineIDs& jointLineIDs = _jointOrientationLines[jointIndex]; glm::vec3 pRight = position + orientation * IDENTITY_RIGHT * size; - glm::vec3 pU = position + orientation * IDENTITY_UP * size; + glm::vec3 pUp = position + orientation * IDENTITY_UP * size; glm::vec3 pFront = position + orientation * IDENTITY_FRONT * size; glm::vec3 red(1.0f, 0.0f, 0.0f); @@ -523,7 +523,6 @@ void SkeletonModel::computeBoundingShape() { freeLineage, glm::mat4()); } - const JointState& movedState = _rig->getJointState(tipIndex); break; } limbLength += limbJoint.getDistanceToParent(); From 992bd5c9d20e578df833fe7ec406e00e7da0e22b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 2 Sep 2015 11:16:36 -0700 Subject: [PATCH 7/8] fix sixense and vive rotation readings for palms --- interface/src/Application.cpp | 2 +- interface/src/avatar/SkeletonModel.cpp | 4 +--- libraries/avatars/src/HandData.h | 6 +++++- .../src/input-plugins/SixenseManager.cpp | 7 +++++-- .../src/input-plugins/ViveControllerManager.cpp | 13 ++++++------- 5 files changed, 18 insertions(+), 14 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a8781ee308..e0726311c9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4919,7 +4919,7 @@ void Application::setPalmData(Hand* hand, UserInputMapper::PoseValue pose, float // Store the one fingertip in the palm structure so we can track velocity const float FINGER_LENGTH = 0.3f; // meters - const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, FINGER_LENGTH); + const glm::vec3 FINGER_VECTOR(0.0f, FINGER_LENGTH, 0.0f); const glm::vec3 newTipPosition = position + rotation * FINGER_VECTOR; glm::vec3 oldTipPosition = palm->getTipRawPosition(); if (deltaTime > 0.0f) { diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index a2e5908477..6a36a41dc4 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -261,9 +261,7 @@ void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) { // the palm's position must be transformed into the model-frame glm::quat inverseRotation = glm::inverse(_rotation); glm::vec3 palmPosition = inverseRotation * (palm.getPosition() - _translation); - - // the palm's "raw" rotation is already in the model-frame - glm::quat palmRotation = palm.getRawRotation(); + glm::quat palmRotation = inverseRotation * palm.getRotation(); inverseKinematics(jointIndex, palmPosition, palmRotation, PALM_PRIORITY); } diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h index 6388c882c7..c87c840399 100644 --- a/libraries/avatars/src/HandData.h +++ b/libraries/avatars/src/HandData.h @@ -64,12 +64,13 @@ public: bool findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, glm::vec3& penetration, const PalmData*& collidingPalm) const; + glm::quat getBaseOrientation() const; + friend class AvatarData; protected: AvatarData* _owningAvatarData; std::vector _palms; - glm::quat getBaseOrientation() const; glm::vec3 getBasePosition() const; float getBaseScale() const; @@ -95,6 +96,7 @@ public: void setRawRotation(const glm::quat rawRotation) { _rawRotation = rawRotation; }; glm::quat getRawRotation() const { return _rawRotation; } + glm::quat getRotation() const { return _owningHandData->getBaseOrientation() * _rawRotation; } void setRawPosition(const glm::vec3& pos) { _rawPosition = pos; } void setRawVelocity(const glm::vec3& velocity) { _rawVelocity = velocity; } const glm::vec3& getRawVelocity() const { return _rawVelocity; } @@ -147,6 +149,7 @@ public: glm::vec3 getNormal() const; private: + // unless marked otherwise, these are all in the model-frame glm::quat _rawRotation; glm::vec3 _rawPosition; glm::vec3 _rawVelocity; @@ -156,6 +159,7 @@ private: glm::vec3 _tipPosition; glm::vec3 _tipVelocity; glm::vec3 _totalPenetration; // accumulator for per-frame penetrations + unsigned int _controllerButtons; unsigned int _lastControllerButtons; float _trigger; diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp index 579fddcd63..f090db7959 100644 --- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp +++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp @@ -481,6 +481,7 @@ void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, int // Qsh = angleAxis(PI, zAxis) * angleAxis(-PI/2, xAxis) // const glm::vec3 xAxis = glm::vec3(1.0f, 0.0f, 0.0f); + const glm::vec3 yAxis = glm::vec3(0.0f, 1.0f, 0.0f); const glm::vec3 zAxis = glm::vec3(0.0f, 0.0f, 1.0f); const glm::quat sixenseToHand = glm::angleAxis(PI, zAxis) * glm::angleAxis(-PI/2.0f, xAxis); @@ -491,13 +492,15 @@ void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, int const glm::quat preOffset = glm::angleAxis(sign * PI / 2.0f, zAxis); // Finally, there is a post-offset (same for both hands) to get the hand's rest orientation - // (fingers forward, palm down) aligned properly in the avatar's model-frame. - const glm::quat postOffset = glm::angleAxis(PI / 2.0f, xAxis); + // (fingers forward, palm down) aligned properly in the avatar's model-frame, + // and then a flip about the yAxis to get into model-frame. + const glm::quat postOffset = glm::angleAxis(PI, yAxis) * glm::angleAxis(PI / 2.0f, xAxis); // The total rotation of the hand uses the formula: // // rotation = postOffset * Qsh^ * (measuredRotation * preOffset) * Qsh // + // TODO: find a shortcut with fewer rotations. rotation = postOffset * glm::inverse(sixenseToHand) * rotation * preOffset * sixenseToHand; _poseStateMap[makeInput(JointChannel(index)).getChannel()] = UserInputMapper::PoseValue(position, rotation); diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index 082c37a837..5410db11a4 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -362,18 +362,17 @@ void ViveControllerManager::handlePoseEvent(const mat4& mat, int index) { // // Qoffset = glm::inverse(deltaRotation when hand is posed fingers forward, palm down) // - // An approximate offset for the Vive can be obtained by inpection: + // An approximate offset for the Vive can be obtained by inspection: // // Qoffset = glm::inverse(glm::angleAxis(sign * PI/4.0f, zAxis) * glm::angleAxis(PI/2.0f, xAxis)) // - - // Finally there is another flip around the yAxis to re-align from model to Vive space, so the full equation is: + // So the full equation is: // - // Q = yFlip * combinedMeasurement * viveToHand + // Q = combinedMeasurement * viveToHand // - // Q = yFlip * (deltaQ * QOffset) * (yFlip * quarterTurnAboutX) + // Q = (deltaQ * QOffset) * (yFlip * quarterTurnAboutX) // - // Q = yFlip * (deltaQ * inverse(deltaQForAlignedHand)) * (yFlip * quarterTurnAboutX) + // Q = (deltaQ * inverse(deltaQForAlignedHand)) * (yFlip * quarterTurnAboutX) const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); @@ -381,7 +380,7 @@ void ViveControllerManager::handlePoseEvent(const mat4& mat, int index) { const glm::quat signedQuaterZ = glm::angleAxis(sign * PI / 2.0f, glm::vec3(0.0f, 0.0f, 1.0f)); const glm::quat eighthX = glm::angleAxis(PI / 4.0f, glm::vec3(1.0f, 0.0f, 0.0f)); const glm::quat offset = glm::inverse(signedQuaterZ * eighthX); - rotation = yFlip * rotation * offset * yFlip * quarterX; + rotation = rotation * offset * yFlip * quarterX; position += rotation * glm::vec3(0, 0, -CONTROLLER_LENGTH_OFFSET); From c61bc190dee217ad5cf3078c74c532bd3dbc962e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 2 Sep 2015 14:16:02 -0700 Subject: [PATCH 8/8] fix finger and palm-normal directions for JS --- libraries/avatars/src/HandData.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index 9a9b51c1c8..1a9b6775d3 100644 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -114,12 +114,14 @@ float HandData::getBaseScale() const { } glm::vec3 PalmData::getFingerDirection() const { - const glm::vec3 LOCAL_FINGER_DIRECTION(0.0f, 0.0f, 1.0f); + // finger points along yAxis in hand-frame + const glm::vec3 LOCAL_FINGER_DIRECTION(0.0f, 1.0f, 0.0f); return glm::normalize(_owningHandData->localToWorldDirection(_rawRotation * LOCAL_FINGER_DIRECTION)); } glm::vec3 PalmData::getNormal() const { - const glm::vec3 LOCAL_PALM_DIRECTION(0.0f, -1.0f, 0.0f); + // palm normal points along zAxis in hand-frame + const glm::vec3 LOCAL_PALM_DIRECTION(0.0f, 0.0f, 1.0f); return glm::normalize(_owningHandData->localToWorldDirection(_rawRotation * LOCAL_PALM_DIRECTION)); }