pickmanager wip

This commit is contained in:
SamGondelman 2017-10-17 12:00:56 -07:00
parent 429905de51
commit 596be8ec27
15 changed files with 487 additions and 345 deletions

View file

@ -12,7 +12,7 @@
#include "avatar/AvatarManager.h"
JointRayPick::JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled) :
JointRayPick::JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, const float maxDistance, const bool enabled) :
RayPick(filter, maxDistance, enabled),
_jointName(jointName),
_posOffset(posOffset),
@ -20,7 +20,7 @@ JointRayPick::JointRayPick(const std::string& jointName, const glm::vec3& posOff
{
}
const PickRay JointRayPick::getPickRay(bool& valid) const {
const PickRay JointRayPick::getMathematicalPick(bool& valid) const {
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
int jointIndex = myAvatar->getJointIndex(QString::fromStdString(_jointName));
bool useAvatarHead = _jointName == "Avatar";

View file

@ -11,14 +11,14 @@
#ifndef hifi_JointRayPick_h
#define hifi_JointRayPick_h
#include <pointers/rays/RayPick.h>
#include "RayPick.h"
class JointRayPick : public RayPick {
public:
JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false);
JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false);
const PickRay getPickRay(bool& valid) const override;
const PickRay getMathematicalPick(bool& valid) const override;
private:
std::string _jointName;

View file

@ -10,16 +10,15 @@
//
#include "MouseRayPick.h"
#include "DependencyManager.h"
#include "Application.h"
#include "display-plugins/CompositorHelper.h"
MouseRayPick::MouseRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled) :
MouseRayPick::MouseRayPick(const PickFilter& filter, const float maxDistance, const bool enabled) :
RayPick(filter, maxDistance, enabled)
{
}
const PickRay MouseRayPick::getPickRay(bool& valid) const {
const PickRay MouseRayPick::getMathematicalPick(bool& valid) const {
QVariant position = qApp->getApplicationCompositor().getReticleInterface()->getPosition();
if (position.isValid()) {
QVariantMap posMap = position.toMap();

View file

@ -11,14 +11,14 @@
#ifndef hifi_MouseRayPick_h
#define hifi_MouseRayPick_h
#include <pointers/rays/RayPick.h>
#include "RayPick.h"
class MouseRayPick : public RayPick {
public:
MouseRayPick(const RayPickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false);
MouseRayPick(const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false);
const PickRay getPickRay(bool& valid) const override;
const PickRay getMathematicalPick(bool& valid) const override;
};
#endif // hifi_MouseRayPick_h

View file

@ -0,0 +1,10 @@
//
// Created by Sam Gondelman 10/17/2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "Pick.h"
const PickFilter PickFilter::NOTHING;

View file

@ -1,12 +1,12 @@
//
// Created by Sam Gondelman 7/11/2017
// Created by Sam Gondelman 10/17/2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_RayPick_h
#define hifi_RayPick_h
#ifndef hifi_Pick_h
#define hifi_Pick_h
#include <stdint.h>
#include <bitset>
@ -16,7 +16,10 @@
#include <RegisteredMetaTypes.h>
#include <shared/ReadWriteLockable.h>
class RayPickFilter {
#include "EntityScriptingInterface.h"
#include "ui/overlays/Overlays.h"
class PickFilter {
public:
enum FlagBit {
PICK_ENTITIES = 0,
@ -39,11 +42,11 @@ public:
// The key is the Flags
Flags _flags;
RayPickFilter() {}
RayPickFilter(const Flags& flags) : _flags(flags) {}
PickFilter() {}
PickFilter(const Flags& flags) : _flags(flags) {}
bool operator== (const RayPickFilter& rhs) const { return _flags == rhs._flags; }
bool operator!= (const RayPickFilter& rhs) const { return _flags != rhs._flags; }
bool operator== (const PickFilter& rhs) const { return _flags == rhs._flags; }
bool operator!= (const PickFilter& rhs) const { return _flags != rhs._flags; }
void setFlag(FlagBit flag, bool value) { _flags[flag] = value; }
@ -91,29 +94,42 @@ public:
static constexpr unsigned int getBitMask(FlagBit bit) { return 1 << bit; }
static const RayPickFilter NOTHING;
static const PickFilter NOTHING;
};
class RayPick : protected ReadWriteLockable {
template<typename T>
class Pick : protected ReadWriteLockable {
public:
using Pointer = std::shared_ptr<RayPick>;
using Pointer = std::shared_ptr<Pick<T>>;
RayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled);
Pick(const PickFilter& filter, const float maxDistance, const bool enabled);
virtual const PickRay getPickRay(bool& valid) const = 0;
virtual const T getMathematicalPick(bool& valid) const = 0;
virtual RayToEntityIntersectionResult getEntityIntersection(const T& pick, bool precisionPicking,
const QVector<EntityItemID>& entitiesToInclude,
const QVector<EntityItemID>& entitiesToIgnore,
bool visibleOnly, bool collidableOnly) = 0;
virtual RayToOverlayIntersectionResult getOverlayIntersection(const T& pick, bool precisionPicking,
const QVector<OverlayID>& overlaysToInclude,
const QVector<OverlayID>& overlaysToIgnore,
bool visibleOnly, bool collidableOnly) = 0;
virtual RayToAvatarIntersectionResult getAvatarIntersection(const T& pick,
const QVector<EntityItemID>& avatarsToInclude,
const QVector<EntityItemID>& avatarsToIgnore) = 0;
virtual glm::vec3 getHUDIntersection(const T& pick) = 0;
void enable(bool enabled = true);
void disable() { enable(false); }
RayPickFilter getFilter() const;
PickFilter getFilter() const;
float getMaxDistance() const;
bool isEnabled() const;
RayPickResult getPrevRayPickResult() const;
RayPickResult getPrevPickResult() const;
void setPrecisionPicking(bool precisionPicking);
void setRayPickResult(const RayPickResult& rayPickResult);
void setPickResult(const RayPickResult& rayPickResult);
QVector<QUuid> getIgnoreItems() const;
QVector<QUuid> getIncludeItems() const;
@ -144,7 +160,7 @@ public:
void setIncludeItems(const QVector<QUuid>& items);
private:
RayPickFilter _filter;
PickFilter _filter;
const float _maxDistance;
bool _enabled;
RayPickResult _prevResult;
@ -153,4 +169,87 @@ private:
QVector<QUuid> _includeItems;
};
#endif // hifi_RayPick_h
template<typename T>
Pick<T>::Pick(const PickFilter& filter, const float maxDistance, const bool enabled) :
_filter(filter),
_maxDistance(maxDistance),
_enabled(enabled) {
}
template<typename T>
void Pick<T>::enable(bool enabled) {
withWriteLock([&] {
_enabled = enabled;
});
}
template<typename T>
PickFilter Pick<T>::getFilter() const {
return resultWithReadLock<PickFilter>([&] {
return _filter;
});
}
template<typename T>
float Pick<T>::getMaxDistance() const {
return _maxDistance;
}
template<typename T>
bool Pick<T>::isEnabled() const {
withReadLock([&]) {
return _enabled;
}
}
template<typename T>
void Pick<T>::setPrecisionPicking(bool precisionPicking) {
withWriteLock([&] {
_filter.setFlag(PickFilter::PICK_COARSE, !precisionPicking);
});
}
template<typename T>
void Pick<T>::setPickResult(const RayPickResult& PickResult) {
withWriteLock([&] {
_prevResult = PickResult;
});
}
template<typename T>
QVector<QUuid> Pick<T>::getIgnoreItems() const {
withReadLock([&]) {
return _ignoreItems;
}
}
template<typename T>
QVector<QUuid> Pick<T>::getIncludeItems() const {
withReadLock([&]) {
return _includeItems;
}
}
template<typename T>
RayPickResult Pick<T>::getPrevPickResult() const {
return resultWithReadLock<RayPickResult>([&] {
return _prevResult;
});
}
template<typename T>
void Pick<T>::setIgnoreItems(const QVector<QUuid>& ignoreItems) {
withWriteLock([&] {
_ignoreItems = ignoreItems;
});
}
template<typename T>
void Pick<T>::setIncludeItems(const QVector<QUuid>& includeItems) {
withWriteLock([&] {
_includeItems = includeItems;
});
}
#endif // hifi_Pick_h

View file

@ -0,0 +1,244 @@
//
// PickManager.h
// interface/src/raypick
//
// Created by Sam Gondelman 10/16/2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_PickManager_h
#define hifi_PickManager_h
#include <unordered_map>
#include "Pick.h"
typedef struct RayCacheKey {
PickFilter::Flags mask;
QVector<QUuid> include;
QVector<QUuid> ignore;
bool operator==(const RayCacheKey& other) const {
return (mask == other.mask && include == other.include && ignore == other.ignore);
}
} RayCacheKey;
namespace std {
template <>
struct hash<RayCacheKey> {
size_t operator()(const RayCacheKey& k) const {
return ((hash<PickFilter::Flags>()(k.mask) ^ (qHash(k.include) << 1)) >> 1) ^ (qHash(k.ignore) << 1);
}
};
}
// T is a mathematical representation of a Pick.
// For example: origin and direction for RayPick
template<typename T>
class PickManager : protected ReadWriteLockable {
public:
virtual void update();
RayPickResult getPrevPickResult(const QUuid& uid) const;
void removePick(const QUuid& uid);
void enablePick(const QUuid& uid) const;
void disablePick(const QUuid& uid) const;
void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const;
void setIgnoreItems(const QUuid& uid, const QVector<QUuid>& ignore) const;
void setIncludeItems(const QUuid& uid, const QVector<QUuid>& include) const;
protected:
Pick<T>::Pointer findPick(const QUuid& uid) const;
QHash<QUuid, Pick<T>::Pointer> _picks;
typedef QHash<T, std::unordered_map<RayCacheKey, RayPickResult>> RayPickCache;
// Returns true if this ray exists in the cache, and if it does, update res if the cached result is closer
bool checkAndCompareCachedResults(T& pick, RayPickCache& cache, RayPickResult& res, const RayCacheKey& key);
void cacheResult(const bool intersects, const RayPickResult& resTemp, const RayCacheKey& key, RayPickResult& res, T& pick, RayPickCache& cache);
};
template<typename T>
RayPick::Pointer PickManager<T>::findPick(const QUuid& uid) const {
return resultWithReadLock<RayPick::Pointer>([&] {
if (_picks.contains(uid)) {
return _picks[uid];
}
return RayPick::Pointer();
});
}
template<typename T>
bool PickManager<T>::checkAndCompareCachedResults(T& pick, RayPickCache& cache, RayPickResult& res, const RayCacheKey& key) {
if (cache.contains(pick) && cache[pick].find(key) != cache[pick].end()) {
if (cache[pick][key].distance < res.distance) {
res = cache[pick][key];
}
return true;
}
return false;
}
template<typename T>
void PickManager<T>::cacheResult(const bool intersects, const RayPickResult& resTemp, const RayCacheKey& key, RayPickResult& res, T& pick, RayPickCache& cache) {
if (intersects) {
cache[pick][key] = resTemp;
if (resTemp.distance < res.distance) {
res = resTemp;
}
} else {
cache[pick][key] = RayPickResult(res.searchRay);
}
}
template<typename T>
void PickManager<T>::update() {
RayPickCache results;
QHash<QUuid, Pick<T>::Pointer> cachedPicks;
withReadLock([&] {
cachedPicks = _picks;
});
for (const auto& uid : cachedPicks.keys()) {
Pick<T>::Pointer pick = cachedPicks[uid];
if (!pick->isEnabled() || pick->getFilter().doesPickNothing() || pick->getMaxDistance() < 0.0f) {
continue;
}
T mathematicalPick;
{
bool valid;
mathematicalPick = pick->getPickRay(valid);
if (!valid) {
continue;
}
}
RayPickResult res = RayPickResult(mathematicalPick);
if (pick->getFilter().doesPickEntities()) {
RayToEntityIntersectionResult entityRes;
bool fromCache = true;
bool invisible = pick->getFilter().doesPickInvisible();
bool nonCollidable = pick->getFilter().doesPickNonCollidable();
RayCacheKey entityKey = { pick->getFilter().getEntityFlags(), pick->getIncludeItems(), pick->getIgnoreItems() };
if (!checkAndCompareCachedResults(mathematicalPick, results, res, entityKey)) {
entityRes = pick->getEntityIntersection(mathematicalPick, !pick->getFilter().doesPickCoarse(),
pick->getIncludeItemsAs<EntityItemID>(), pick->getIgnoreItemsAs<EntityItemID>(), !invisible, !nonCollidable);
fromCache = false;
}
if (!fromCache) {
cacheResult(entityRes.intersects, RayPickResult(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, mathematicalPick, entityRes.surfaceNormal),
entityKey, res, mathematicalPick, results);
}
}
if (pick->getFilter().doesPickOverlays()) {
RayToOverlayIntersectionResult overlayRes;
bool fromCache = true;
bool invisible = pick->getFilter().doesPickInvisible();
bool nonCollidable = pick->getFilter().doesPickNonCollidable();
RayCacheKey overlayKey = { pick->getFilter().getOverlayFlags(), pick->getIncludeItems(), pick->getIgnoreItems() };
if (!checkAndCompareCachedResults(mathematicalPick, results, res, overlayKey)) {
overlayRes = pick->getOverlayIntersection(mathematicalPick, !pick->getFilter().doesPickCoarse(),
pick->getIncludeItemsAs<OverlayID>(), pick->getIgnoreItemsAs<OverlayID>(), !invisible, !nonCollidable);
fromCache = false;
}
if (!fromCache) {
cacheResult(overlayRes.intersects, RayPickResult(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, mathematicalPick, overlayRes.surfaceNormal),
overlayKey, res, mathematicalPick, results);
}
}
if (pick->getFilter().doesPickAvatars()) {
RayCacheKey avatarKey = { pick->getFilter().getAvatarFlags(), pick->getIncludeItems(), pick->getIgnoreItems() };
if (!checkAndCompareCachedResults(mathematicalPick, results, res, avatarKey)) {
RayToAvatarIntersectionResult avatarRes = pick->getAvatarIntersection(mathematicalPick,
pick->getIncludeItemsAs<EntityItemID>(), pick->getIgnoreItemsAs<EntityItemID>());
cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, mathematicalPick), avatarKey, res, mathematicalPick, results);
}
}
// Can't intersect with HUD in desktop mode
if (pick->getFilter().doesPickHUD() && DependencyManager::get<HMDScriptingInterface>()->isHMDMode()) {
RayCacheKey hudKey = { pick->getFilter().getHUDFlags(), QVector<QUuid>(), QVector<QUuid>() };
if (!checkAndCompareCachedResults(mathematicalPick, results, res, hudKey)) {
glm::vec3 hudRes = pick->getHUDIntersection(mathematicalPick.origin, mathematicalPick.direction);
cacheResult(true, RayPickResult(IntersectionType::HUD, 0, glm::distance(mathematicalPick.origin, hudRes), hudRes, mathematicalPick), hudKey, res, mathematicalPick, results);
}
}
if (pick->getMaxDistance() == 0.0f || (pick->getMaxDistance() > 0.0f && res.distance < pick->getMaxDistance())) {
pick->setPickResult(res);
} else {
pick->setPickResult(RayPickResult(mathematicalPick));
}
}
}
template<typename T>
RayPickResult PickManager<T>::getPrevPickResult(const QUuid& uid) const {
auto rayPick = findPick(uid);
if (rayPick) {
return rayPick->getPrevPickResult();
}
return RayPickResult();
}
template<typename T>
void PickManager<T>::removePick(const QUuid& uid) {
withWriteLock([&] {
_picks.remove(uid);
});
}
template<typename T>
void PickManager<T>::enablePick(const QUuid& uid) const {
auto rayPick = findPick(uid);
if (rayPick) {
rayPick->enable();
}
}
template<typename T>
void PickManager<T>::disablePick(const QUuid& uid) const {
auto rayPick = findPick(uid);
if (rayPick) {
rayPick->disable();
}
}
template<typename T>
void PickManager<T>::setPrecisionPicking(const QUuid& uid, bool precisionPicking) const {
auto rayPick = findPick(uid);
if (rayPick) {
rayPick->setPrecisionPicking(precisionPicking);
}
}
template<typename T>
void PickManager<T>::setIgnoreItems(const QUuid& uid, const QVector<QUuid>& ignore) const {
auto rayPick = findPick(uid);
if (rayPick) {
rayPick->setIgnoreItems(ignore);
}
}
template<typename T>
void PickManager<T>::setIncludeItems(const QUuid& uid, const QVector<QUuid>& include) const {
auto rayPick = findPick(uid);
if (rayPick) {
rayPick->setIncludeItems(include);
}
}
#endif // hifi_PickManager_h

View file

@ -0,0 +1,39 @@
//
// Created by Sam Gondelman 7/11/2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "RayPick.h"
#include "Application.h"
#include "avatar/AvatarManager.h"
#include "scripting/HMDScriptingInterface.h"
#include "DependencyManager.h"
RayToEntityIntersectionResult RayPick::getEntityIntersection(const PickRay& pick, bool precisionPicking,
const QVector<EntityItemID>& entitiesToInclude,
const QVector<EntityItemID>& entitiesToIgnore,
bool visibleOnly, bool collidableOnly) {
return DependencyManager::get<EntityScriptingInterface>()->findRayIntersectionVector(pick, precisionPicking,
entitiesToInclude, entitiesToIgnore, visibleOnly, collidableOnly);
}
RayToOverlayIntersectionResult RayPick::getOverlayIntersection(const PickRay& pick, bool precisionPicking,
const QVector<OverlayID>& overlaysToInclude,
const QVector<OverlayID>& overlaysToIgnore,
bool visibleOnly, bool collidableOnly) {
return qApp->getOverlays().findRayIntersectionVector(pick, precisionPicking,
overlaysToInclude, overlaysToIgnore, visibleOnly, collidableOnly);
}
RayToAvatarIntersectionResult RayPick::getAvatarIntersection(const PickRay& pick,
const QVector<EntityItemID>& avatarsToInclude,
const QVector<EntityItemID>& avatarsToIgnore) {
return DependencyManager::get<AvatarManager>()->findRayIntersectionVector(pick, avatarsToInclude, avatarsToIgnore);
}
glm::vec3 RayPick::getHUDIntersection(const PickRay& pick) {
return DependencyManager::get<HMDScriptingInterface>()->calculateRayUICollisionPoint(pick.origin, pick.direction);
}

View file

@ -0,0 +1,35 @@
//
// Created by Sam Gondelman 7/11/2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_RayPick_h
#define hifi_RayPick_h
#include "Pick.h"
class EntityItemID;
class OverlayID;
class RayPick : public Pick<PickRay> {
public:
RayPick(const PickFilter& filter, const float maxDistance, const bool enabled) : Pick(filter, maxDistance, enabled) {}
RayToEntityIntersectionResult getEntityIntersection(const PickRay& pick, bool precisionPicking,
const QVector<EntityItemID>& entitiesToInclude,
const QVector<EntityItemID>& entitiesToIgnore,
bool visibleOnly, bool collidableOnly) override;
RayToOverlayIntersectionResult getOverlayIntersection(const PickRay& pick, bool precisionPicking,
const QVector<OverlayID>& overlaysToInclude,
const QVector<OverlayID>& overlaysToIgnore,
bool visibleOnly, bool collidableOnly) override;
RayToAvatarIntersectionResult getAvatarIntersection(const PickRay& pick,
const QVector<EntityItemID>& avatarsToInclude,
const QVector<EntityItemID>& avatarsToIgnore) override;
glm::vec3 getHUDIntersection(const PickRay& pick) override;
};
#endif // hifi_RayPick_h

View file

@ -10,209 +10,33 @@
//
#include "RayPickManager.h"
#include <pointers/rays/StaticRayPick.h>
#include "Application.h"
#include "EntityScriptingInterface.h"
#include "ui/overlays/Overlays.h"
#include "avatar/AvatarManager.h"
#include "scripting/HMDScriptingInterface.h"
#include "DependencyManager.h"
#include "StaticRayPick.h"
#include "JointRayPick.h"
#include "MouseRayPick.h"
bool RayPickManager::checkAndCompareCachedResults(QPair<glm::vec3, glm::vec3>& ray, RayPickCache& cache, RayPickResult& res, const RayCacheKey& key) {
if (cache.contains(ray) && cache[ray].find(key) != cache[ray].end()) {
if (cache[ray][key].distance < res.distance) {
res = cache[ray][key];
}
return true;
}
return false;
}
void RayPickManager::cacheResult(const bool intersects, const RayPickResult& resTemp, const RayCacheKey& key, RayPickResult& res, QPair<glm::vec3, glm::vec3>& ray, RayPickCache& cache) {
if (intersects) {
cache[ray][key] = resTemp;
if (resTemp.distance < res.distance) {
res = resTemp;
}
} else {
cache[ray][key] = RayPickResult(res.searchRay);
}
}
void RayPickManager::update() {
RayPickCache results;
QHash<QUuid, RayPick::Pointer> cachedRayPicks;
withReadLock([&] {
cachedRayPicks = _rayPicks;
});
for (const auto& uid : cachedRayPicks.keys()) {
std::shared_ptr<RayPick> rayPick = cachedRayPicks[uid];
if (!rayPick->isEnabled() || rayPick->getFilter().doesPickNothing() || rayPick->getMaxDistance() < 0.0f) {
continue;
}
PickRay ray;
{
bool valid;
ray = rayPick->getPickRay(valid);
if (!valid) {
continue;
}
}
QPair<glm::vec3, glm::vec3> rayKey = QPair<glm::vec3, glm::vec3>(ray.origin, ray.direction);
RayPickResult res = RayPickResult(ray);
if (rayPick->getFilter().doesPickEntities()) {
RayToEntityIntersectionResult entityRes;
bool fromCache = true;
bool invisible = rayPick->getFilter().doesPickInvisible();
bool nonCollidable = rayPick->getFilter().doesPickNonCollidable();
RayCacheKey entityKey = { rayPick->getFilter().getEntityFlags(), rayPick->getIncludeItems(), rayPick->getIgnoreItems() };
if (!checkAndCompareCachedResults(rayKey, results, res, entityKey)) {
entityRes = DependencyManager::get<EntityScriptingInterface>()->findRayIntersectionVector(ray, !rayPick->getFilter().doesPickCoarse(),
rayPick->getIncludeItemsAs<EntityItemID>(), rayPick->getIgnoreItemsAs<EntityItemID>(), !invisible, !nonCollidable);
fromCache = false;
}
if (!fromCache) {
cacheResult(entityRes.intersects, RayPickResult(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, ray, entityRes.surfaceNormal),
entityKey, res, rayKey, results);
}
}
if (rayPick->getFilter().doesPickOverlays()) {
RayToOverlayIntersectionResult overlayRes;
bool fromCache = true;
bool invisible = rayPick->getFilter().doesPickInvisible();
bool nonCollidable = rayPick->getFilter().doesPickNonCollidable();
RayCacheKey overlayKey = { rayPick->getFilter().getOverlayFlags(), rayPick->getIncludeItems(), rayPick->getIgnoreItems() };
if (!checkAndCompareCachedResults(rayKey, results, res, overlayKey)) {
overlayRes = qApp->getOverlays().findRayIntersectionVector(ray, !rayPick->getFilter().doesPickCoarse(),
rayPick->getIncludeItemsAs<OverlayID>(), rayPick->getIgnoreItemsAs<OverlayID>(), !invisible, !nonCollidable);
fromCache = false;
}
if (!fromCache) {
cacheResult(overlayRes.intersects, RayPickResult(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, ray, overlayRes.surfaceNormal),
overlayKey, res, rayKey, results);
}
}
if (rayPick->getFilter().doesPickAvatars()) {
RayCacheKey avatarKey = { rayPick->getFilter().getAvatarFlags(), rayPick->getIncludeItems(), rayPick->getIgnoreItems() };
if (!checkAndCompareCachedResults(rayKey, results, res, avatarKey)) {
RayToAvatarIntersectionResult avatarRes = DependencyManager::get<AvatarManager>()->findRayIntersectionVector(ray,
rayPick->getIncludeItemsAs<EntityItemID>(), rayPick->getIgnoreItemsAs<EntityItemID>());
cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, ray), avatarKey, res, rayKey, results);
}
}
// Can't intersect with HUD in desktop mode
if (rayPick->getFilter().doesPickHUD() && DependencyManager::get<HMDScriptingInterface>()->isHMDMode()) {
RayPickFilter::Flags hudMask = rayPick->getFilter().getHUDFlags();
RayCacheKey hudKey = { rayPick->getFilter().getHUDFlags() };
if (!checkAndCompareCachedResults(rayKey, results, res, hudKey)) {
glm::vec3 hudRes = DependencyManager::get<HMDScriptingInterface>()->calculateRayUICollisionPoint(ray.origin, ray.direction);
cacheResult(true, RayPickResult(IntersectionType::HUD, 0, glm::distance(ray.origin, hudRes), hudRes, ray), hudKey, res, rayKey, results);
}
}
if (rayPick->getMaxDistance() == 0.0f || (rayPick->getMaxDistance() > 0.0f && res.distance < rayPick->getMaxDistance())) {
rayPick->setRayPickResult(res);
} else {
rayPick->setRayPickResult(RayPickResult(ray));
}
}
}
QUuid RayPickManager::createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, float maxDistance, bool enabled) {
QUuid RayPickManager::createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, float maxDistance, bool enabled) {
auto newRayPick = std::make_shared<JointRayPick>(jointName, posOffset, dirOffset, filter, maxDistance, enabled);
QUuid id = QUuid::createUuid();
withWriteLock([&] {
_rayPicks[id] = newRayPick;
_picks[id] = newRayPick;
});
return id;
}
QUuid RayPickManager::createRayPick(const RayPickFilter& filter, float maxDistance, bool enabled) {
QUuid RayPickManager::createRayPick(const PickFilter& filter, float maxDistance, bool enabled) {
QUuid id = QUuid::createUuid();
auto newRayPick = std::make_shared<MouseRayPick>(filter, maxDistance, enabled);
withWriteLock([&] {
_rayPicks[id] = newRayPick;
_picks[id] = newRayPick;
});
return id;
}
QUuid RayPickManager::createRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, float maxDistance, bool enabled) {
QUuid RayPickManager::createRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, float maxDistance, bool enabled) {
QUuid id = QUuid::createUuid();
auto newRayPick = std::make_shared<StaticRayPick>(position, direction, filter, maxDistance, enabled);
withWriteLock([&] {
_rayPicks[id] = newRayPick;
_picks[id] = newRayPick;
});
return id;
}
void RayPickManager::removeRayPick(const QUuid& uid) {
withWriteLock([&] {
_rayPicks.remove(uid);
});
}
RayPick::Pointer RayPickManager::findRayPick(const QUuid& uid) const {
return resultWithReadLock<RayPick::Pointer>([&] {
if (_rayPicks.contains(uid)) {
return _rayPicks[uid];
}
return RayPick::Pointer();
});
}
void RayPickManager::enableRayPick(const QUuid& uid) const {
auto rayPick = findRayPick(uid);
if (rayPick) {
rayPick->enable();
}
}
void RayPickManager::disableRayPick(const QUuid& uid) const {
auto rayPick = findRayPick(uid);
if (rayPick) {
rayPick->disable();
}
}
RayPickResult RayPickManager::getPrevRayPickResult(const QUuid& uid) const {
auto rayPick = findRayPick(uid);
if (rayPick) {
return rayPick->getPrevRayPickResult();
}
return RayPickResult();
}
void RayPickManager::setPrecisionPicking(const QUuid& uid, bool precisionPicking) const {
auto rayPick = findRayPick(uid);
if (rayPick) {
rayPick->setPrecisionPicking(precisionPicking);
}
}
void RayPickManager::setIgnoreItems(const QUuid& uid, const QVector<QUuid>& ignore) const {
auto rayPick = findRayPick(uid);
if (rayPick) {
rayPick->setIgnoreItems(ignore);
}
}
void RayPickManager::setIncludeItems(const QUuid& uid, const QVector<QUuid>& include) const {
auto rayPick = findRayPick(uid);
if (rayPick) {
rayPick->setIncludeItems(include);
}
}
}

