added JS/C++ RayPickResult, working on RayPickManager::update

This commit is contained in:
SamGondelman 2017-07-12 17:12:25 -07:00
parent 285705c934
commit 916a99c670
10 changed files with 137 additions and 66 deletions

View file

@ -32,4 +32,8 @@ void LaserPointer::disable() {
RayPickManager::getInstance().disableRayPick(_rayPickUID);
// TODO:
// turn off rendering
}
const RayPickResult& LaserPointer::getPrevRayPickResult() {
return RayPickManager::getInstance().getPrevRayPickResult(_rayPickUID);
}

View file

@ -14,6 +14,8 @@
#include <QString>
#include "glm/glm.hpp"
class RayPickResult;
class LaserPointer {
public:
@ -27,6 +29,8 @@ public:
// void setRenderState(const QString& stateName);
// void setRenderStateProperties(const QHash<QString, triplet of properties>& renderStateProperties);
const RayPickResult& getPrevRayPickResult();
private:
unsigned int _rayPickUID;
};

View file

@ -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();
}
}
}
const RayPickResult& LaserPointerManager::getPrevRayPickResult(const unsigned int uid) {
if (_laserPointers.contains(uid)) {
return _laserPointers[uid]->getPrevRayPickResult();
}
return RayPickResult();
}

View file

@ -17,6 +17,7 @@
#include <glm/glm.hpp>
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<unsigned int, std::shared_ptr<LaserPointer>> _laserPointers;

View file

@ -14,6 +14,7 @@
#include <QtCore/QObject>
#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); }
};

View file

@ -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;
};

View file

@ -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> rayPick, QPair<glm::vec3, glm::vec3>& ray, QHash<QPair<glm::vec3, glm::vec3>, QHash<unsigned int, RayPickResult>> cache, RayPickResult& res, unsigned int mask) {
bool RayPickManager::checkAndCompareCachedResults(QPair<glm::vec3, glm::vec3>& ray, QHash<QPair<glm::vec3, glm::vec3>, QHash<unsigned int, RayPickResult>>& 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<RayPick> rayPi
return false;
}
void RayPickManager::cacheResult(const bool intersects, const RayPickResult& resTemp, unsigned int mask, RayPickResult& res,
QPair<glm::vec3, glm::vec3>& ray, QHash<QPair<glm::vec3, glm::vec3>, QHash<unsigned int, RayPickResult>>& cache) {
if (intersects) {
cache[ray][mask] = resTemp;
if (resTemp.distance < res.distance) {
res = resTemp;
}
} else {
cache[ray][mask] = RayPickResult();
}
}
void RayPickManager::update() {
QHash<QPair<glm::vec3, glm::vec3>, QHash<unsigned int, RayPickResult>> results;
for (auto &rayPick : _rayPicks) {
@ -44,74 +58,92 @@ void RayPickManager::update() {
// TODO:
// get rid of this and make PickRay hashable
QPair<glm::vec3, glm::vec3> rayKey = QPair<glm::vec3, glm::vec3>(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<EntityScriptingInterface>()->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<EntityScriptingInterface>()->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<EntityScriptingInterface>()->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<EntityScriptingInterface>()->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<AvatarManager>()->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<HMDScriptingInterface>()->isHMDMode()) {
if (!checkAndCompareCachedResults(rayKey, results, res, RayPickMask::PICK_HUD)) {
glm::vec3 hudRes = DependencyManager::get<HMDScriptingInterface>()->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();
}

View file

@ -18,6 +18,7 @@
#include <QtCore/QObject>
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> rayPick, QPair<glm::vec3, glm::vec3>& ray, QHash<QPair<glm::vec3, glm::vec3>, QHash<unsigned int, RayPickResult>> cache, RayPickResult& res, unsigned int mask);
bool checkAndCompareCachedResults(QPair<glm::vec3, glm::vec3>& ray, QHash<QPair<glm::vec3, glm::vec3>, QHash<unsigned int, RayPickResult>>& cache, RayPickResult& res, unsigned int mask);
void cacheResult(const bool intersects, const RayPickResult& resTemp, unsigned int mask, RayPickResult& res,
QPair<glm::vec3, glm::vec3>& ray, QHash<QPair<glm::vec3, glm::vec3>, QHash<unsigned int, RayPickResult>>& cache);
unsigned int addRayPick(std::shared_ptr<RayPick> 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<unsigned int, std::shared_ptr<RayPick>> _rayPicks;

View file

@ -34,6 +34,7 @@ int vec2MetaTypeId = qRegisterMetaType<glm::vec2>();
int quatMetaTypeId = qRegisterMetaType<glm::quat>();
int xColorMetaTypeId = qRegisterMetaType<xColor>();
int pickRayMetaTypeId = qRegisterMetaType<PickRay>();
int rayPickResultMetaTypeId = qRegisterMetaType<RayPickResult>();
int collisionMetaTypeId = qRegisterMetaType<Collision>();
int qMapURLStringMetaTypeId = qRegisterMetaType<QMap<QUrl,QString>>();
int socketErrorMetaTypeId = qRegisterMetaType<QAbstractSocket::SocketError>();
@ -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);

View file

@ -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,