diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 1eb87c16f0..c9e099df21 100755 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -760,6 +760,109 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic return result; } +RayToAvatarIntersectionResult AvatarManager::findRayIntersectionOld(const PickRay& ray, + const QScriptValue& avatarIdsToInclude, + const QScriptValue& avatarIdsToDiscard) { + QVector avatarsToInclude = qVectorEntityItemIDFromScriptValue(avatarIdsToInclude); + QVector avatarsToDiscard = qVectorEntityItemIDFromScriptValue(avatarIdsToDiscard); + + return findRayIntersectionVectorOld(ray, avatarsToInclude, avatarsToDiscard); +} + +RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVectorOld(const PickRay& ray, + const QVector& avatarsToInclude, + const QVector& avatarsToDiscard) { + RayToAvatarIntersectionResult result; + if (QThread::currentThread() != thread()) { + BLOCKING_INVOKE_METHOD(const_cast(this), "findRayIntersectionVector", + Q_RETURN_ARG(RayToAvatarIntersectionResult, result), + Q_ARG(const PickRay&, ray), + Q_ARG(const QVector&, avatarsToInclude), + Q_ARG(const QVector&, avatarsToDiscard)); + return result; + } + + // It's better to intersect the ray against the avatar's actual mesh, but this is currently difficult to + // do, because the transformed mesh data only exists over in GPU-land. As a compromise, this code + // intersects against the avatars capsule and then against the (T-pose) mesh. The end effect is that picking + // against the avatar is sort-of right, but you likely wont be able to pick against the arms. + + // TODO -- find a way to extract transformed avatar mesh data from the rendering engine. + + std::vector sortedAvatars; + auto avatarHashCopy = getHashCopy(); + for (auto avatarData : avatarHashCopy) { + auto avatar = std::static_pointer_cast(avatarData); + if ((avatarsToInclude.size() > 0 && !avatarsToInclude.contains(avatar->getID())) || + (avatarsToDiscard.size() > 0 && avatarsToDiscard.contains(avatar->getID()))) { + continue; + } + + float distance = FLT_MAX; +#if 0 + // if we weren't picking against the capsule, we would want to pick against the avatarBounds... + SkeletonModelPointer avatarModel = avatar->getSkeletonModel(); + AABox avatarBounds = avatarModel->getRenderableMeshBound(); + if (avatarBounds.contains(ray.origin)) { + distance = 0.0f; + } + else { + float boundDistance = FLT_MAX; + BoxFace face; + glm::vec3 surfaceNormal; + if (avatarBounds.findRayIntersection(ray.origin, ray.direction, boundDistance, face, surfaceNormal)) { + distance = boundDistance; + } + } +#else + glm::vec3 start; + glm::vec3 end; + float radius; + avatar->getCapsule(start, end, radius); + findRayCapsuleIntersection(ray.origin, ray.direction, start, end, radius, distance); +#endif + + if (distance < FLT_MAX) { + sortedAvatars.emplace_back(distance, avatar); + } + } + + if (sortedAvatars.size() > 1) { + static auto comparator = [](const SortedAvatar& left, const SortedAvatar& right) { return left.first < right.first; }; + std::sort(sortedAvatars.begin(), sortedAvatars.end(), comparator); + } + + for (auto it = sortedAvatars.begin(); it != sortedAvatars.end(); ++it) { + const SortedAvatar& sortedAvatar = *it; + // We can exit once avatarCapsuleDistance > bestDistance + if (sortedAvatar.first > result.distance) { + break; + } + + float distance = FLT_MAX; + BoxFace face; + glm::vec3 surfaceNormal; + QVariantMap extraInfo; + SkeletonModelPointer avatarModel = sortedAvatar.second->getSkeletonModel(); + if (avatarModel->findRayIntersectionAgainstSubMeshes(ray.origin, ray.direction, distance, face, surfaceNormal, extraInfo, true)) { + if (distance < result.distance) { + result.intersects = true; + result.avatarID = sortedAvatar.second->getID(); + result.distance = distance; + result.face = face; + result.surfaceNormal = surfaceNormal; + result.extraInfo = extraInfo; + } + } + } + + if (result.intersects) { + result.intersection = ray.origin + ray.direction * result.distance; + } + + return result; +} + ParabolaToAvatarIntersectionResult AvatarManager::findParabolaIntersectionVector(const PickParabola& pick, const QVector& avatarsToInclude, const QVector& avatarsToDiscard) { diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 50d9e80e8b..66f28206e0 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -157,6 +157,15 @@ public: const QVector& avatarsToDiscard, bool pickAgainstMesh); + Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersectionOld(const PickRay& ray, + const QScriptValue& avatarIdsToInclude = QScriptValue(), + const QScriptValue& avatarIdsToDiscard = QScriptValue()); + + Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersectionVectorOld(const PickRay& ray, + const QVector& avatarsToInclude, + const QVector& avatarsToDiscard); + + /**jsdoc * @function AvatarManager.findParabolaIntersectionVector * @param {PickParabola} pick diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index bc4dca54f2..8a05bdd018 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -34,7 +34,6 @@ #include "IKTarget.h" #include "PathUtils.h" - static int nextRigId = 1; static std::map rigRegistry; static std::mutex rigRegistryMutex; @@ -1871,7 +1870,7 @@ void Rig::initAnimGraph(const QUrl& url) { auto roleState = roleAnimState.second; overrideRoleAnimation(roleState.role, roleState.url, roleState.fps, roleState.loop, roleState.firstFrame, roleState.lastFrame); } - + _flow.setRig(this); emit onLoadComplete(); }); connect(_animLoader.get(), &AnimNodeLoader::error, [url](int error, QString str) { @@ -1903,6 +1902,9 @@ void Rig::initAnimGraph(const QUrl& url) { connect(_networkLoader.get(), &AnimNodeLoader::error, [networkUrl](int error, QString str) { qCritical(animation) << "Error loading: code = " << error << "str =" << str; }); + connect(this, &Rig::onLoadComplete, [&]() { + _flow.calculateConstraints(); + }); } } diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 41c25a3c3e..9bd2ed528a 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -25,6 +25,7 @@ #include "AnimNodeLoader.h" #include "SimpleMovingAverage.h" #include "AnimUtil.h" +#include "Flow.h" class Rig; class AnimInverseKinematics; @@ -233,6 +234,7 @@ public: const AnimContext::DebugAlphaMap& getDebugAlphaMap() const { return _lastContext.getDebugAlphaMap(); } const AnimVariantMap& getAnimVars() const { return _lastAnimVars; } const AnimContext::DebugStateMachineMap& getStateMachineMap() const { return _lastContext.getStateMachineMap(); } + void computeFlowSkeleton() { _flow.calculateConstraints(); } signals: void onLoadComplete(); @@ -424,6 +426,7 @@ protected: SnapshotBlendPoseHelper _hipsBlendHelper; ControllerParameters _previousControllerParameters; + Flow _flow; }; #endif /* defined(__hifi__Rig__) */ diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index b43fe012b7..4ba2ffc07d 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -35,6 +35,7 @@ #include "MetaModelPayload.h" #include "MultiSphereShape.h" +#include "Flow.h" namespace render { template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar); @@ -285,6 +286,8 @@ public: */ Q_INVOKABLE glm::quat jointToWorldRotation(const glm::quat& rotation, const int jointIndex = -1) const; + Q_INVOKABLE void callFlow() { _skeletonModel->getRig().computeFlowSkeleton(); }; + virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override; virtual void setAttachmentData(const QVector& attachmentData) override; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 954462a9f2..47064bdbd3 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -2943,6 +2943,12 @@ int EntityTree::getJointIndex(const QUuid& entityID, const QString& name) const } return entity->getJointIndex(name); } +void EntityTree::callFlowSkeleton(const QUuid& entityID) { + /* + EntityTree* nonConstThis = const_cast(this); + EntityItemPointer entity = nonConstThis->findEntityByEntityItemID(entityID); + */ +} QStringList EntityTree::getJointNames(const QUuid& entityID) const { EntityTree* nonConstThis = const_cast(this); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index f9b7b8d67f..cc80083e0d 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -240,6 +240,7 @@ public: // these are used to call through to EntityItems Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name) const; Q_INVOKABLE QStringList getJointNames(const QUuid& entityID) const; + Q_INVOKABLE void callFlowSkeleton(const QUuid& entityID); void knowAvatarID(QUuid avatarID) { _avatarIDs += avatarID; } void forgetAvatarID(QUuid avatarID) { _avatarIDs -= avatarID; }