View file

@ -11,64 +11,16 @@
#ifndef hifi_RayPickManager_h
#define hifi_RayPickManager_h
#include <memory>
#include <unordered_map>
#include <queue>
#include <QtCore/QObject>
#include <RegisteredMetaTypes.h>
#include <pointers/rays/RayPick.h>
#include "PickManager.h"
class RayPickResult;
typedef struct RayCacheKey {
RayPickFilter::Flags mask;
QVector<QUuid> include;
QVector<QUuid> ignore;
bool operator==(const RayCacheKey& other) const {
return (mask == other.mask && include == other.include && ignore == other.ignore);
}
} RayCacheKey;
namespace std {
template <>
struct hash<RayCacheKey> {
size_t operator()(const RayCacheKey& k) const {
return ((hash<RayPickFilter::Flags>()(k.mask) ^ (qHash(k.include) << 1)) >> 1) ^ (qHash(k.ignore) << 1);
}
};
}
class RayPickManager : protected ReadWriteLockable {
class RayPickManager : public PickManager<PickRay> {
public:
void update();
QUuid createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled);
QUuid createRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled);
QUuid createRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance, const bool enabled);
void removeRayPick(const QUuid& uid);
void enableRayPick(const QUuid& uid) const;
void disableRayPick(const QUuid& uid) const;
RayPickResult getPrevRayPickResult(const QUuid& uid) const;
void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const;
void setIgnoreItems(const QUuid& uid, const QVector<QUuid>& ignore) const;
void setIncludeItems(const QUuid& uid, const QVector<QUuid>& include) const;
private:
RayPick::Pointer findRayPick(const QUuid& uid) const;
QHash<QUuid, RayPick::Pointer> _rayPicks;
typedef QHash<QPair<glm::vec3, glm::vec3>, std::unordered_map<RayCacheKey, RayPickResult>> RayPickCache;
// Returns true if this ray exists in the cache, and if it does, update res if the cached result is closer
bool checkAndCompareCachedResults(QPair<glm::vec3, glm::vec3>& ray, RayPickCache& cache, RayPickResult& res, const RayCacheKey& key);
void cacheResult(const bool intersects, const RayPickResult& resTemp, const RayCacheKey& key, RayPickResult& res, QPair<glm::vec3, glm::vec3>& ray, RayPickCache& cache);
QUuid createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, const float maxDistance, const bool enabled);
QUuid createRayPick(const PickFilter& filter, const float maxDistance, const bool enabled);
QUuid createRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, const float maxDistance, const bool enabled);
};
#endif // hifi_RayPickManager_h

