Implement Entities.findInFrustum() method

This commit is contained in:
David Rowe 2016-09-09 18:57:48 +12:00
parent ce58edc4e0
commit 38c2efa22f
8 changed files with 148 additions and 12 deletions

View file

@ -21,6 +21,7 @@
#include "EntityTree.h"
#include "LightEntityItem.h"
#include "ModelEntityItem.h"
#include "QVariantGLM.h"
#include "SimulationOwner.h"
#include "ZoneEntityItem.h"
@ -550,14 +551,6 @@ QVector<QUuid> EntityScriptingInterface::findEntities(const glm::vec3& center, f
return result;
}
QVector<QUuid> EntityScriptingInterface::findEntitiesInView(const glm::vec3& center, float radius) const {
QVector<QUuid> result;
// TODO
return result;
}
QVector<QUuid> EntityScriptingInterface::findEntitiesInBox(const glm::vec3& corner, const glm::vec3& dimensions) const {
QVector<QUuid> result;
if (_entityTree) {
@ -574,6 +567,48 @@ QVector<QUuid> EntityScriptingInterface::findEntitiesInBox(const glm::vec3& corn
return result;
}
QVector<QUuid> EntityScriptingInterface::findEntitiesInFrustum(QVariantMap frustum) const {
QVector<QUuid> result;
const QString POSITION_PROPERTY = "position";
bool positionOK = frustum.contains(POSITION_PROPERTY);
glm::vec3 position = positionOK ? qMapToGlmVec3(frustum[POSITION_PROPERTY]) : glm::vec3();
const QString ORIENTATION_PROPERTY = "orientation";
bool orientationOK = frustum.contains(ORIENTATION_PROPERTY);
glm::quat orientation = orientationOK ? qMapToGlmQuat(frustum[ORIENTATION_PROPERTY]) : glm::quat();
const QString PROJECTION_PROPERTY = "projection";
bool projectionOK = frustum.contains(PROJECTION_PROPERTY);
glm::mat4 projection = projectionOK ? qMapToGlmMat4(frustum[PROJECTION_PROPERTY]) : glm::mat4();
const QString CENTER_RADIUS_PROPERTY = "centerRadius";
bool centerRadiusOK = frustum.contains(CENTER_RADIUS_PROPERTY);
float centerRadius = centerRadiusOK ? frustum[CENTER_RADIUS_PROPERTY].toFloat() : 0.0f;
if (positionOK && orientationOK && projectionOK && centerRadiusOK) {
ViewFrustum viewFrustum;
viewFrustum.setPosition(position);
viewFrustum.setOrientation(orientation);
viewFrustum.setProjection(projection);
viewFrustum.setCenterRadius(centerRadius);
viewFrustum.calculate();
if (_entityTree) {
QVector<EntityItemPointer> entities;
_entityTree->withReadLock([&] {
_entityTree->findEntities(viewFrustum, entities);
});
foreach(EntityItemPointer entity, entities) {
result << entity->getEntityItemID();
}
}
}
return result;
}
RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking,
const QScriptValue& entityIdsToInclude, const QScriptValue& entityIdsToDiscard) {

View file

@ -127,14 +127,19 @@ public slots:
/// this function will not find any models in script engine contexts which don't have access to models
Q_INVOKABLE QVector<QUuid> findEntities(const glm::vec3& center, float radius) const;
/// finds models within the search sphere specified by the center point and radius
/// this function will not find any models in script engine contexts which don't have access to models
Q_INVOKABLE QVector<QUuid> findEntitiesInView(const glm::vec3& center, float radius) const;
/// finds models within the box specified by the corner and dimensions
/// this function will not find any models in script engine contexts which don't have access to models
Q_INVOKABLE QVector<QUuid> findEntitiesInBox(const glm::vec3& corner, const glm::vec3& dimensions) const;
/// finds models within the frustum
/// the frustum must have the following properties:
/// - position
/// - orientation
/// - projection
/// - centerRadius
/// this function will not find any models in script engine contexts which don't have access to models
Q_INVOKABLE QVector<QUuid> findEntitiesInFrustum(QVariantMap frustum) const;
/// If the scripting context has visible entities, this will determine a ray intersection, the results
/// may be inaccurate if the engine is unable to access the visible entities, in which case result.accurate
/// will be false.

View file

@ -688,6 +688,31 @@ void EntityTree::findEntities(const AABox& box, QVector<EntityItemPointer>& foun
foundEntities.swap(args._foundEntities);
}
class FindInFrustumArgs {
public:
ViewFrustum frustum;
QVector<EntityItemPointer> entities;
};
bool EntityTree::findInFrustumOperation(OctreeElementPointer element, void* extraData) {
FindInFrustumArgs* args = static_cast<FindInFrustumArgs*>(extraData);
if (element->isInView(args->frustum)) {
EntityTreeElementPointer entityTreeElement = std::static_pointer_cast<EntityTreeElement>(element);
entityTreeElement->getEntities(args->frustum, args->entities);
return true;
}
return false;
}
// NOTE: assumes caller has handled locking
void EntityTree::findEntities(const ViewFrustum& frustum, QVector<EntityItemPointer>& foundEntities) {
FindInFrustumArgs args = { frustum, QVector<EntityItemPointer>() };
// NOTE: This should use recursion, since this is a spatial operation
recurseTreeWithOperation(findInFrustumOperation, &args);
// swap the two lists of entity pointers instead of copy
foundEntities.swap(args.entities);
}
EntityItemPointer EntityTree::findEntityByID(const QUuid& id) {
EntityItemID entityID(id);
return findEntityByEntityItemID(entityID);

View file

@ -153,6 +153,11 @@ public:
/// \remark Side effect: any initial contents in entities will be lost
void findEntities(const AABox& box, QVector<EntityItemPointer>& foundEntities);
/// finds all entities within a frustum
/// \parameter frustum the query frustum
/// \param foundEntities[out] vector of EntityItemPointer
void findEntities(const ViewFrustum& frustum, QVector<EntityItemPointer>& foundEntities);
void addNewlyCreatedHook(NewlyCreatedEntityHook* hook);
void removeNewlyCreatedHook(NewlyCreatedEntityHook* hook);
@ -276,6 +281,7 @@ protected:
static bool findInSphereOperation(OctreeElementPointer element, void* extraData);
static bool findInCubeOperation(OctreeElementPointer element, void* extraData);
static bool findInBoxOperation(OctreeElementPointer element, void* extraData);
static bool findInFrustumOperation(OctreeElementPointer element, void* extraData);
static bool sendEntitiesOperation(OctreeElementPointer element, void* extraData);
void notifyNewlyCreatedEntity(const EntityItem& newEntity, const SharedNodePointer& senderNode);

View file

@ -796,6 +796,17 @@ void EntityTreeElement::getEntities(const AABox& box, QVector<EntityItemPointer>
});
}
void EntityTreeElement::getEntities(const ViewFrustum& frustum, QVector<EntityItemPointer>& foundEntities) {
forEachEntity([&](EntityItemPointer entity) {
bool success;
AABox entityBox = entity->getAABox(success);
// FIXME - See FIXMEs for similar methods above.
if (!success || frustum.boxIntersectsFrustum(entityBox) || frustum.boxIntersectsKeyhole(entityBox)) {
foundEntities.push_back(entity);
}
});
}
EntityItemPointer EntityTreeElement::getEntityWithEntityItemID(const EntityItemID& id) const {
EntityItemPointer foundEntity = NULL;
withReadLock([&] {

View file

@ -194,6 +194,11 @@ public:
/// \param entities[out] vector of non-const EntityItemPointer
void getEntities(const AABox& box, QVector<EntityItemPointer>& foundEntities);
/// finds all entities that touch a frustum
/// \param frustum the query frustum
/// \param entities[out] vector of non-const EntityItemPointer
void getEntities(const ViewFrustum& frustum, QVector<EntityItemPointer>& foundEntities);
EntityItemPointer getEntityWithID(uint32_t id) const;
EntityItemPointer getEntityWithEntityItemID(const EntityItemID& id) const;
void getEntitiesInside(const AACube& box, QVector<EntityItemPointer>& foundEntities);

View file

@ -62,3 +62,48 @@ void qListtoRgbColor(const QVariant& q, rgbColor& returnValue) {
returnValue[GREEN_INDEX] = qList[GREEN_INDEX].toInt();
returnValue[BLUE_INDEX] = qList[BLUE_INDEX].toInt();
}
glm::vec3 qMapToGlmVec3(const QVariant& q) {
QVariantMap qMap = q.toMap();
if (qMap.contains("x") && qMap.contains("y") && qMap.contains("y")) {
return glm::vec3(
qMap["x"].toFloat(),
qMap["y"].toFloat(),
qMap["z"].toFloat()
);
} else {
return glm::vec3();
}
}
glm::quat qMapToGlmQuat(const QVariant& q) {
QVariantMap qMap = q.toMap();
if (qMap.contains("w") && qMap.contains("x") && qMap.contains("y") && qMap.contains("z")) {
return glm::quat(
qMap["w"].toFloat(),
qMap["x"].toFloat(),
qMap["y"].toFloat(),
qMap["z"].toFloat()
);
} else {
return glm::quat();
}
}
glm::mat4 qMapToGlmMat4(const QVariant& q) {
QVariantMap qMap = q.toMap();
if (qMap.contains("r0c0") && qMap.contains("r1c0") && qMap.contains("r2c0") && qMap.contains("r3c0")
&& qMap.contains("r0c1") && qMap.contains("r1c1") && qMap.contains("r2c1") && qMap.contains("r3c1")
&& qMap.contains("r0c2") && qMap.contains("r1c2") && qMap.contains("r2c2") && qMap.contains("r3c2")
&& qMap.contains("r0c3") && qMap.contains("r1c3") && qMap.contains("r2c3") && qMap.contains("r3c3")) {
return glm::mat4(
qMap["r0c0"].toFloat(), qMap["r1c0"].toFloat(), qMap["r2c0"].toFloat(), qMap["r3c0"].toFloat(),
qMap["r0c1"].toFloat(), qMap["r1c1"].toFloat(), qMap["r2c1"].toFloat(), qMap["r3c1"].toFloat(),
qMap["r0c2"].toFloat(), qMap["r1c2"].toFloat(), qMap["r2c2"].toFloat(), qMap["r3c2"].toFloat(),
qMap["r0c3"].toFloat(), qMap["r1c3"].toFloat(), qMap["r2c3"].toFloat(), qMap["r3c3"].toFloat()
);
} else {
return glm::mat4();
}
}

View file

@ -27,3 +27,7 @@ QVariantMap glmToQMap(const glm::quat& glmQuat);
glm::vec3 qListToGlmVec3(const QVariant& q);
glm::quat qListToGlmQuat(const QVariant& q);
void qListtoRgbColor(const QVariant& q, rgbColor& returnValue);
glm::vec3 qMapToGlmVec3(const QVariant& q);
glm::quat qMapToGlmQuat(const QVariant& q);
glm::mat4 qMapToGlmMat4(const QVariant& q);