From 916a99c670f7f13666ce1d145b99f8b7acef5168 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 12 Jul 2017 17:12:25 -0700 Subject: [PATCH] added JS/C++ RayPickResult, working on RayPickManager::update --- interface/src/raypick/LaserPointer.cpp | 4 + interface/src/raypick/LaserPointer.h | 4 + interface/src/raypick/LaserPointerManager.cpp | 10 +- interface/src/raypick/LaserPointerManager.h | 2 + .../raypick/LaserPointerScriptingInterface.h | 3 +- interface/src/raypick/RayPick.h | 6 +- interface/src/raypick/RayPickManager.cpp | 113 ++++++++++++------ interface/src/raypick/RayPickManager.h | 28 +---- libraries/shared/src/RegisteredMetaTypes.cpp | 18 +++ libraries/shared/src/RegisteredMetaTypes.h | 15 +++ 10 files changed, 137 insertions(+), 66 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 898df04345..b190539607 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -32,4 +32,8 @@ void LaserPointer::disable() { RayPickManager::getInstance().disableRayPick(_rayPickUID); // TODO: // turn off rendering +} + +const RayPickResult& LaserPointer::getPrevRayPickResult() { + return RayPickManager::getInstance().getPrevRayPickResult(_rayPickUID); } \ No newline at end of file diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index 93dd33f305..a65c6a9748 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -14,6 +14,8 @@ #include #include "glm/glm.hpp" +class RayPickResult; + class LaserPointer { public: @@ -27,6 +29,8 @@ public: // void setRenderState(const QString& stateName); // void setRenderStateProperties(const QHash& renderStateProperties); + const RayPickResult& getPrevRayPickResult(); + private: unsigned int _rayPickUID; }; diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index 1be2087ffb..2e7b084d73 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -10,6 +10,7 @@ // #include "LaserPointerManager.h" #include "LaserPointer.h" +#include "RayPick.h" LaserPointerManager& LaserPointerManager::getInstance() { static LaserPointerManager instance; @@ -33,4 +34,11 @@ void LaserPointerManager::disableLaserPointer(const unsigned int uid) { if (_laserPointers.contains(uid)) { _laserPointers[uid]->disable(); } -} \ No newline at end of file +} + +const RayPickResult& LaserPointerManager::getPrevRayPickResult(const unsigned int uid) { + if (_laserPointers.contains(uid)) { + return _laserPointers[uid]->getPrevRayPickResult(); + } + return RayPickResult(); +} diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index 503db5e459..f8b3ae1a26 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -17,6 +17,7 @@ #include class LaserPointer; +class RayPickResult; class LaserPointerManager { @@ -27,6 +28,7 @@ public: void removeLaserPointer(const unsigned int uid) { _laserPointers.remove(uid); } void enableLaserPointer(const unsigned int uid); void disableLaserPointer(const unsigned int uid); + const RayPickResult& getPrevRayPickResult(const unsigned int uid); private: QHash> _laserPointers; diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index 428d722bbb..8d6758119a 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -14,6 +14,7 @@ #include #include "LaserPointerManager.h" +#include "RegisteredMetaTypes.h" class LaserPointerScriptingInterface : public QObject { Q_OBJECT @@ -26,7 +27,7 @@ public slots: Q_INVOKABLE void enableLaserPointer(unsigned int uid) { LaserPointerManager::getInstance().enableLaserPointer(uid); } Q_INVOKABLE void disableLaserPointer(unsigned int uid) { LaserPointerManager::getInstance().disableLaserPointer(uid); } Q_INVOKABLE void removeLaserPointer(unsigned int uid) { LaserPointerManager::getInstance().removeLaserPointer(uid); } - //Q_INVOKABLE IntersectionResults getLaserPointerCollisionResults(unsigned int uid) { LaserPointerManager::getInstance().getLaserPointerCollisionResults(uid); } + Q_INVOKABLE RayPickResult getPrevRayPickResult(unsigned int uid) { return LaserPointerManager::getInstance().getPrevRayPickResult(uid); } }; diff --git a/interface/src/raypick/RayPick.h b/interface/src/raypick/RayPick.h index 7ad2d9f83f..512512dc2f 100644 --- a/interface/src/raypick/RayPick.h +++ b/interface/src/raypick/RayPick.h @@ -27,15 +27,15 @@ public: const uint16_t getFilter() { return _filter; } const float getMaxDistance() { return _maxDistance; } const bool isEnabled() { return _enabled; } - //const IntersectionResult& getLastIntersectionResult() { return _prevIntersectionResult; } + const RayPickResult& getPrevRayPickResult() { return _prevResult; } - //void setIntersectionResult(const IntersectionResult& intersectionResult) { _prevIntersectionResult = intersectionResult; } + void setRayPickResult(const RayPickResult& rayPickResult) { _prevResult = rayPickResult; } private: uint16_t _filter; float _maxDistance; bool _enabled; - //IntersectionResult _prevIntersectionResult; // set to invalid on disable()? + RayPickResult _prevResult; }; diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index bb25c8f168..5a242c4f3b 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -9,12 +9,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "RayPickManager.h" + #include "RayPick.h" #include "Application.h" #include "EntityScriptingInterface.h" #include "ui/overlays/Overlays.h" #include "avatar/AvatarManager.h" +#include "scripting/HMDScriptingInterface.h" #include "DependencyManager.h" RayPickManager& RayPickManager::getInstance() { @@ -23,9 +25,9 @@ RayPickManager& RayPickManager::getInstance() { } // Returns true if this ray exists in the cache, and if it does, update res if the cached result is closer -bool RayPickManager::checkAndCompareCachedResults(std::shared_ptr rayPick, QPair& ray, QHash, QHash> cache, RayPickResult& res, unsigned int mask) { +bool RayPickManager::checkAndCompareCachedResults(QPair& ray, QHash, QHash>& cache, RayPickResult& res, unsigned int mask) { if (cache.contains(ray) && cache[ray].contains(mask)) { - if (cache[ray][mask].getDistance() < res.getDistance() && cache[ray][mask].getDistance() < rayPick->getMaxDistance()) { + if (cache[ray][mask].distance < res.distance) { res = cache[ray][mask]; } return true; @@ -33,6 +35,18 @@ bool RayPickManager::checkAndCompareCachedResults(std::shared_ptr rayPi return false; } +void RayPickManager::cacheResult(const bool intersects, const RayPickResult& resTemp, unsigned int mask, RayPickResult& res, + QPair& ray, QHash, QHash>& cache) { + if (intersects) { + cache[ray][mask] = resTemp; + if (resTemp.distance < res.distance) { + res = resTemp; + } + } else { + cache[ray][mask] = RayPickResult(); + } +} + void RayPickManager::update() { QHash, QHash> results; for (auto &rayPick : _rayPicks) { @@ -44,74 +58,92 @@ void RayPickManager::update() { // TODO: // get rid of this and make PickRay hashable QPair rayKey = QPair(ray.origin, ray.direction); - RayPickResult res; // start with FLT_MAX distance + RayPickResult res; if (rayPick->getFilter() & RayPickMask::PICK_ENTITIES) { RayToEntityIntersectionResult entityRes; + bool fromCache = true; if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE && rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { - if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_ENTITIES | RayPickMask::PICK_INCLUDE_INVISIBLE | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { + if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_ENTITIES | RayPickMask::PICK_INCLUDE_INVISIBLE | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { entityRes = DependencyManager::get()->findRayIntersection(ray, true, QScriptValue(), QScriptValue(), false, false); + fromCache = false; } - } - else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) { - if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_ENTITIES | RayPickMask::PICK_INCLUDE_INVISIBLE)) { + } else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) { + if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_ENTITIES | RayPickMask::PICK_INCLUDE_INVISIBLE)) { entityRes = DependencyManager::get()->findRayIntersection(ray, true, QScriptValue(), QScriptValue(), false, true); + fromCache = false; } - } - else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { - if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_ENTITIES | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { + } else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { + if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_ENTITIES | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { entityRes = DependencyManager::get()->findRayIntersection(ray, true, QScriptValue(), QScriptValue(), true, false); + fromCache = false; } - } - else { - if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_ENTITIES)) { + } else { + if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_ENTITIES)) { entityRes = DependencyManager::get()->findRayIntersection(ray, true, QScriptValue(), QScriptValue(), true, true); + fromCache = false; } } - if (entityRes.intersects) { - res = RayPickResult(entityRes.entityID, entityRes.distance, entityRes.intersection, entityRes.surfaceNormal); - // add to cache + + if (!fromCache) { + unsigned int mask = (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) | (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE); + cacheResult(entityRes.intersects, RayPickResult(entityRes.entityID, entityRes.distance, entityRes.intersection, entityRes.surfaceNormal), + RayPickMask::PICK_ENTITIES | mask, res, rayKey, results); } } if (rayPick->getFilter() & RayPickMask::PICK_OVERLAYS) { RayToOverlayIntersectionResult overlayRes; + bool fromCache = true; if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE && rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { - if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_OVERLAYS | RayPickMask::PICK_INCLUDE_INVISIBLE | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { + if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_OVERLAYS | RayPickMask::PICK_INCLUDE_INVISIBLE | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { overlayRes = qApp->getOverlays().findRayIntersection(ray, true, QScriptValue(), QScriptValue(), false, false); + fromCache = false; } - } - else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) { - if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_OVERLAYS | RayPickMask::PICK_INCLUDE_INVISIBLE)) { + } else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) { + if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_OVERLAYS | RayPickMask::PICK_INCLUDE_INVISIBLE)) { overlayRes = qApp->getOverlays().findRayIntersection(ray, true, QScriptValue(), QScriptValue(), false, true); + fromCache = false; } - } - else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { - if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_OVERLAYS | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { + } else if (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE) { + if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_OVERLAYS | RayPickMask::PICK_INCLUDE_NONCOLLIDABLE)) { overlayRes = qApp->getOverlays().findRayIntersection(ray, true, QScriptValue(), QScriptValue(), true, false); + fromCache = false; } - } - else { - if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_OVERLAYS)) { + } else { + if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_OVERLAYS)) { overlayRes = qApp->getOverlays().findRayIntersection(ray, true, QScriptValue(), QScriptValue(), true, true); + fromCache = false; } } - if (overlayRes.intersects) { - res = RayPickResult(overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, overlayRes.surfaceNormal); - // add to cache + + if (!fromCache) { + unsigned int mask = (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_INVISIBLE) | (rayPick->getFilter() & RayPickMask::PICK_INCLUDE_NONCOLLIDABLE); + cacheResult(overlayRes.intersects, RayPickResult(overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, overlayRes.surfaceNormal), + RayPickMask::PICK_OVERLAYS | mask, res, rayKey, results); } } if (rayPick->getFilter() & RayPickMask::PICK_AVATARS) { - if (!checkAndCompareCachedResults(rayPick, rayKey, results, res, RayPickMask::PICK_AVATARS)) { + if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_AVATARS)) { RayToAvatarIntersectionResult avatarRes = DependencyManager::get()->findRayIntersection(ray, QScriptValue(), QScriptValue()); - if (avatarRes.intersects) { - res = RayPickResult(avatarRes.avatarID, avatarRes.distance, avatarRes.intersection); - // add to cache - } + cacheResult(avatarRes.intersects, RayPickResult(avatarRes.avatarID, avatarRes.distance, avatarRes.intersection), RayPickMask::PICK_AVATARS, res, rayKey, results); } } + // Can't intersect with HUD in desktop mode + if (rayPick->getFilter() & RayPickMask::PICK_HUD && DependencyManager::get()->isHMDMode()) { + if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_HUD)) { + glm::vec3 hudRes = DependencyManager::get()->calculateRayUICollisionPoint(ray.origin, ray.direction); + cacheResult(true, RayPickResult(0, glm::distance(ray.origin, hudRes), hudRes), RayPickMask::PICK_HUD, res, rayKey, results); + } + } + + if (res.distance < rayPick->getMaxDistance()) { + rayPick->setRayPickResult(res); + } else { + rayPick->setRayPickResult(RayPickResult()); + } } } @@ -129,17 +161,22 @@ void RayPickManager::removeRayPick(const unsigned int uid) { } void RayPickManager::enableRayPick(const unsigned int uid) { - // TODO: - // use lock and defer enabling to prevent issues if (_rayPicks.contains(uid)) { _rayPicks[uid]->enable(); } } void RayPickManager::disableRayPick(const unsigned int uid) { - // TODO: - // use lock and defer disabling to prevent issues if (_rayPicks.contains(uid)) { _rayPicks[uid]->disable(); } } + +const RayPickResult& RayPickManager::getPrevRayPickResult(const unsigned int uid) { + // TODO: + // does this need to lock the individual ray? what happens with concurrent set/get? + if (_rayPicks.contains(uid)) { + return _rayPicks[uid]->getPrevRayPickResult(); + } + return RayPickResult(); +} diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h index ac700118f6..8a98677776 100644 --- a/interface/src/raypick/RayPickManager.h +++ b/interface/src/raypick/RayPickManager.h @@ -18,6 +18,7 @@ #include class RayPick; +class RayPickResult; enum RayPickMask { PICK_NOTHING = 0, @@ -34,28 +35,6 @@ enum RayPickMask { PICK_ALL_INTERSECTIONS = 128 // if not set, returns closest intersection, otherwise, returns list of all intersections }; -// TODO: -// move/improve this and register it as a meta type -class RayPickResult { - -public: - RayPickResult() {} - RayPickResult(const QUuid& objectID, const float distance, const glm::vec3& intersection, const glm::vec3& surfaceNormal = glm::vec3(NAN)) : - _objectID(objectID), _distance(distance), _intersection(intersection), _surfaceNormal(surfaceNormal) {} - - const QUuid& getUID() { return _objectID; } - const float getDistance() { return _distance; } - const glm::vec3& getIntersection() { return _intersection; } - const glm::vec3& getSurfaceNormal() { return _surfaceNormal; } - -private: - //Type type; - QUuid _objectID { 0 }; - float _distance { FLT_MAX }; - glm::vec3 _intersection { NAN }; - glm::vec3 _surfaceNormal { NAN }; -}; - class RayPickManager : public QObject { Q_OBJECT Q_PROPERTY(unsigned int PICK_NOTHING READ PICK_NOTHING CONSTANT) @@ -72,11 +51,14 @@ public: static RayPickManager& getInstance(); void update(); - bool RayPickManager::checkAndCompareCachedResults(std::shared_ptr rayPick, QPair& ray, QHash, QHash> cache, RayPickResult& res, unsigned int mask); + bool checkAndCompareCachedResults(QPair& ray, QHash, QHash>& cache, RayPickResult& res, unsigned int mask); + void cacheResult(const bool intersects, const RayPickResult& resTemp, unsigned int mask, RayPickResult& res, + QPair& ray, QHash, QHash>& cache); unsigned int addRayPick(std::shared_ptr rayPick); void removeRayPick(const unsigned int uid); void enableRayPick(const unsigned int uid); void disableRayPick(const unsigned int uid); + const RayPickResult& getPrevRayPickResult(const unsigned int uid); private: QHash> _rayPicks; diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index b30637c83f..1565777666 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -34,6 +34,7 @@ int vec2MetaTypeId = qRegisterMetaType(); int quatMetaTypeId = qRegisterMetaType(); int xColorMetaTypeId = qRegisterMetaType(); int pickRayMetaTypeId = qRegisterMetaType(); +int rayPickResultMetaTypeId = qRegisterMetaType(); int collisionMetaTypeId = qRegisterMetaType(); int qMapURLStringMetaTypeId = qRegisterMetaType>(); int socketErrorMetaTypeId = qRegisterMetaType(); @@ -56,6 +57,7 @@ void registerMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, qColorToScriptValue, qColorFromScriptValue); qScriptRegisterMetaType(engine, qURLToScriptValue, qURLFromScriptValue); qScriptRegisterMetaType(engine, pickRayToScriptValue, pickRayFromScriptValue); + qScriptRegisterMetaType(engine, rayPickResultToScriptValue, rayPickResultFromScriptValue); qScriptRegisterMetaType(engine, collisionToScriptValue, collisionFromScriptValue); qScriptRegisterMetaType(engine, quuidToScriptValue, quuidFromScriptValue); qScriptRegisterMetaType(engine, qSizeFToScriptValue, qSizeFFromScriptValue); @@ -751,6 +753,22 @@ void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay) { } } +QScriptValue rayPickResultToScriptValue(QScriptEngine* engine, const RayPickResult& rayPickResult) { + QScriptValue obj = engine->newObject(); + QScriptValue objectID = quuidToScriptValue(engine, rayPickResult.objectID); + obj.setProperty("objectID", objectID); + obj.setProperty("distance", rayPickResult.distance); + QScriptValue intersection = vec3toScriptValue(engine, rayPickResult.intersection); + obj.setProperty("intersection", intersection); + QScriptValue surfaceNormal = vec3toScriptValue(engine, rayPickResult.surfaceNormal); + obj.setProperty("surfaceNormal", surfaceNormal); + return obj; +} + +void rayPickResultFromScriptValue(const QScriptValue& object, RayPickResult& rayPickResult) { + // TODO: cannot currently accept RayPickResults from JS +} + QScriptValue collisionToScriptValue(QScriptEngine* engine, const Collision& collision) { QScriptValue obj = engine->newObject(); obj.setProperty("type", collision.type); diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 123c769a96..7d9ba941a9 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -136,6 +136,21 @@ Q_DECLARE_METATYPE(PickRay) QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay); void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay); +class RayPickResult { +public: + RayPickResult() {} + RayPickResult(const QUuid& objectID, const float distance, const glm::vec3& intersection, const glm::vec3& surfaceNormal = glm::vec3(NAN)) : + objectID(objectID), distance(distance), intersection(intersection), surfaceNormal(surfaceNormal) {} + //Type type; + QUuid objectID { 0 }; + float distance { FLT_MAX }; + glm::vec3 intersection { NAN }; + glm::vec3 surfaceNormal { NAN }; +}; +Q_DECLARE_METATYPE(RayPickResult) +QScriptValue rayPickResultToScriptValue(QScriptEngine* engine, const RayPickResult& rayPickResult); +void rayPickResultFromScriptValue(const QScriptValue& object, RayPickResult& rayPickResult); + enum ContactEventType { CONTACT_EVENT_TYPE_START, CONTACT_EVENT_TYPE_CONTINUE,