From a11bf7f15ba2f7810f3837713a3fc9dba4c7b4db Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 19 Sep 2014 14:26:44 -0700 Subject: [PATCH 1/4] Decouple Rift head tracking from avatar's head position This makes the Rift's view reflect the user's physical movements exactly while the avatar follows the movements as best it can. --- interface/src/Application.cpp | 2 +- interface/src/avatar/Avatar.cpp | 4 ---- interface/src/avatar/Avatar.h | 1 - interface/src/avatar/MyAvatar.cpp | 2 +- interface/src/avatar/SkeletonModel.cpp | 7 +++++++ interface/src/avatar/SkeletonModel.h | 6 ++++++ 6 files changed, 15 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a20a6553d4..00cf3b9d01 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -682,7 +682,7 @@ void Application::paintGL() { if (whichCamera.getMode() == CAMERA_MODE_MIRROR) { OculusManager::display(whichCamera.getRotation(), whichCamera.getPosition(), whichCamera); } else { - OculusManager::display(_myAvatar->getWorldAlignedOrientation(), whichCamera.getPosition(), whichCamera); + OculusManager::display(_myAvatar->getWorldAlignedOrientation(), _myAvatar->getUprightHeadPosition(), whichCamera); } } else if (TV3DManager::isConnected()) { diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 6f421965db..22e7697b40 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -1028,10 +1028,6 @@ float Avatar::getPelvisFloatingHeight() const { return -_skeletonModel.getBindExtents().minimum.y; } -float Avatar::getPelvisToHeadLength() const { - return glm::distance(_position, getHead()->getPosition()); -} - void Avatar::setShowDisplayName(bool showDisplayName) { if (!Menu::getInstance()->isOptionChecked(MenuOption::NamesAboveHeads)) { _displayNameAlpha = 0.0f; diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index c449a0d1b9..58add5aecd 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -223,7 +223,6 @@ protected: float getSkeletonHeight() const; float getHeadHeight() const; float getPelvisFloatingHeight() const; - float getPelvisToHeadLength() const; glm::vec3 getDisplayNamePosition(); void renderDisplayName(); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 27f74f185d..e59de3628a 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -977,7 +977,7 @@ void MyAvatar::clearLookAtTargetAvatar() { } glm::vec3 MyAvatar::getUprightHeadPosition() const { - return _position + getWorldAlignedOrientation() * glm::vec3(0.0f, getPelvisToHeadLength(), 0.0f); + return _position + getWorldAlignedOrientation() * _skeletonModel.getDefaultHeadModelPosition(); } const float SCRIPT_PRIORITY = DEFAULT_PRIORITY + 1.0f; diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 86ca42b15e..2e53412be4 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -656,6 +656,13 @@ void SkeletonModel::buildShapes() { // This method moves the shapes to their default positions in Model frame. computeBoundingShape(geometry); + int headJointIndex = _geometry->getFBXGeometry().headJointIndex; + if (0 <= headJointIndex && headJointIndex < _jointStates.size()) { + getJointPosition(headJointIndex, _defaultHeadModelPosition); + } else { + _defaultHeadModelPosition = glm::vec3(0.f, 0.f, 0.f); + } + // While the shapes are in their default position we disable collisions between // joints that are currently colliding. disableCurrentSelfCollisions(); diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index ca0007ddb4..036811a926 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -97,6 +97,10 @@ public: /// \return whether or not both eye meshes were found bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; + /// Gets the default position of the head in model frame coordinates. + /// \return whether or not the head was found. + glm::vec3 getDefaultHeadModelPosition() const { return _defaultHeadModelPosition; } + virtual void updateVisibleJointStates(); SkeletonRagdoll* buildRagdoll(); @@ -146,6 +150,8 @@ private: CapsuleShape _boundingShape; glm::vec3 _boundingShapeLocalOffset; SkeletonRagdoll* _ragdoll; + + glm::vec3 _defaultHeadModelPosition; }; #endif // hifi_SkeletonModel_h From f95e20153c3a366eb1a04022546290c290ffc926 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 22 Sep 2014 15:13:08 -0700 Subject: [PATCH 2/4] Fix upright head model position calculation for avatar scale changes --- interface/src/avatar/SkeletonModel.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 2e53412be4..9522e54e26 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -658,7 +658,11 @@ void SkeletonModel::buildShapes() { int headJointIndex = _geometry->getFBXGeometry().headJointIndex; if (0 <= headJointIndex && headJointIndex < _jointStates.size()) { + int rootJointIndex = _geometry->getFBXGeometry().rootJointIndex; + glm::vec3 rootModelPosition; getJointPosition(headJointIndex, _defaultHeadModelPosition); + getJointPosition(rootJointIndex, rootModelPosition); + _defaultHeadModelPosition = _defaultHeadModelPosition - rootModelPosition; } else { _defaultHeadModelPosition = glm::vec3(0.f, 0.f, 0.f); } From aa9511c263bbb8cd046392fce30589ede794788d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 25 Sep 2014 22:49:12 -0700 Subject: [PATCH 3/4] Position Rift camera at avatar model's mid-eye location --- interface/src/Application.cpp | 2 +- interface/src/avatar/Avatar.cpp | 4 +++ interface/src/avatar/Avatar.h | 1 + interface/src/avatar/MyAvatar.cpp | 6 ++++- interface/src/avatar/MyAvatar.h | 1 + interface/src/avatar/SkeletonModel.cpp | 34 ++++++++++++++++++-------- interface/src/avatar/SkeletonModel.h | 8 +++--- interface/src/renderer/Model.cpp | 8 ++++++ interface/src/renderer/Model.h | 5 ++++ 9 files changed, 54 insertions(+), 15 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 00cf3b9d01..03743c5f69 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -682,7 +682,7 @@ void Application::paintGL() { if (whichCamera.getMode() == CAMERA_MODE_MIRROR) { OculusManager::display(whichCamera.getRotation(), whichCamera.getPosition(), whichCamera); } else { - OculusManager::display(_myAvatar->getWorldAlignedOrientation(), _myAvatar->getUprightHeadPosition(), whichCamera); + OculusManager::display(_myAvatar->getWorldAlignedOrientation(), _myAvatar->getDefaultEyePosition(), whichCamera); } } else if (TV3DManager::isConnected()) { diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 22e7697b40..6f421965db 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -1028,6 +1028,10 @@ float Avatar::getPelvisFloatingHeight() const { return -_skeletonModel.getBindExtents().minimum.y; } +float Avatar::getPelvisToHeadLength() const { + return glm::distance(_position, getHead()->getPosition()); +} + void Avatar::setShowDisplayName(bool showDisplayName) { if (!Menu::getInstance()->isOptionChecked(MenuOption::NamesAboveHeads)) { _displayNameAlpha = 0.0f; diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 58add5aecd..c449a0d1b9 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -223,6 +223,7 @@ protected: float getSkeletonHeight() const; float getHeadHeight() const; float getPelvisFloatingHeight() const; + float getPelvisToHeadLength() const; glm::vec3 getDisplayNamePosition(); void renderDisplayName(); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e59de3628a..2f6b728a24 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -977,7 +977,11 @@ void MyAvatar::clearLookAtTargetAvatar() { } glm::vec3 MyAvatar::getUprightHeadPosition() const { - return _position + getWorldAlignedOrientation() * _skeletonModel.getDefaultHeadModelPosition(); + return _position + getWorldAlignedOrientation() * glm::vec3(0.0f, getPelvisToHeadLength(), 0.0f); +} + +glm::vec3 MyAvatar::getDefaultEyePosition() const { + return _position + getWorldAlignedOrientation() * _skeletonModel.getDefaultEyeModelPosition(); } const float SCRIPT_PRIORITY = DEFAULT_PRIORITY + 1.0f; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index d553d4f367..249e1f91b0 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -66,6 +66,7 @@ public: const glm::vec3& getMouseRayDirection() const { return _mouseRayDirection; } glm::vec3 getGravity() const { return _gravity; } glm::vec3 getUprightHeadPosition() const; + glm::vec3 getDefaultEyePosition() const; bool getShouldRenderLocally() const { return _shouldRender; } const QList& getAnimationHandles() const { return _animationHandles; } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 9522e54e26..ca60ff8ac0 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -470,23 +470,23 @@ bool SkeletonModel::getNeckParentRotationFromDefaultOrientation(glm::quat& neckP return success; } -bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const { +bool SkeletonModel::getEyeModelPositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const { if (!isActive()) { return false; - } + } const FBXGeometry& geometry = _geometry->getFBXGeometry(); - if (getJointPositionInWorldFrame(geometry.leftEyeJointIndex, firstEyePosition) && - getJointPositionInWorldFrame(geometry.rightEyeJointIndex, secondEyePosition)) { + if (getJointPosition(geometry.leftEyeJointIndex, firstEyePosition) && + getJointPosition(geometry.rightEyeJointIndex, secondEyePosition)) { return true; } // no eye joints; try to estimate based on head/neck joints glm::vec3 neckPosition, headPosition; - if (getJointPositionInWorldFrame(geometry.neckJointIndex, neckPosition) && - getJointPositionInWorldFrame(geometry.headJointIndex, headPosition)) { + if (getJointPosition(geometry.neckJointIndex, neckPosition) && + getJointPosition(geometry.headJointIndex, headPosition)) { const float EYE_PROPORTION = 0.6f; glm::vec3 baseEyePosition = glm::mix(neckPosition, headPosition, EYE_PROPORTION); glm::quat headRotation; - getJointRotationInWorldFrame(geometry.headJointIndex, headRotation); + getJointRotation(geometry.headJointIndex, headRotation); const float EYES_FORWARD = 0.25f; const float EYE_SEPARATION = 0.1f; float headHeight = glm::distance(neckPosition, headPosition); @@ -497,6 +497,15 @@ bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& seco return false; } +bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const { + if (getEyeModelPositions(firstEyePosition, secondEyePosition)) { + firstEyePosition = _translation + _rotation * firstEyePosition; + secondEyePosition = _translation + _rotation * secondEyePosition; + return true; + } + return false; +} + void SkeletonModel::renderRagdoll() { if (!_ragdoll) { return; @@ -658,13 +667,18 @@ void SkeletonModel::buildShapes() { int headJointIndex = _geometry->getFBXGeometry().headJointIndex; if (0 <= headJointIndex && headJointIndex < _jointStates.size()) { + glm::vec3 leftEyePosition, rightEyePosition; + getEyeModelPositions(leftEyePosition, rightEyePosition); + glm::vec3 midEyePosition = (leftEyePosition + rightEyePosition) / 2.f; + int rootJointIndex = _geometry->getFBXGeometry().rootJointIndex; glm::vec3 rootModelPosition; - getJointPosition(headJointIndex, _defaultHeadModelPosition); getJointPosition(rootJointIndex, rootModelPosition); - _defaultHeadModelPosition = _defaultHeadModelPosition - rootModelPosition; + + _defaultEyeModelPosition = midEyePosition - rootModelPosition; + _defaultEyeModelPosition.z = -_defaultEyeModelPosition.z; } else { - _defaultHeadModelPosition = glm::vec3(0.f, 0.f, 0.f); + _defaultEyeModelPosition = glm::vec3(0.f, 0.f, 0.f); } // While the shapes are in their default position we disable collisions between diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 036811a926..35122d5e18 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -97,9 +97,9 @@ public: /// \return whether or not both eye meshes were found bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; - /// Gets the default position of the head in model frame coordinates. + /// Gets the default position of the mid eye point in model frame coordinates. /// \return whether or not the head was found. - glm::vec3 getDefaultHeadModelPosition() const { return _defaultHeadModelPosition; } + glm::vec3 getDefaultEyeModelPosition() const { return _defaultEyeModelPosition; } virtual void updateVisibleJointStates(); @@ -144,6 +144,8 @@ private: /// \param position position of joint in model-frame /// \param rotation rotation of joint in model-frame void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation); + + bool getEyeModelPositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; Avatar* _owningAvatar; @@ -151,7 +153,7 @@ private: glm::vec3 _boundingShapeLocalOffset; SkeletonRagdoll* _ragdoll; - glm::vec3 _defaultHeadModelPosition; + glm::vec3 _defaultEyeModelPosition; }; #endif // hifi_SkeletonModel_h diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 19d711a69d..e4ab8b24d9 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -768,6 +768,14 @@ bool Model::getJointRotationInWorldFrame(int jointIndex, glm::quat& rotation) co return true; } +bool Model::getJointRotation(int jointIndex, glm::quat& rotation) const { + if (jointIndex == -1 || jointIndex >= _jointStates.size()) { + return false; + } + rotation = _jointStates[jointIndex].getRotation(); + return true; +} + bool Model::getJointCombinedRotation(int jointIndex, glm::quat& rotation) const { if (jointIndex == -1 || jointIndex >= _jointStates.size()) { return false; diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 63b2058a20..2361133878 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -153,6 +153,11 @@ public: /// \return true if joint exists bool getJointPosition(int jointIndex, glm::vec3& position) const; + /// \param jointIndex index of joint in model structure + /// \param rotation[out] rotation of joint in model-frame + /// \return true if joint exists + bool getJointRotation(int jointIndex, glm::quat& rotation) const; + QStringList getJointNames() const; AnimationHandlePointer createAnimationHandle(); From c0419c61f437cc503a459d9fbdd735e6f5edf036 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 26 Sep 2014 09:15:17 -0700 Subject: [PATCH 4/4] Fix missing constructor initialization --- interface/src/avatar/SkeletonModel.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index ca60ff8ac0..1af5cfc893 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -27,7 +27,8 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) : _owningAvatar(owningAvatar), _boundingShape(), _boundingShapeLocalOffset(0.0f), - _ragdoll(NULL) { + _ragdoll(NULL), + _defaultEyeModelPosition(glm::vec3(0.f, 0.f, 0.f)) { } SkeletonModel::~SkeletonModel() { @@ -677,8 +678,6 @@ void SkeletonModel::buildShapes() { _defaultEyeModelPosition = midEyePosition - rootModelPosition; _defaultEyeModelPosition.z = -_defaultEyeModelPosition.z; - } else { - _defaultEyeModelPosition = glm::vec3(0.f, 0.f, 0.f); } // While the shapes are in their default position we disable collisions between