View file

@ -7,13 +7,13 @@
//
#include "StaticRayPick.h"
StaticRayPick::StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance, const bool enabled) :
StaticRayPick::StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, const float maxDistance, const bool enabled) :
RayPick(filter, maxDistance, enabled),
_pickRay(position, direction)
{
}
const PickRay StaticRayPick::getPickRay(bool& valid) const {
const PickRay StaticRayPick::getMathematicalPick(bool& valid) const {
valid = true;
return _pickRay;
}

View file

@ -13,9 +13,9 @@
class StaticRayPick : public RayPick {
public:
StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false);
StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false);
const PickRay getPickRay(bool& valid) const override;
const PickRay getMathematicalPick(bool& valid) const override;
private:
PickRay _pickRay;

View file

@ -1,75 +0,0 @@
//
// Created by Sam Gondelman 7/11/2017
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "RayPick.h"
const RayPickFilter RayPickFilter::NOTHING;
RayPick::RayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled) :
_filter(filter),
_maxDistance(maxDistance),
_enabled(enabled)
{
}
void RayPick::enable(bool enabled) {
withWriteLock([&] {
_enabled = enabled;
});
}
RayPickFilter RayPick::getFilter() const {
return resultWithReadLock<RayPickFilter>([&] {
return _filter;
});
}
float RayPick::getMaxDistance() const {
return _maxDistance;
}
bool RayPick::isEnabled() const {
return _enabled;
}
void RayPick::setPrecisionPicking(bool precisionPicking) {
withWriteLock([&]{
_filter.setFlag(RayPickFilter::PICK_COARSE, !precisionPicking);
});
}
void RayPick::setRayPickResult(const RayPickResult& rayPickResult) {
withWriteLock([&] {
_prevResult = rayPickResult;
});
}
QVector<QUuid> RayPick::getIgnoreItems() const {
return _ignoreItems;
}
QVector<QUuid> RayPick::getIncludeItems() const {
return _includeItems;
}
RayPickResult RayPick::getPrevRayPickResult() const {
return resultWithReadLock<RayPickResult>([&] {
return _prevResult;
});
}
void RayPick::setIgnoreItems(const QVector<QUuid>& ignoreItems) {
withWriteLock([&] {
_ignoreItems = ignoreItems;
});
}
void RayPick::setIncludeItems(const QVector<QUuid>& includeItems) {
withWriteLock([&] {
_includeItems = includeItems;
});
}

View file

@ -131,7 +131,22 @@ public:
PickRay(const glm::vec3& origin, const glm::vec3 direction) : origin(origin), direction(direction) {}
glm::vec3 origin;
glm::vec3 direction;
bool operator==(const PickRay& other) const {
return (origin == other.origin && direction == other.direction);
}
};
namespace std {
template <>
struct hash<glm::vec3> {
size_t operator()(const glm::vec3& a) const {
return ((hash<float>()(a.x) ^ (hash<float>()(a.y) << 1)) >> 1) ^ (hash<float>()(a.z) << 1);
}
};
}
uint qHash(const PickRay& a) {
return (uint)(std::hash<glm::vec3>()(a.origin) ^ (std::hash<glm::vec3>()(a.direction) << 1));
}
Q_DECLARE_METATYPE(PickRay)
QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay);
void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay);