From 43244193e889e539b2a65eaab4bd9b274142769f Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Fri, 18 Jan 2019 12:46:18 -0700 Subject: [PATCH] Mesh picking against default pose with transformed ray --- interface/src/avatar/AvatarManager.cpp | 42 +++++++++-- interface/src/avatar/AvatarManager.h | 6 +- interface/src/avatar/MyAvatar.cpp | 71 ------------------ interface/src/avatar/MyAvatar.h | 50 ------------- interface/src/raypick/RayPick.cpp | 2 +- .../src/avatars-renderer/Avatar.cpp | 73 +++++++++++++++++++ .../src/avatars-renderer/Avatar.h | 51 +++++++++++++ 7 files changed, 165 insertions(+), 130 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 548b3d44a5..2c6f51cd4a 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -43,6 +43,7 @@ #include "InterfaceLogging.h" #include "Menu.h" #include "MyAvatar.h" +#include "DebugDraw.h" #include "SceneScriptingInterface.h" // 50 times per second - target is 45hz, but this helps account for any small deviations @@ -641,18 +642,20 @@ AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID) RayToAvatarIntersectionResult AvatarManager::findRayIntersection(const PickRay& ray, const QScriptValue& avatarIdsToInclude, const QScriptValue& avatarIdsToDiscard, - const QScriptValue& jointIndicesToFilter) { + const QScriptValue& jointIndicesToFilter, + bool pickAgainstMesh) { QVector avatarsToInclude = qVectorEntityItemIDFromScriptValue(avatarIdsToInclude); QVector avatarsToDiscard = qVectorEntityItemIDFromScriptValue(avatarIdsToDiscard); QVector jointsToFilter; qVectorIntFromScriptValue(jointIndicesToFilter, jointsToFilter); - return findRayIntersectionVector(ray, avatarsToInclude, avatarsToDiscard, jointsToFilter); + return findRayIntersectionVector(ray, avatarsToInclude, avatarsToDiscard, jointsToFilter, pickAgainstMesh); } RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const PickRay& ray, const QVector& avatarsToInclude, const QVector& avatarsToDiscard, - const QVector& jointIndicesToFilter) { + const QVector& jointIndicesToFilter, + bool pickAgainstMesh) { RayToAvatarIntersectionResult result; if (QThread::currentThread() != thread()) { BLOCKING_INVOKE_METHOD(const_cast(this), "findRayIntersectionVector", @@ -660,7 +663,8 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic Q_ARG(const PickRay&, ray), Q_ARG(const QVector&, avatarsToInclude), Q_ARG(const QVector&, avatarsToDiscard), - Q_ARG(const QVector&, jointIndicesToFilter)); + Q_ARG(const QVector&, jointIndicesToFilter), + Q_ARG(bool, pickAgainstMesh)); return result; } @@ -673,7 +677,9 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic glm::vec3 surfaceNormal; QVariantMap extraInfo; std::vector physicsResults = _myAvatar->getCharacterController()->rayTest(glmToBullet(ray.origin), glmToBullet(ray.direction), distance, QVector()); - + glm::vec3 transformedRayPoint; + glm::vec3 transformedRayDirection; + if (physicsResults.size() > 0) { MyCharacterController::RayAvatarResult rayAvatarResult; AvatarPointer avatar = nullptr; @@ -752,13 +758,37 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic } } } + if (rayAvatarResult._intersect) { + if (pickAgainstMesh) { + glm::vec3 localRayOrigin = avatar->worldToJointPoint(ray.origin, rayAvatarResult._intersectWithJoint); + glm::vec3 localRayPoint = avatar->worldToJointPoint(ray.origin + ray.direction, rayAvatarResult._intersectWithJoint); + + auto avatarOrientation = avatar->getWorldOrientation(); + auto avatarPosition = avatar->getWorldPosition(); + + auto jointOrientation = avatarOrientation * avatar->getAbsoluteDefaultJointRotationInObjectFrame(rayAvatarResult._intersectWithJoint); + auto jointPosition = avatarPosition + (avatarOrientation * avatar->getAbsoluteDefaultJointTranslationInObjectFrame(rayAvatarResult._intersectWithJoint)); + + auto defaultFrameRayOrigin = jointPosition + jointOrientation * localRayOrigin; + auto defaultFrameRayPoint = jointPosition + jointOrientation * localRayPoint; + auto defaultFrameRayDirection = defaultFrameRayPoint - defaultFrameRayOrigin; + + if (avatar->getSkeletonModel()->findRayIntersectionAgainstSubMeshes(defaultFrameRayOrigin, defaultFrameRayDirection, distance, face, surfaceNormal, extraInfo, true, false)) { + auto newDistance = glm::length(vec3FromVariant(extraInfo["worldIntersectionPoint"]) - defaultFrameRayOrigin); + rayAvatarResult._distance = newDistance; + rayAvatarResult._intersectionPoint = ray.origin + newDistance * glm::normalize(ray.direction); + rayAvatarResult._intersectionNormal = surfaceNormal; + extraInfo["worldIntersectionPoint"] = vec3toVariant(rayAvatarResult._intersectionPoint); + } + } + result.intersects = true; result.avatarID = rayAvatarResult._intersectWithAvatar; result.distance = rayAvatarResult._distance; result.surfaceNormal = rayAvatarResult._intersectionNormal; result.jointIndex = rayAvatarResult._intersectWithJoint; - result.intersection = rayAvatarResult._intersectionPoint; + result.intersection = ray.origin + rayAvatarResult._distance * glm::normalize(ray.direction); result.extraInfo = extraInfo; result.face = face; } diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 93be716087..5bc31d74b3 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -144,7 +144,8 @@ public: Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersection(const PickRay& ray, const QScriptValue& avatarIdsToInclude = QScriptValue(), const QScriptValue& avatarIdsToDiscard = QScriptValue(), - const QScriptValue& jointIndicesToFilter = QScriptValue()); + const QScriptValue& jointIndicesToFilter = QScriptValue(), + bool pickAgainstMesh = false); /**jsdoc * @function AvatarManager.findRayIntersectionVector * @param {PickRay} ray @@ -156,7 +157,8 @@ public: Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersectionVector(const PickRay& ray, const QVector& avatarsToInclude, const QVector& avatarsToDiscard, - const QVector& jointIndicesToFilter); + const QVector& jointIndicesToFilter, + bool pickAgainstMesh); /**jsdoc * @function AvatarManager.findParabolaIntersectionVector diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 670444baf0..641b2dff00 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1122,77 +1122,6 @@ controller::Pose MyAvatar::getRightHandTipPose() const { return pose; } -glm::vec3 MyAvatar::worldToJointPoint(const glm::vec3& position, const int jointIndex) const { - glm::vec3 jointPos = getWorldPosition();//default value if no or invalid joint specified - glm::quat jointRot = getWorldOrientation();//default value if no or invalid joint specified - if (jointIndex != -1) { - if (_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPos)) { - _skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot); - } else { - qWarning() << "Invalid joint index specified: " << jointIndex; - } - } - glm::vec3 modelOffset = position - jointPos; - glm::vec3 jointSpacePosition = glm::inverse(jointRot) * modelOffset; - - return jointSpacePosition; -} - -glm::vec3 MyAvatar::worldToJointDirection(const glm::vec3& worldDir, const int jointIndex) const { - glm::quat jointRot = getWorldOrientation();//default value if no or invalid joint specified - if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) { - qWarning() << "Invalid joint index specified: " << jointIndex; - } - - glm::vec3 jointSpaceDir = glm::inverse(jointRot) * worldDir; - return jointSpaceDir; -} - -glm::quat MyAvatar::worldToJointRotation(const glm::quat& worldRot, const int jointIndex) const { - glm::quat jointRot = getWorldOrientation();//default value if no or invalid joint specified - if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) { - qWarning() << "Invalid joint index specified: " << jointIndex; - } - glm::quat jointSpaceRot = glm::inverse(jointRot) * worldRot; - return jointSpaceRot; -} - -glm::vec3 MyAvatar::jointToWorldPoint(const glm::vec3& jointSpacePos, const int jointIndex) const { - glm::vec3 jointPos = getWorldPosition();//default value if no or invalid joint specified - glm::quat jointRot = getWorldOrientation();//default value if no or invalid joint specified - - if (jointIndex != -1) { - if (_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPos)) { - _skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot); - } else { - qWarning() << "Invalid joint index specified: " << jointIndex; - } - } - - glm::vec3 worldOffset = jointRot * jointSpacePos; - glm::vec3 worldPos = jointPos + worldOffset; - - return worldPos; -} - -glm::vec3 MyAvatar::jointToWorldDirection(const glm::vec3& jointSpaceDir, const int jointIndex) const { - glm::quat jointRot = getWorldOrientation();//default value if no or invalid joint specified - if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) { - qWarning() << "Invalid joint index specified: " << jointIndex; - } - glm::vec3 worldDir = jointRot * jointSpaceDir; - return worldDir; -} - -glm::quat MyAvatar::jointToWorldRotation(const glm::quat& jointSpaceRot, const int jointIndex) const { - glm::quat jointRot = getWorldOrientation();//default value if no or invalid joint specified - if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) { - qWarning() << "Invalid joint index specified: " << jointIndex; - } - glm::quat worldRot = jointRot * jointSpaceRot; - return worldRot; -} - // virtual void MyAvatar::render(RenderArgs* renderArgs) { // don't render if we've been asked to disable local rendering diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index f107a488a6..5bc9c14f1d 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -784,56 +784,6 @@ public: */ Q_INVOKABLE controller::Pose getRightHandTipPose() const; - // world-space to avatar-space rigconversion functions - /**jsdoc - * @function MyAvatar.worldToJointPoint - * @param {Vec3} position - * @param {number} [jointIndex=-1] - * @returns {Vec3} - */ - Q_INVOKABLE glm::vec3 worldToJointPoint(const glm::vec3& position, const int jointIndex = -1) const; - - /**jsdoc - * @function MyAvatar.worldToJointDirection - * @param {Vec3} direction - * @param {number} [jointIndex=-1] - * @returns {Vec3} - */ - Q_INVOKABLE glm::vec3 worldToJointDirection(const glm::vec3& direction, const int jointIndex = -1) const; - - /**jsdoc - * @function MyAvatar.worldToJointRotation - * @param {Quat} rotation - * @param {number} [jointIndex=-1] - * @returns {Quat} - */ - Q_INVOKABLE glm::quat worldToJointRotation(const glm::quat& rotation, const int jointIndex = -1) const; - - - /**jsdoc - * @function MyAvatar.jointToWorldPoint - * @param {vec3} position - * @param {number} [jointIndex=-1] - * @returns {Vec3} - */ - Q_INVOKABLE glm::vec3 jointToWorldPoint(const glm::vec3& position, const int jointIndex = -1) const; - - /**jsdoc - * @function MyAvatar.jointToWorldDirection - * @param {Vec3} direction - * @param {number} [jointIndex=-1] - * @returns {Vec3} - */ - Q_INVOKABLE glm::vec3 jointToWorldDirection(const glm::vec3& direction, const int jointIndex = -1) const; - - /**jsdoc - * @function MyAvatar.jointToWorldRotation - * @param {Quat} rotation - * @param {number} [jointIndex=-1] - * @returns {Quat} - */ - Q_INVOKABLE glm::quat jointToWorldRotation(const glm::quat& rotation, const int jointIndex = -1) const; - AvatarWeakPointer getLookAtTargetAvatar() const { return _lookAtTargetAvatar; } void updateLookAtTargetAvatar(); void computeMyLookAtTarget(const AvatarHash& hash); diff --git a/interface/src/raypick/RayPick.cpp b/interface/src/raypick/RayPick.cpp index 85ffc97450..7d6c0b6eef 100644 --- a/interface/src/raypick/RayPick.cpp +++ b/interface/src/raypick/RayPick.cpp @@ -56,7 +56,7 @@ PickResultPointer RayPick::getOverlayIntersection(const PickRay& pick) { } PickResultPointer RayPick::getAvatarIntersection(const PickRay& pick) { - RayToAvatarIntersectionResult avatarRes = DependencyManager::get()->findRayIntersectionVector(pick, getIncludeItemsAs(), getIgnoreItemsAs(), QVector()); + RayToAvatarIntersectionResult avatarRes = DependencyManager::get()->findRayIntersectionVector(pick, getIncludeItemsAs(), getIgnoreItemsAs(), QVector(), false); if (avatarRes.intersects) { return std::make_shared(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, pick, avatarRes.surfaceNormal, avatarRes.extraInfo); } else { diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index f2252b2aa3..a34c17550f 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -1283,6 +1283,79 @@ glm::vec3 Avatar::getAbsoluteJointScaleInObjectFrame(int index) const { } } + +glm::vec3 Avatar::worldToJointPoint(const glm::vec3& position, const int jointIndex) const { + glm::vec3 jointPos = getWorldPosition();//default value if no or invalid joint specified + glm::quat jointRot = getWorldOrientation();//default value if no or invalid joint specified + if (jointIndex != -1) { + if (_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPos)) { + _skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot); + } else { + qWarning() << "Invalid joint index specified: " << jointIndex; + } + } + glm::vec3 modelOffset = position - jointPos; + glm::vec3 jointSpacePosition = glm::inverse(jointRot) * modelOffset; + + return jointSpacePosition; +} + +glm::vec3 Avatar::worldToJointDirection(const glm::vec3& worldDir, const int jointIndex) const { + glm::quat jointRot = getWorldOrientation();//default value if no or invalid joint specified + if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) { + qWarning() << "Invalid joint index specified: " << jointIndex; + } + + glm::vec3 jointSpaceDir = glm::inverse(jointRot) * worldDir; + return jointSpaceDir; +} + +glm::quat Avatar::worldToJointRotation(const glm::quat& worldRot, const int jointIndex) const { + glm::quat jointRot = getWorldOrientation();//default value if no or invalid joint specified + if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) { + qWarning() << "Invalid joint index specified: " << jointIndex; + } + glm::quat jointSpaceRot = glm::inverse(jointRot) * worldRot; + return jointSpaceRot; +} + +glm::vec3 Avatar::jointToWorldPoint(const glm::vec3& jointSpacePos, const int jointIndex) const { + glm::vec3 jointPos = getWorldPosition();//default value if no or invalid joint specified + glm::quat jointRot = getWorldOrientation();//default value if no or invalid joint specified + + if (jointIndex != -1) { + if (_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPos)) { + _skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot); + } else { + qWarning() << "Invalid joint index specified: " << jointIndex; + } + } + + glm::vec3 worldOffset = jointRot * jointSpacePos; + glm::vec3 worldPos = jointPos + worldOffset; + + return worldPos; +} + +glm::vec3 Avatar::jointToWorldDirection(const glm::vec3& jointSpaceDir, const int jointIndex) const { + glm::quat jointRot = getWorldOrientation();//default value if no or invalid joint specified + if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) { + qWarning() << "Invalid joint index specified: " << jointIndex; + } + glm::vec3 worldDir = jointRot * jointSpaceDir; + return worldDir; +} + +glm::quat Avatar::jointToWorldRotation(const glm::quat& jointSpaceRot, const int jointIndex) const { + glm::quat jointRot = getWorldOrientation();//default value if no or invalid joint specified + if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) { + qWarning() << "Invalid joint index specified: " << jointIndex; + } + glm::quat worldRot = jointRot * jointSpaceRot; + return worldRot; +} + + void Avatar::invalidateJointIndicesCache() const { QWriteLocker writeLock(&_modelJointIndicesCacheLock); _modelJointsCached = false; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index db2908fc5d..c0c61992b1 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -223,12 +223,63 @@ public: */ Q_INVOKABLE virtual glm::vec3 getAbsoluteDefaultJointTranslationInObjectFrame(int index) const; + virtual glm::vec3 getAbsoluteJointScaleInObjectFrame(int index) const override; virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override; virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override; virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; } virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override { return false; } + // world-space to avatar-space rigconversion functions + /**jsdoc + * @function MyAvatar.worldToJointPoint + * @param {Vec3} position + * @param {number} [jointIndex=-1] + * @returns {Vec3} + */ + Q_INVOKABLE glm::vec3 worldToJointPoint(const glm::vec3& position, const int jointIndex = -1) const; + + /**jsdoc + * @function MyAvatar.worldToJointDirection + * @param {Vec3} direction + * @param {number} [jointIndex=-1] + * @returns {Vec3} + */ + Q_INVOKABLE glm::vec3 worldToJointDirection(const glm::vec3& direction, const int jointIndex = -1) const; + + /**jsdoc + * @function MyAvatar.worldToJointRotation + * @param {Quat} rotation + * @param {number} [jointIndex=-1] + * @returns {Quat} + */ + Q_INVOKABLE glm::quat worldToJointRotation(const glm::quat& rotation, const int jointIndex = -1) const; + + + /**jsdoc + * @function MyAvatar.jointToWorldPoint + * @param {vec3} position + * @param {number} [jointIndex=-1] + * @returns {Vec3} + */ + Q_INVOKABLE glm::vec3 jointToWorldPoint(const glm::vec3& position, const int jointIndex = -1) const; + + /**jsdoc + * @function MyAvatar.jointToWorldDirection + * @param {Vec3} direction + * @param {number} [jointIndex=-1] + * @returns {Vec3} + */ + Q_INVOKABLE glm::vec3 jointToWorldDirection(const glm::vec3& direction, const int jointIndex = -1) const; + + /**jsdoc + * @function MyAvatar.jointToWorldRotation + * @param {Quat} rotation + * @param {number} [jointIndex=-1] + * @returns {Quat} + */ + Q_INVOKABLE glm::quat jointToWorldRotation(const glm::quat& rotation, const int jointIndex = -1) const; + virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override; virtual void setAttachmentData(const QVector& attachmentData) override;