Merge pull request #2920 from ZappoMan/aacube

Add RayPick support for models
This commit is contained in:
Clément Brisset 2014-05-24 17:03:59 -07:00
commit 6bb933996f
37 changed files with 1157 additions and 276 deletions

View file

@ -41,6 +41,22 @@ function mouseMoveEvent(event) {
print("voxelAt.x/y/z/s=" + voxelAt.x + ", " + voxelAt.y + ", " + voxelAt.z + ": " + voxelAt.s);
print("voxelAt.red/green/blue=" + voxelAt.red + ", " + voxelAt.green + ", " + voxelAt.blue);
}
intersection = Models.findRayIntersection(pickRay);
if (!intersection.accurate) {
print(">>> NOTE: intersection not accurate. will try calling Models.findRayIntersectionBlocking()");
intersection = Models.findRayIntersectionBlocking(pickRay);
print(">>> AFTER BLOCKING CALL intersection.accurate=" + intersection.accurate);
}
if (intersection.intersects) {
print("intersection modelID.id=" + intersection.modelID.id);
print("intersection modelProperties.modelURL=" + intersection.modelProperties.modelURL);
print("intersection face=" + intersection.face);
print("intersection distance=" + intersection.distance);
print("intersection intersection.x/y/z=" + intersection.intersection.x + ", "
+ intersection.intersection.y + ", " + intersection.intersection.z);
}
}
Controller.mouseMoveEvent.connect(mouseMoveEvent);

View file

@ -2085,10 +2085,10 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
if (rootCode) {
VoxelPositionSize rootDetails;
voxelDetailsForCode(rootCode, rootDetails);
AABox serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
serverBounds.scale(TREE_SCALE);
ViewFrustum::location serverFrustumLocation = _viewFrustum.boxInFrustum(serverBounds);
ViewFrustum::location serverFrustumLocation = _viewFrustum.cubeInFrustum(serverBounds);
if (serverFrustumLocation != ViewFrustum::OUTSIDE) {
inViewServers++;
@ -2151,10 +2151,10 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
if (rootCode) {
VoxelPositionSize rootDetails;
voxelDetailsForCode(rootCode, rootDetails);
AABox serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
serverBounds.scale(TREE_SCALE);
ViewFrustum::location serverFrustumLocation = _viewFrustum.boxInFrustum(serverBounds);
ViewFrustum::location serverFrustumLocation = _viewFrustum.cubeInFrustum(serverBounds);
if (serverFrustumLocation != ViewFrustum::OUTSIDE) {
inView = true;
} else {

View file

@ -73,6 +73,42 @@ Model* ModelTreeRenderer::getModel(const ModelItem& modelItem) {
return model;
}
void calculateRotatedExtents(Extents& extents, const glm::quat& rotation) {
glm::vec3 bottomLeftNear(extents.minimum.x, extents.minimum.y, extents.minimum.z);
glm::vec3 bottomRightNear(extents.maximum.x, extents.minimum.y, extents.minimum.z);
glm::vec3 bottomLeftFar(extents.minimum.x, extents.minimum.y, extents.maximum.z);
glm::vec3 bottomRightFar(extents.maximum.x, extents.minimum.y, extents.maximum.z);
glm::vec3 topLeftNear(extents.minimum.x, extents.maximum.y, extents.minimum.z);
glm::vec3 topRightNear(extents.maximum.x, extents.maximum.y, extents.minimum.z);
glm::vec3 topLeftFar(extents.minimum.x, extents.maximum.y, extents.maximum.z);
glm::vec3 topRightFar(extents.maximum.x, extents.maximum.y, extents.maximum.z);
glm::vec3 bottomLeftNearRotated = rotation * bottomLeftNear;
glm::vec3 bottomRightNearRotated = rotation * bottomRightNear;
glm::vec3 bottomLeftFarRotated = rotation * bottomLeftFar;
glm::vec3 bottomRightFarRotated = rotation * bottomRightFar;
glm::vec3 topLeftNearRotated = rotation * topLeftNear;
glm::vec3 topRightNearRotated = rotation * topRightNear;
glm::vec3 topLeftFarRotated = rotation * topLeftFar;
glm::vec3 topRightFarRotated = rotation * topRightFar;
extents.minimum = glm::min(bottomLeftNearRotated,
glm::min(bottomRightNearRotated,
glm::min(bottomLeftFarRotated,
glm::min(bottomRightFarRotated,
glm::min(topLeftNearRotated,
glm::min(topRightNearRotated,
glm::min(topLeftFarRotated,topRightFarRotated)))))));
extents.maximum = glm::max(bottomLeftNearRotated,
glm::max(bottomRightNearRotated,
glm::max(bottomLeftFarRotated,
glm::max(bottomRightFarRotated,
glm::max(topLeftNearRotated,
glm::max(topRightNearRotated,
glm::max(topLeftFarRotated,topRightFarRotated)))))));
}
void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) {
args->_elementsTouched++;
// actually render it here...
@ -91,7 +127,7 @@ void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
if (!isShadowMode && displayElementProxy && numberOfModels > 0) {
glm::vec3 elementCenter = modelTreeElement->getAABox().calcCenter() * (float)TREE_SCALE;
glm::vec3 elementCenter = modelTreeElement->getAACube().calcCenter() * (float)TREE_SCALE;
float elementSize = modelTreeElement->getScale() * (float)TREE_SCALE;
glColor3f(1.0f, 0.0f, 0.0f);
glPushMatrix();
@ -157,9 +193,9 @@ void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
for (uint16_t i = 0; i < numberOfModels; i++) {
ModelItem& modelItem = modelItems[i];
// render modelItem aspoints
AABox modelBox = modelItem.getAABox();
modelBox.scale(TREE_SCALE);
if (args->_viewFrustum->boxInFrustum(modelBox) != ViewFrustum::OUTSIDE) {
AACube modelCube = modelItem.getAACube();
modelCube.scale(TREE_SCALE);
if (args->_viewFrustum->cubeInFrustum(modelCube) != ViewFrustum::OUTSIDE) {
glm::vec3 position = modelItem.getPosition() * (float)TREE_SCALE;
float radius = modelItem.getRadius() * (float)TREE_SCALE;
float size = modelItem.getSize() * (float)TREE_SCALE;
@ -212,10 +248,42 @@ void ModelTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
}
if (!isShadowMode && displayModelBounds) {
glColor3f(0.0f, 1.0f, 0.0f);
glm::vec3 unRotatedMinimum = model->getUnscaledMeshExtents().minimum;
glm::vec3 unRotatedMaximum = model->getUnscaledMeshExtents().maximum;
glm::vec3 unRotatedExtents = unRotatedMaximum - unRotatedMinimum;
float width = unRotatedExtents.x;
float height = unRotatedExtents.y;
float depth = unRotatedExtents.z;
Extents rotatedExtents = model->getUnscaledMeshExtents();
calculateRotatedExtents(rotatedExtents, rotation);
glm::vec3 rotatedSize = rotatedExtents.maximum - rotatedExtents.minimum;
const glm::vec3& modelScale = model->getScale();
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
// draw the orignal bounding cube
glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
glutWireCube(size);
// draw the rotated bounding cube
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
glPushMatrix();
glScalef(rotatedSize.x * modelScale.x, rotatedSize.y * modelScale.y, rotatedSize.z * modelScale.z);
glutWireCube(1.0);
glPopMatrix();
// draw the model relative bounding box
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
glScalef(width * modelScale.x, height * modelScale.y, depth * modelScale.z);
glColor3f(0.0f, 1.0f, 0.0f);
glutWireCube(1.0);
glPopMatrix();
}

View file

@ -1105,8 +1105,7 @@ void Model::scaleToFit() {
// size is our "target size in world space"
// we need to set our model scale so that the extents of the mesh, fit in a cube that size...
glm::vec3 dimensions = modelMeshExtents.maximum - modelMeshExtents.minimum;
float maxDimension = glm::max(glm::max(dimensions.x, dimensions.y), dimensions.z);
float maxDimension = glm::distance(modelMeshExtents.maximum, modelMeshExtents.minimum);
float maxScale = _scaleToFitLargestDimension / maxDimension;
glm::vec3 scale(maxScale, maxScale, maxScale);
setScaleInternal(scale);

View file

@ -81,7 +81,7 @@ void NodeBounds::draw() {
glm::vec3 location(rootDetails.x, rootDetails.y, rootDetails.z);
location *= (float)TREE_SCALE;
AABox serverBounds(location, rootDetails.s * TREE_SCALE);
AACube serverBounds(location, rootDetails.s * TREE_SCALE);
glm::vec3 center = serverBounds.getVertex(BOTTOM_RIGHT_NEAR)
+ ((serverBounds.getVertex(TOP_LEFT_FAR) - serverBounds.getVertex(BOTTOM_RIGHT_NEAR)) / 2.0f);

View file

@ -293,7 +293,7 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser
VoxelPositionSize rootDetails;
voxelDetailsForCode(rootCode, rootDetails);
AABox serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
serverBounds.scale(TREE_SCALE);
serverDetails << " jurisdiction: "
<< qPrintable(rootCodeHex)

View file

@ -1546,6 +1546,8 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
for (QHash<QString, ExtractedMesh>::iterator it = meshes.begin(); it != meshes.end(); it++) {
ExtractedMesh& extracted = it.value();
extracted.mesh.meshExtents.reset();
// accumulate local transforms
QString modelID = models.contains(it.key()) ? it.key() : parentMap.value(it.key());
@ -1556,6 +1558,9 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
glm::vec3 transformedVertex = glm::vec3(modelTransform * glm::vec4(vertex, 1.0f));
geometry.meshExtents.minimum = glm::min(geometry.meshExtents.minimum, transformedVertex);
geometry.meshExtents.maximum = glm::max(geometry.meshExtents.maximum, transformedVertex);
extracted.mesh.meshExtents.minimum = glm::min(extracted.mesh.meshExtents.minimum, transformedVertex);
extracted.mesh.meshExtents.maximum = glm::max(extracted.mesh.meshExtents.maximum, transformedVertex);
}
// look for textures, material properties

View file

@ -150,6 +150,8 @@ public:
QVector<glm::vec4> clusterWeights;
QVector<FBXCluster> clusters;
Extents meshExtents;
bool isEye;

View file

@ -202,7 +202,7 @@ public:
float getSize() const { return _radius * 2.0f; }
/// get maximum dimension in domain scale units (0.0 - 1.0)
AABox getAABox() const { return AABox(getMinimumPoint(), getSize()); }
AACube getAACube() const { return AACube(getMinimumPoint(), getSize()); }
// model related properties
bool hasModel() const { return !_modelURL.isEmpty(); }

View file

@ -116,8 +116,8 @@ void ModelTree::storeModel(const ModelItem& model, const SharedNodePointer& send
// if we didn't find it in the tree, then store it...
if (!theOperator.wasFound()) {
AABox modelBox = model.getAABox();
ModelTreeElement* element = (ModelTreeElement*)getOrCreateChildElementContaining(model.getAABox());
AACube modelCube = model.getAACube();
ModelTreeElement* element = (ModelTreeElement*)getOrCreateChildElementContaining(model.getAACube());
element->storeModel(model);
// In the case where we stored it, we also need to mark the entire "path" down to the model as
@ -270,7 +270,7 @@ bool ModelTree::findNearPointOperation(OctreeElement* element, void* extraData)
ModelTreeElement* modelTreeElement = static_cast<ModelTreeElement*>(element);
glm::vec3 penetration;
bool sphereIntersection = modelTreeElement->getAABox().findSpherePenetration(args->position,
bool sphereIntersection = modelTreeElement->getAACube().findSpherePenetration(args->position,
args->targetRadius, penetration);
// If this modelTreeElement contains the point, then search it...
@ -320,7 +320,7 @@ public:
bool ModelTree::findInSphereOperation(OctreeElement* element, void* extraData) {
FindAllNearPointArgs* args = static_cast<FindAllNearPointArgs*>(extraData);
glm::vec3 penetration;
bool sphereIntersection = element->getAABox().findSpherePenetration(args->position,
bool sphereIntersection = element->getAACube().findSpherePenetration(args->position,
args->targetRadius, penetration);
// If this element contains the point, then search it...
@ -343,31 +343,31 @@ void ModelTree::findModels(const glm::vec3& center, float radius, QVector<const
foundModels.swap(args.models);
}
class FindModelsInBoxArgs {
class FindModelsInCubeArgs {
public:
FindModelsInBoxArgs(const AABox& box)
: _box(box), _foundModels() {
FindModelsInCubeArgs(const AACube& cube)
: _cube(cube), _foundModels() {
}
AABox _box;
AACube _cube;
QVector<ModelItem*> _foundModels;
};
bool ModelTree::findInBoxForUpdateOperation(OctreeElement* element, void* extraData) {
FindModelsInBoxArgs* args = static_cast< FindModelsInBoxArgs*>(extraData);
const AABox& elementBox = element->getAABox();
if (elementBox.touches(args->_box)) {
bool ModelTree::findInCubeForUpdateOperation(OctreeElement* element, void* extraData) {
FindModelsInCubeArgs* args = static_cast< FindModelsInCubeArgs*>(extraData);
const AACube& elementCube = element->getAACube();
if (elementCube.touches(args->_cube)) {
ModelTreeElement* modelTreeElement = static_cast<ModelTreeElement*>(element);
modelTreeElement->getModelsForUpdate(args->_box, args->_foundModels);
modelTreeElement->getModelsForUpdate(args->_cube, args->_foundModels);
return true;
}
return false;
}
void ModelTree::findModelsForUpdate(const AABox& box, QVector<ModelItem*> foundModels) {
FindModelsInBoxArgs args(box);
void ModelTree::findModelsForUpdate(const AACube& cube, QVector<ModelItem*> foundModels) {
FindModelsInCubeArgs args(cube);
lockForRead();
recurseTreeWithOperation(findInBoxForUpdateOperation, &args);
recurseTreeWithOperation(findInCubeForUpdateOperation, &args);
unlock();
// swap the two lists of model pointers instead of copy
foundModels.swap(args._foundModels);
@ -507,7 +507,7 @@ void ModelTree::update() {
bool shouldDie = args._movingModels[i].getShouldDie();
// if the particle is still inside our total bounds, then re-add it
AABox treeBounds = getRoot()->getAABox();
AACube treeBounds = getRoot()->getAACube();
if (!shouldDie && treeBounds.contains(args._movingModels[i].getPosition())) {
storeModel(args._movingModels[i]);

View file

@ -58,11 +58,11 @@ public:
/// \remark Side effect: any initial contents in foundModels will be lost
void findModels(const glm::vec3& center, float radius, QVector<const ModelItem*>& foundModels);
/// finds all models that touch a box
/// \param box the query box
/// finds all models that touch a cube
/// \param cube the query cube
/// \param foundModels[out] vector of non-const ModelItem*
/// \remark Side effect: any initial contents in models will be lost
void findModelsForUpdate(const AABox& box, QVector<ModelItem*> foundModels);
void findModelsForUpdate(const AACube& cube, QVector<ModelItem*> foundModels);
void addNewlyCreatedHook(NewlyCreatedModelHook* hook);
void removeNewlyCreatedHook(NewlyCreatedModelHook* hook);
@ -86,7 +86,7 @@ private:
static bool findByIDOperation(OctreeElement* element, void* extraData);
static bool findAndDeleteOperation(OctreeElement* element, void* extraData);
static bool findAndUpdateModelItemIDOperation(OctreeElement* element, void* extraData);
static bool findInBoxForUpdateOperation(OctreeElement* element, void* extraData);
static bool findInCubeForUpdateOperation(OctreeElement* element, void* extraData);
void notifyNewlyCreatedModel(const ModelItem& newModel, const SharedNodePointer& senderNode);

View file

@ -57,9 +57,9 @@ bool ModelTreeElement::appendElementData(OctreePacketData* packetData, EncodeBit
for (uint16_t i = 0; i < _modelItems->size(); i++) {
if (params.viewFrustum) {
const ModelItem& model = (*_modelItems)[i];
AABox modelBox = model.getAABox();
modelBox.scale(TREE_SCALE);
if (params.viewFrustum->boxInFrustum(modelBox) != ViewFrustum::OUTSIDE) {
AACube modelCube = model.getAACube();
modelCube.scale(TREE_SCALE);
if (params.viewFrustum->cubeInFrustum(modelCube) != ViewFrustum::OUTSIDE) {
indexesOfModelsToInclude << i;
numberOfModels++;
}
@ -86,18 +86,18 @@ bool ModelTreeElement::appendElementData(OctreePacketData* packetData, EncodeBit
bool ModelTreeElement::containsModelBounds(const ModelItem& model) const {
glm::vec3 clampedMin = glm::clamp(model.getMinimumPoint(), 0.0f, 1.0f);
glm::vec3 clampedMax = glm::clamp(model.getMaximumPoint(), 0.0f, 1.0f);
return _box.contains(clampedMin) && _box.contains(clampedMax);
return _cube.contains(clampedMin) && _cube.contains(clampedMax);
}
bool ModelTreeElement::bestFitModelBounds(const ModelItem& model) const {
glm::vec3 clampedMin = glm::clamp(model.getMinimumPoint(), 0.0f, 1.0f);
glm::vec3 clampedMax = glm::clamp(model.getMaximumPoint(), 0.0f, 1.0f);
if (_box.contains(clampedMin) && _box.contains(clampedMax)) {
if (_cube.contains(clampedMin) && _cube.contains(clampedMax)) {
int childForMinimumPoint = getMyChildContainingPoint(clampedMin);
int childForMaximumPoint = getMyChildContainingPoint(clampedMax);
// if this is a really small box, then it's close enough!
if (_box.getScale() <= SMALLEST_REASONABLE_OCTREE_ELEMENT_SCALE) {
if (_cube.getScale() <= SMALLEST_REASONABLE_OCTREE_ELEMENT_SCALE) {
return true;
}
// If I contain both the minimum and maximum point, but two different children of mine
@ -140,6 +140,37 @@ void ModelTreeElement::update(ModelTreeUpdateArgs& args) {
}
}
bool ModelTreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
void** intersectedObject) {
// only called if we do intersect our bounding cube, but find if we actually intersect with models...
QList<ModelItem>::iterator modelItr = _modelItems->begin();
QList<ModelItem>::const_iterator modelEnd = _modelItems->end();
bool somethingIntersected = false;
while(modelItr != modelEnd) {
ModelItem& model = (*modelItr);
AACube modelCube = model.getAACube();
float localDistance;
BoxFace localFace;
// if the ray doesn't intersect with our cube, we can stop searching!
if (modelCube.findRayIntersection(origin, direction, localDistance, localFace)) {
if (localDistance < distance) {
distance = localDistance;
face = localFace;
*intersectedObject = (void*)(&model);
somethingIntersected = true;
}
}
++modelItr;
}
return somethingIntersected;
}
bool ModelTreeElement::findSpherePenetration(const glm::vec3& center, float radius,
glm::vec3& penetration, void** penetratedObject) const {
QList<ModelItem>::iterator modelItr = _modelItems->begin();
@ -282,18 +313,18 @@ void ModelTreeElement::getModels(const glm::vec3& searchPosition, float searchRa
}
}
void ModelTreeElement::getModelsForUpdate(const AABox& box, QVector<ModelItem*>& foundModels) {
void ModelTreeElement::getModelsForUpdate(const AACube& box, QVector<ModelItem*>& foundModels) {
QList<ModelItem>::iterator modelItr = _modelItems->begin();
QList<ModelItem>::iterator modelEnd = _modelItems->end();
AABox modelBox;
AACube modelCube;
while(modelItr != modelEnd) {
ModelItem* model = &(*modelItr);
float radius = model->getRadius();
// NOTE: we actually do box-box collision queries here, which is sloppy but good enough for now
// TODO: decide whether to replace modelBox-box query with sphere-box (requires a square root
// NOTE: we actually do cube-cube collision queries here, which is sloppy but good enough for now
// TODO: decide whether to replace modelCube-cube query with sphere-cube (requires a square root
// but will be slightly more accurate).
modelBox.setBox(model->getPosition() - glm::vec3(radius), 2.f * radius);
if (modelBox.touches(_box)) {
modelCube.setBox(model->getPosition() - glm::vec3(radius), 2.f * radius);
if (modelCube.touches(_cube)) {
foundModels.push_back(model);
}
++modelItr;

View file

@ -100,6 +100,11 @@ public:
virtual bool isRendered() const { return getShouldRender(); }
virtual bool deleteApproved() const { return !hasModels(); }
virtual bool canRayIntersect() const { return hasModels(); }
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
void** intersectedObject);
virtual bool findSpherePenetration(const glm::vec3& center, float radius,
glm::vec3& penetration, void** penetratedObject) const;
@ -125,7 +130,7 @@ public:
/// finds all models that touch a box
/// \param box the query box
/// \param models[out] vector of non-const ModelItem*
void getModelsForUpdate(const AABox& box, QVector<ModelItem*>& foundModels);
void getModelsForUpdate(const AACube& box, QVector<ModelItem*>& foundModels);
const ModelItem* getModelWithID(uint32_t id) const;

View file

@ -173,3 +173,115 @@ QVector<ModelItemID> ModelsScriptingInterface::findModels(const glm::vec3& cente
return result;
}
RayToModelIntersectionResult ModelsScriptingInterface::findRayIntersection(const PickRay& ray) {
return findRayIntersectionWorker(ray, Octree::TryLock);
}
RayToModelIntersectionResult ModelsScriptingInterface::findRayIntersectionBlocking(const PickRay& ray) {
return findRayIntersectionWorker(ray, Octree::Lock);
}
RayToModelIntersectionResult ModelsScriptingInterface::findRayIntersectionWorker(const PickRay& ray,
Octree::lockType lockType) {
RayToModelIntersectionResult result;
if (_modelTree) {
OctreeElement* element;
ModelItem* intersectedModel;
result.intersects = _modelTree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face,
(void**)&intersectedModel, lockType, &result.accurate);
if (result.intersects && intersectedModel) {
result.modelID = intersectedModel->getModelItemID();
result.modelProperties = intersectedModel->getProperties();
result.intersection = ray.origin + (ray.direction * result.distance);
}
}
return result;
}
RayToModelIntersectionResult::RayToModelIntersectionResult() :
intersects(false),
accurate(true), // assume it's accurate
modelID(),
modelProperties(),
distance(0),
face()
{
};
QScriptValue RayToModelIntersectionResultToScriptValue(QScriptEngine* engine, const RayToModelIntersectionResult& value) {
QScriptValue obj = engine->newObject();
obj.setProperty("intersects", value.intersects);
obj.setProperty("accurate", value.accurate);
QScriptValue modelItemValue = ModelItemIDtoScriptValue(engine, value.modelID);
obj.setProperty("modelID", modelItemValue);
QScriptValue modelPropertiesValue = ModelItemPropertiesToScriptValue(engine, value.modelProperties);
obj.setProperty("modelProperties", modelPropertiesValue);
obj.setProperty("distance", value.distance);
QString faceName = "";
// handle BoxFace
switch (value.face) {
case MIN_X_FACE:
faceName = "MIN_X_FACE";
break;
case MAX_X_FACE:
faceName = "MAX_X_FACE";
break;
case MIN_Y_FACE:
faceName = "MIN_Y_FACE";
break;
case MAX_Y_FACE:
faceName = "MAX_Y_FACE";
break;
case MIN_Z_FACE:
faceName = "MIN_Z_FACE";
break;
case MAX_Z_FACE:
faceName = "MAX_Z_FACE";
break;
case UNKNOWN_FACE:
faceName = "UNKNOWN_FACE";
break;
}
obj.setProperty("face", faceName);
QScriptValue intersection = vec3toScriptValue(engine, value.intersection);
obj.setProperty("intersection", intersection);
return obj;
}
void RayToModelIntersectionResultFromScriptValue(const QScriptValue& object, RayToModelIntersectionResult& value) {
value.intersects = object.property("intersects").toVariant().toBool();
value.accurate = object.property("accurate").toVariant().toBool();
QScriptValue modelIDValue = object.property("modelID");
if (modelIDValue.isValid()) {
ModelItemIDfromScriptValue(modelIDValue, value.modelID);
}
QScriptValue modelPropertiesValue = object.property("modelProperties");
if (modelPropertiesValue.isValid()) {
ModelItemPropertiesFromScriptValue(modelPropertiesValue, value.modelProperties);
}
value.distance = object.property("distance").toVariant().toFloat();
QString faceName = object.property("face").toVariant().toString();
if (faceName == "MIN_X_FACE") {
value.face = MIN_X_FACE;
} else if (faceName == "MAX_X_FACE") {
value.face = MAX_X_FACE;
} else if (faceName == "MIN_Y_FACE") {
value.face = MIN_Y_FACE;
} else if (faceName == "MAX_Y_FACE") {
value.face = MAX_Y_FACE;
} else if (faceName == "MIN_Z_FACE") {
value.face = MIN_Z_FACE;
} else {
value.face = MAX_Z_FACE;
};
QScriptValue intersection = object.property("intersection");
if (intersection.isValid()) {
vec3FromScriptValue(intersection, value.intersection);
}
}

View file

@ -15,10 +15,30 @@
#include <QtCore/QObject>
#include <CollisionInfo.h>
#include <Octree.h>
#include <OctreeScriptingInterface.h>
#include <RegisteredMetaTypes.h>
#include "ModelEditPacketSender.h"
class RayToModelIntersectionResult {
public:
RayToModelIntersectionResult();
bool intersects;
bool accurate;
ModelItemID modelID;
ModelItemProperties modelProperties;
float distance;
BoxFace face;
glm::vec3 intersection;
};
Q_DECLARE_METATYPE(RayToModelIntersectionResult)
QScriptValue RayToModelIntersectionResultToScriptValue(QScriptEngine* engine, const RayToModelIntersectionResult& results);
void RayToModelIntersectionResultFromScriptValue(const QScriptValue& object, RayToModelIntersectionResult& results);
/// handles scripting of Model commands from JS passed to assigned clients
class ModelsScriptingInterface : public OctreeScriptingInterface {
Q_OBJECT
@ -59,6 +79,16 @@ public slots:
/// this function will not find any models in script engine contexts which don't have access to models
QVector<ModelItemID> findModels(const glm::vec3& center, float radius) const;
/// If the scripting context has visible voxels, this will determine a ray intersection, the results
/// may be inaccurate if the engine is unable to access the visible voxels, in which case result.accurate
/// will be false.
Q_INVOKABLE RayToModelIntersectionResult findRayIntersection(const PickRay& ray);
/// If the scripting context has visible voxels, this will determine a ray intersection, and will block in
/// order to return an accurate result
Q_INVOKABLE RayToModelIntersectionResult findRayIntersectionBlocking(const PickRay& ray);
signals:
void modelCollisionWithVoxel(const ModelItemID& modelID, const VoxelDetail& voxel, const CollisionInfo& collision);
void modelCollisionWithModel(const ModelItemID& idA, const ModelItemID& idB, const CollisionInfo& collision);
@ -66,6 +96,9 @@ signals:
private:
void queueModelMessage(PacketType packetType, ModelItemID modelID, const ModelItemProperties& properties);
/// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode
RayToModelIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType);
uint32_t _nextCreatorTokenID;
ModelTree* _modelTree;
};

View file

@ -9,27 +9,31 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "AABox.h"
#include "AACube.h"
#include "GeometryUtil.h"
#include "SharedUtil.h"
#include "AABox.h"
#include "GeometryUtil.h"
AABox::AABox(const glm::vec3& corner, float size) :
_corner(corner), _scale(size) {
_corner(corner), _scale(size, size, size) {
};
AABox::AABox() : _corner(0,0,0), _scale(0) {
AABox::AABox(const glm::vec3& corner, const glm::vec3& dimensions) :
_corner(corner), _scale(dimensions) {
};
AABox::AABox() : _corner(0.0f, 0.0f, 0.0f), _scale(0.0f, 0.0f, 0.0f) {
};
glm::vec3 AABox::calcCenter() const {
glm::vec3 center(_corner);
center += (glm::vec3(_scale, _scale, _scale) * 0.5f);
center += (_scale * 0.5f);
return center;
}
glm::vec3 AABox::calcTopFarLeft() const {
glm::vec3 topFarLeft(_corner);
topFarLeft += glm::vec3(_scale, _scale, _scale);
topFarLeft += _scale;
return topFarLeft;
};
@ -41,26 +45,31 @@ void AABox::scale(float scale) {
glm::vec3 AABox::getVertex(BoxVertex vertex) const {
switch (vertex) {
case BOTTOM_LEFT_NEAR:
return _corner + glm::vec3(_scale, 0, 0);
return _corner + glm::vec3(_scale.x, 0, 0);
case BOTTOM_RIGHT_NEAR:
return _corner;
case TOP_RIGHT_NEAR:
return _corner + glm::vec3(0, _scale, 0);
return _corner + glm::vec3(0, _scale.y, 0);
case TOP_LEFT_NEAR:
return _corner + glm::vec3(_scale, _scale, 0);
return _corner + glm::vec3(_scale.x, _scale.y, 0);
case BOTTOM_LEFT_FAR:
return _corner + glm::vec3(_scale, 0, _scale);
return _corner + glm::vec3(_scale.x, 0, _scale.z);
case BOTTOM_RIGHT_FAR:
return _corner + glm::vec3(0, 0, _scale);
return _corner + glm::vec3(0, 0, _scale.z);
case TOP_RIGHT_FAR:
return _corner + glm::vec3(0, _scale, _scale);
return _corner + glm::vec3(0, _scale.y, _scale.z);
default: //quiet windows warnings
case TOP_LEFT_FAR:
return _corner + glm::vec3(_scale, _scale, _scale);
return _corner + _scale;
}
}
void AABox::setBox(const glm::vec3& corner, float scale) {
_corner = corner;
_scale = glm::vec3(scale, scale, scale);
}
void AABox::setBox(const glm::vec3& corner, const glm::vec3& scale) {
_corner = corner;
_scale = scale;
}
@ -68,13 +77,13 @@ void AABox::setBox(const glm::vec3& corner, float scale) {
glm::vec3 AABox::getVertexP(const glm::vec3& normal) const {
glm::vec3 result = _corner;
if (normal.x > 0) {
result.x += _scale;
result.x += _scale.x;
}
if (normal.y > 0) {
result.y += _scale;
result.y += _scale.y;
}
if (normal.z > 0) {
result.z += _scale;
result.z += _scale.z;
}
return result;
}
@ -83,15 +92,15 @@ glm::vec3 AABox::getVertexN(const glm::vec3& normal) const {
glm::vec3 result = _corner;
if (normal.x < 0) {
result.x += _scale;
result.x += _scale.x;
}
if (normal.y < 0) {
result.y += _scale;
result.y += _scale.y;
}
if (normal.z < 0) {
result.z += _scale;
result.z += _scale.z;
}
return result;
@ -103,9 +112,9 @@ static bool isWithin(float value, float corner, float size) {
}
bool AABox::contains(const glm::vec3& point) const {
return isWithin(point.x, _corner.x, _scale) &&
isWithin(point.y, _corner.y, _scale) &&
isWithin(point.z, _corner.z, _scale);
return isWithin(point.x, _corner.x, _scale.x) &&
isWithin(point.y, _corner.y, _scale.y) &&
isWithin(point.z, _corner.z, _scale.z);
}
bool AABox::contains(const AABox& otherBox) const {
@ -119,11 +128,33 @@ bool AABox::contains(const AABox& otherBox) const {
}
bool AABox::touches(const AABox& otherBox) const {
glm::vec3 relativeCenter = _corner - otherBox._corner + (glm::vec3(_scale - otherBox._scale) * 0.5f);
float totalHalfScale = 0.5f * (_scale + otherBox._scale);
return fabs(relativeCenter.x) <= totalHalfScale &&
fabs(relativeCenter.y) <= totalHalfScale &&
fabs(relativeCenter.z) <= totalHalfScale;
glm::vec3 relativeCenter = _corner - otherBox._corner + ((_scale - otherBox._scale) * 0.5f);
glm::vec3 totalHalfScale = (_scale + otherBox._scale) * 0.5f;
return fabs(relativeCenter.x) <= totalHalfScale.x &&
fabs(relativeCenter.y) <= totalHalfScale.y &&
fabs(relativeCenter.z) <= totalHalfScale.z;
}
bool AABox::contains(const AACube& otherCube) const {
for (int v = BOTTOM_LEFT_NEAR; v < TOP_LEFT_FAR; v++) {
glm::vec3 vertex = otherCube.getVertex((BoxVertex)v);
if (!contains(vertex)) {
return false;
}
}
return true;
}
bool AABox::touches(const AACube& otherCube) const {
glm::vec3 relativeCenter = _corner - otherCube.getCorner() + ((_scale - otherCube.getDimensions()) * 0.5f);
glm::vec3 totalHalfScale = (_scale + otherCube.getDimensions()) * 0.5f;
return fabs(relativeCenter.x) <= totalHalfScale.x &&
fabs(relativeCenter.y) <= totalHalfScale.y &&
fabs(relativeCenter.z) <= totalHalfScale.z;
}
// determines whether a value is within the expanded extents
@ -132,9 +163,9 @@ static bool isWithinExpanded(float value, float corner, float size, float expans
}
bool AABox::expandedContains(const glm::vec3& point, float expansion) const {
return isWithinExpanded(point.x, _corner.x, _scale, expansion) &&
isWithinExpanded(point.y, _corner.y, _scale, expansion) &&
isWithinExpanded(point.z, _corner.z, _scale, expansion);
return isWithinExpanded(point.x, _corner.x, _scale.x, expansion) &&
isWithinExpanded(point.y, _corner.y, _scale.y, expansion) &&
isWithinExpanded(point.z, _corner.z, _scale.z, expansion);
}
// finds the intersection between a ray and the facing plane on one axis
@ -156,7 +187,7 @@ bool AABox::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& e
}
// check each axis
glm::vec3 expandedCorner = _corner - glm::vec3(expansion, expansion, expansion);
glm::vec3 expandedSize = glm::vec3(_scale, _scale, _scale) + glm::vec3(expansion, expansion, expansion) * 2.0f;
glm::vec3 expandedSize = _scale + glm::vec3(expansion, expansion, expansion) * 2.0f;
glm::vec3 direction = end - start;
float axisDistance;
return (findIntersection(start.x, direction.x, expandedCorner.x, expandedSize.x, axisDistance) &&
@ -181,23 +212,23 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct
}
// check each axis
float axisDistance;
if ((findIntersection(origin.x, direction.x, _corner.x, _scale, axisDistance) && axisDistance >= 0 &&
isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) &&
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) {
if ((findIntersection(origin.x, direction.x, _corner.x, _scale.x, axisDistance) && axisDistance >= 0 &&
isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale.y) &&
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale.z))) {
distance = axisDistance;
face = direction.x > 0 ? MIN_X_FACE : MAX_X_FACE;
return true;
}
if ((findIntersection(origin.y, direction.y, _corner.y, _scale, axisDistance) && axisDistance >= 0 &&
isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale) &&
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) {
if ((findIntersection(origin.y, direction.y, _corner.y, _scale.y, axisDistance) && axisDistance >= 0 &&
isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x) &&
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale.z))) {
distance = axisDistance;
face = direction.y > 0 ? MIN_Y_FACE : MAX_Y_FACE;
return true;
}
if ((findIntersection(origin.z, direction.z, _corner.z, _scale, axisDistance) && axisDistance >= 0 &&
isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) &&
isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) {
if ((findIntersection(origin.z, direction.z, _corner.z, _scale.z, axisDistance) && axisDistance >= 0 &&
isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale.y) &&
isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x))) {
distance = axisDistance;
face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE;
return true;
@ -260,28 +291,28 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec3& point, BoxFace face) con
switch (face) {
case MIN_X_FACE:
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
glm::vec3(_corner.x, _corner.y + _scale, _corner.z + _scale));
glm::vec3(_corner.x, _corner.y + _scale.y, _corner.z + _scale.z));
case MAX_X_FACE:
return glm::clamp(point, glm::vec3(_corner.x + _scale, _corner.y, _corner.z),
glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale));
return glm::clamp(point, glm::vec3(_corner.x + _scale.x, _corner.y, _corner.z),
glm::vec3(_corner.x + _scale.x, _corner.y + _scale.y, _corner.z + _scale.z));
case MIN_Y_FACE:
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
glm::vec3(_corner.x + _scale, _corner.y, _corner.z + _scale));
glm::vec3(_corner.x + _scale.x, _corner.y, _corner.z + _scale.z));
case MAX_Y_FACE:
return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _scale, _corner.z),
glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale));
return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _scale.y, _corner.z),
glm::vec3(_corner.x + _scale.x, _corner.y + _scale.y, _corner.z + _scale.z));
case MIN_Z_FACE:
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z));
glm::vec3(_corner.x + _scale.z, _corner.y + _scale.y, _corner.z));
default: //quiet windows warnings
case MAX_Z_FACE:
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _scale),
glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale));
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _scale.z),
glm::vec3(_corner.x + _scale.x, _corner.y + _scale.y, _corner.z + _scale.z));
}
}
@ -331,7 +362,7 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4&
glm::vec4 thirdAxisMaxPlane = getPlane((BoxFace)(thirdAxis * 2 + 1));
glm::vec4 offset = glm::vec4(0.0f, 0.0f, 0.0f,
glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), glm::vec3(_scale, _scale, _scale)) * 0.5f);
glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), _scale) * 0.5f);
glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset,
secondAxisMaxPlane + thirdAxisMaxPlane + offset };
@ -355,12 +386,12 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4&
glm::vec4 AABox::getPlane(BoxFace face) const {
switch (face) {
case MIN_X_FACE: return glm::vec4(-1.0f, 0.0f, 0.0f, _corner.x);
case MAX_X_FACE: return glm::vec4(1.0f, 0.0f, 0.0f, -_corner.x - _scale);
case MAX_X_FACE: return glm::vec4(1.0f, 0.0f, 0.0f, -_corner.x - _scale.x);
case MIN_Y_FACE: return glm::vec4(0.0f, -1.0f, 0.0f, _corner.y);
case MAX_Y_FACE: return glm::vec4(0.0f, 1.0f, 0.0f, -_corner.y - _scale);
case MAX_Y_FACE: return glm::vec4(0.0f, 1.0f, 0.0f, -_corner.y - _scale.y);
case MIN_Z_FACE: return glm::vec4(0.0f, 0.0f, -1.0f, _corner.z);
default: //quiet windows warnings
case MAX_Z_FACE: return glm::vec4(0.0f, 0.0f, 1.0f, -_corner.z - _scale);
case MAX_Z_FACE: return glm::vec4(0.0f, 0.0f, 1.0f, -_corner.z - _scale.z);
}
}

View file

@ -17,60 +17,43 @@
#include <glm/glm.hpp>
enum BoxFace {
MIN_X_FACE,
MAX_X_FACE,
MIN_Y_FACE,
MAX_Y_FACE,
MIN_Z_FACE,
MAX_Z_FACE,
UNKNOWN_FACE
};
#include "BoxBase.h"
enum BoxVertex {
BOTTOM_LEFT_NEAR = 0,
BOTTOM_RIGHT_NEAR = 1,
TOP_RIGHT_NEAR = 2,
TOP_LEFT_NEAR = 3,
BOTTOM_LEFT_FAR = 4,
BOTTOM_RIGHT_FAR = 5,
TOP_RIGHT_FAR = 6,
TOP_LEFT_FAR = 7
};
const int FACE_COUNT = 6;
class AACube;
class AABox {
public:
AABox(const glm::vec3& corner, float size);
AABox(const glm::vec3& corner, const glm::vec3& dimensions);
AABox();
~AABox() {};
void setBox(const glm::vec3& corner, float scale);
void setBox(const glm::vec3& corner, const glm::vec3& scale);
// for use in frustum computations
glm::vec3 getVertexP(const glm::vec3& normal) const;
glm::vec3 getVertexN(const glm::vec3& normal) const;
void setBox(const glm::vec3& corner, float scale);
glm::vec3 getVertexP(const glm::vec3& normal) const;
glm::vec3 getVertexN(const glm::vec3& normal) const;
void scale(float scale);
const glm::vec3& getCorner() const { return _corner; }
const glm::vec3& getScale() const { return _scale; }
const glm::vec3& getDimensions() const { return _scale; }
void scale(float scale);
glm::vec3 calcCenter() const;
glm::vec3 calcTopFarLeft() const;
glm::vec3 getVertex(BoxVertex vertex) const;
bool contains(const glm::vec3& point) const;
bool contains(const AABox& otherBox) const;
bool touches(const AABox& otherBox) const;
const glm::vec3& getCorner() const { return _corner; };
float getScale() const { return _scale; }
bool contains(const AACube& otherCube) const;
bool touches(const AACube& otherCube) const;
glm::vec3 calcCenter() const;
glm::vec3 calcTopFarLeft() const;
glm::vec3 getVertex(BoxVertex vertex) const;
bool contains(const glm::vec3& point) const;
bool contains(const AABox& otherBox) const;
bool touches(const AABox& otherBox) const;
bool expandedContains(const glm::vec3& point, float expansion) const;
bool expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const;
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const;
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const;
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const;
bool expandedContains(const glm::vec3& point, float expansion) const;
bool expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const;
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const;
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const;
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const;
private:
glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const;
@ -80,7 +63,7 @@ private:
static BoxFace getOppositeFace(BoxFace face);
glm::vec3 _corner;
float _scale;
glm::vec3 _scale;
};
#endif // hifi_AABox_h

View file

@ -0,0 +1,397 @@
//
// AACube.cpp
// libraries/octree/src
//
// Created by Brad Hefta-Gaub on 04/11/13.
// Copyright 2013 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 "AABox.h"
#include "AACube.h"
#include "GeometryUtil.h"
#include "SharedUtil.h"
AACube::AACube(const glm::vec3& corner, float size) :
_corner(corner), _scale(size) {
};
AACube::AACube() : _corner(0,0,0), _scale(0) {
};
glm::vec3 AACube::calcCenter() const {
glm::vec3 center(_corner);
center += (glm::vec3(_scale, _scale, _scale) * 0.5f);
return center;
}
glm::vec3 AACube::calcTopFarLeft() const {
glm::vec3 topFarLeft(_corner);
topFarLeft += glm::vec3(_scale, _scale, _scale);
return topFarLeft;
};
void AACube::scale(float scale) {
_corner = _corner * scale;
_scale = _scale * scale;
}
glm::vec3 AACube::getVertex(BoxVertex vertex) const {
switch (vertex) {
case BOTTOM_LEFT_NEAR:
return _corner + glm::vec3(_scale, 0, 0);
case BOTTOM_RIGHT_NEAR:
return _corner;
case TOP_RIGHT_NEAR:
return _corner + glm::vec3(0, _scale, 0);
case TOP_LEFT_NEAR:
return _corner + glm::vec3(_scale, _scale, 0);
case BOTTOM_LEFT_FAR:
return _corner + glm::vec3(_scale, 0, _scale);
case BOTTOM_RIGHT_FAR:
return _corner + glm::vec3(0, 0, _scale);
case TOP_RIGHT_FAR:
return _corner + glm::vec3(0, _scale, _scale);
default: //quiet windows warnings
case TOP_LEFT_FAR:
return _corner + glm::vec3(_scale, _scale, _scale);
}
}
void AACube::setBox(const glm::vec3& corner, float scale) {
_corner = corner;
_scale = scale;
}
glm::vec3 AACube::getVertexP(const glm::vec3& normal) const {
glm::vec3 result = _corner;
if (normal.x > 0) {
result.x += _scale;
}
if (normal.y > 0) {
result.y += _scale;
}
if (normal.z > 0) {
result.z += _scale;
}
return result;
}
glm::vec3 AACube::getVertexN(const glm::vec3& normal) const {
glm::vec3 result = _corner;
if (normal.x < 0) {
result.x += _scale;
}
if (normal.y < 0) {
result.y += _scale;
}
if (normal.z < 0) {
result.z += _scale;
}
return result;
}
// determines whether a value is within the extents
static bool isWithin(float value, float corner, float size) {
return value >= corner && value <= corner + size;
}
bool AACube::contains(const glm::vec3& point) const {
return isWithin(point.x, _corner.x, _scale) &&
isWithin(point.y, _corner.y, _scale) &&
isWithin(point.z, _corner.z, _scale);
}
bool AACube::contains(const AACube& otherCube) const {
for (int v = BOTTOM_LEFT_NEAR; v < TOP_LEFT_FAR; v++) {
glm::vec3 vertex = otherCube.getVertex((BoxVertex)v);
if (!contains(vertex)) {
return false;
}
}
return true;
}
bool AACube::touches(const AACube& otherCube) const {
glm::vec3 relativeCenter = _corner - otherCube._corner + (glm::vec3(_scale - otherCube._scale) * 0.5f);
float totalHalfScale = 0.5f * (_scale + otherCube._scale);
return fabs(relativeCenter.x) <= totalHalfScale &&
fabs(relativeCenter.y) <= totalHalfScale &&
fabs(relativeCenter.z) <= totalHalfScale;
}
bool AACube::contains(const AABox& otherBox) const {
for (int v = BOTTOM_LEFT_NEAR; v < TOP_LEFT_FAR; v++) {
glm::vec3 vertex = otherBox.getVertex((BoxVertex)v);
if (!contains(vertex)) {
return false;
}
}
return true;
}
bool AACube::touches(const AABox& otherBox) const {
glm::vec3 myDimensions = glm::vec3(_scale);
glm::vec3 relativeCenter = _corner - otherBox.getCorner() + ((myDimensions - otherBox.getScale()) * 0.5f);
glm::vec3 totalHalfScale = (myDimensions + otherBox.getDimensions()) * 0.5f;
return fabs(relativeCenter.x) <= totalHalfScale.x &&
fabs(relativeCenter.y) <= totalHalfScale.y &&
fabs(relativeCenter.z) <= totalHalfScale.z;
}
// determines whether a value is within the expanded extents
static bool isWithinExpanded(float value, float corner, float size, float expansion) {
return value >= corner - expansion && value <= corner + size + expansion;
}
bool AACube::expandedContains(const glm::vec3& point, float expansion) const {
return isWithinExpanded(point.x, _corner.x, _scale, expansion) &&
isWithinExpanded(point.y, _corner.y, _scale, expansion) &&
isWithinExpanded(point.z, _corner.z, _scale, expansion);
}
// finds the intersection between a ray and the facing plane on one axis
static bool findIntersection(float origin, float direction, float corner, float size, float& distance) {
if (direction > EPSILON) {
distance = (corner - origin) / direction;
return true;
} else if (direction < -EPSILON) {
distance = (corner + size - origin) / direction;
return true;
}
return false;
}
bool AACube::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const {
// handle the trivial cases where the expanded box contains the start or end
if (expandedContains(start, expansion) || expandedContains(end, expansion)) {
return true;
}
// check each axis
glm::vec3 expandedCorner = _corner - glm::vec3(expansion, expansion, expansion);
glm::vec3 expandedSize = glm::vec3(_scale, _scale, _scale) + glm::vec3(expansion, expansion, expansion) * 2.0f;
glm::vec3 direction = end - start;
float axisDistance;
return (findIntersection(start.x, direction.x, expandedCorner.x, expandedSize.x, axisDistance) &&
axisDistance >= 0.0f && axisDistance <= 1.0f &&
isWithin(start.y + axisDistance*direction.y, expandedCorner.y, expandedSize.y) &&
isWithin(start.z + axisDistance*direction.z, expandedCorner.z, expandedSize.z)) ||
(findIntersection(start.y, direction.y, expandedCorner.y, expandedSize.y, axisDistance) &&
axisDistance >= 0.0f && axisDistance <= 1.0f &&
isWithin(start.x + axisDistance*direction.x, expandedCorner.x, expandedSize.x) &&
isWithin(start.z + axisDistance*direction.z, expandedCorner.z, expandedSize.z)) ||
(findIntersection(start.z, direction.z, expandedCorner.z, expandedSize.z, axisDistance) &&
axisDistance >= 0.0f && axisDistance <= 1.0f &&
isWithin(start.y + axisDistance*direction.y, expandedCorner.y, expandedSize.y) &&
isWithin(start.x + axisDistance*direction.x, expandedCorner.x, expandedSize.x));
}
bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const {
// handle the trivial case where the box contains the origin
if (contains(origin)) {
distance = 0;
return true;
}
// check each axis
float axisDistance;
if ((findIntersection(origin.x, direction.x, _corner.x, _scale, axisDistance) && axisDistance >= 0 &&
isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) &&
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) {
distance = axisDistance;
face = direction.x > 0 ? MIN_X_FACE : MAX_X_FACE;
return true;
}
if ((findIntersection(origin.y, direction.y, _corner.y, _scale, axisDistance) && axisDistance >= 0 &&
isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale) &&
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) {
distance = axisDistance;
face = direction.y > 0 ? MIN_Y_FACE : MAX_Y_FACE;
return true;
}
if ((findIntersection(origin.z, direction.z, _corner.z, _scale, axisDistance) && axisDistance >= 0 &&
isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) &&
isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) {
distance = axisDistance;
face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE;
return true;
}
return false;
}
bool AACube::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const {
glm::vec4 center4 = glm::vec4(center, 1.0f);
float minPenetrationLength = FLT_MAX;
for (int i = 0; i < FACE_COUNT; i++) {
glm::vec4 facePlane = getPlane((BoxFace)i);
glm::vec3 vector = getClosestPointOnFace(center, (BoxFace)i) - center;
if (glm::dot(center4, getPlane((BoxFace)i)) >= 0.0f) {
// outside this face, so use vector to closest point to determine penetration
return ::findSpherePenetration(vector, glm::vec3(-facePlane), radius, penetration);
}
float vectorLength = glm::length(vector);
if (vectorLength < minPenetrationLength) {
// remember the smallest penetration vector; if we're inside all faces, we'll use that
penetration = (vectorLength < EPSILON) ? glm::vec3(-facePlane) * radius :
vector * ((vectorLength + radius) / -vectorLength);
minPenetrationLength = vectorLength;
}
}
return true;
}
bool AACube::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const {
glm::vec4 start4 = glm::vec4(start, 1.0f);
glm::vec4 end4 = glm::vec4(end, 1.0f);
glm::vec4 startToEnd = glm::vec4(end - start, 0.0f);
float minPenetrationLength = FLT_MAX;
for (int i = 0; i < FACE_COUNT; i++) {
// find the vector from the segment to the closest point on the face (starting from deeper end)
glm::vec4 facePlane = getPlane((BoxFace)i);
glm::vec3 closest = (glm::dot(start4, facePlane) <= glm::dot(end4, facePlane)) ?
getClosestPointOnFace(start4, startToEnd, (BoxFace)i) : getClosestPointOnFace(end4, -startToEnd, (BoxFace)i);
glm::vec3 vector = -computeVectorFromPointToSegment(closest, start, end);
if (glm::dot(vector, glm::vec3(facePlane)) < 0.0f) {
// outside this face, so use vector to closest point to determine penetration
return ::findSpherePenetration(vector, glm::vec3(-facePlane), radius, penetration);
}
float vectorLength = glm::length(vector);
if (vectorLength < minPenetrationLength) {
// remember the smallest penetration vector; if we're inside all faces, we'll use that
penetration = (vectorLength < EPSILON) ? glm::vec3(-facePlane) * radius :
vector * ((vectorLength + radius) / -vectorLength);
minPenetrationLength = vectorLength;
}
}
return true;
}
glm::vec3 AACube::getClosestPointOnFace(const glm::vec3& point, BoxFace face) const {
switch (face) {
case MIN_X_FACE:
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
glm::vec3(_corner.x, _corner.y + _scale, _corner.z + _scale));
case MAX_X_FACE:
return glm::clamp(point, glm::vec3(_corner.x + _scale, _corner.y, _corner.z),
glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale));
case MIN_Y_FACE:
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
glm::vec3(_corner.x + _scale, _corner.y, _corner.z + _scale));
case MAX_Y_FACE:
return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _scale, _corner.z),
glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale));
case MIN_Z_FACE:
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z));
default: //quiet windows warnings
case MAX_Z_FACE:
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _scale),
glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale));
}
}
glm::vec3 AACube::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const {
// check against the four planes that border the face
BoxFace oppositeFace = getOppositeFace(face);
bool anyOutside = false;
for (int i = 0; i < FACE_COUNT; i++) {
if (i == face || i == oppositeFace) {
continue;
}
glm::vec4 iPlane = getPlane((BoxFace)i);
float originDistance = glm::dot(origin, iPlane);
if (originDistance < 0.0f) {
continue; // inside the border
}
anyOutside = true;
float divisor = glm::dot(direction, iPlane);
if (fabs(divisor) < EPSILON) {
continue; // segment is parallel to plane
}
// find intersection and see if it lies within face bounds
float directionalDistance = -originDistance / divisor;
glm::vec4 intersection = origin + direction * directionalDistance;
BoxFace iOppositeFace = getOppositeFace((BoxFace)i);
for (int j = 0; j < FACE_COUNT; j++) {
if (j == face || j == oppositeFace || j == i || j == iOppositeFace) {
continue;
}
if (glm::dot(intersection, getPlane((BoxFace)j)) > 0.0f) {
goto outerContinue; // intersection is out of bounds
}
}
return getClosestPointOnFace(glm::vec3(intersection), face);
outerContinue: ;
}
// if we were outside any of the sides, we must check against the diagonals
if (anyOutside) {
int faceAxis = face / 2;
int secondAxis = (faceAxis + 1) % 3;
int thirdAxis = (faceAxis + 2) % 3;
glm::vec4 secondAxisMinPlane = getPlane((BoxFace)(secondAxis * 2));
glm::vec4 secondAxisMaxPlane = getPlane((BoxFace)(secondAxis * 2 + 1));
glm::vec4 thirdAxisMaxPlane = getPlane((BoxFace)(thirdAxis * 2 + 1));
glm::vec4 offset = glm::vec4(0.0f, 0.0f, 0.0f,
glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), glm::vec3(_scale, _scale, _scale)) * 0.5f);
glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset,
secondAxisMaxPlane + thirdAxisMaxPlane + offset };
float minDistance = FLT_MAX;
for (size_t i = 0; i < sizeof(diagonals) / sizeof(diagonals[0]); i++) {
float divisor = glm::dot(direction, diagonals[i]);
if (fabs(divisor) < EPSILON) {
continue; // segment is parallel to diagonal plane
}
minDistance = glm::min(-glm::dot(origin, diagonals[i]) / divisor, minDistance);
}
if (minDistance != FLT_MAX) {
return getClosestPointOnFace(glm::vec3(origin + direction * minDistance), face);
}
}
// last resort or all inside: clamp origin to face
return getClosestPointOnFace(glm::vec3(origin), face);
}
glm::vec4 AACube::getPlane(BoxFace face) const {
switch (face) {
case MIN_X_FACE: return glm::vec4(-1.0f, 0.0f, 0.0f, _corner.x);
case MAX_X_FACE: return glm::vec4(1.0f, 0.0f, 0.0f, -_corner.x - _scale);
case MIN_Y_FACE: return glm::vec4(0.0f, -1.0f, 0.0f, _corner.y);
case MAX_Y_FACE: return glm::vec4(0.0f, 1.0f, 0.0f, -_corner.y - _scale);
case MIN_Z_FACE: return glm::vec4(0.0f, 0.0f, -1.0f, _corner.z);
default: //quiet windows warnings
case MAX_Z_FACE: return glm::vec4(0.0f, 0.0f, 1.0f, -_corner.z - _scale);
}
}
BoxFace AACube::getOppositeFace(BoxFace face) {
switch (face) {
case MIN_X_FACE: return MAX_X_FACE;
case MAX_X_FACE: return MIN_X_FACE;
case MIN_Y_FACE: return MAX_Y_FACE;
case MAX_Y_FACE: return MIN_Y_FACE;
case MIN_Z_FACE: return MAX_Z_FACE;
default: //quiet windows warnings
case MAX_Z_FACE: return MIN_Z_FACE;
}
}

View file

@ -0,0 +1,64 @@
//
// AACube.h
// libraries/octree/src
//
// Created by Brad Hefta-Gaub on 04/11/13.
// Copyright 2013 High Fidelity, Inc.
//
// Originally from lighthouse3d. Modified to utilize glm::vec3 and clean up to our coding standards
// Simple axis aligned box class.
//
// 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_AACube_h
#define hifi_AACube_h
#include <glm/glm.hpp>
#include "BoxBase.h"
class AABox;
class AACube {
public:
AACube(const glm::vec3& corner, float size);
AACube();
~AACube() {};
void setBox(const glm::vec3& corner, float scale);
glm::vec3 getVertexP(const glm::vec3& normal) const;
glm::vec3 getVertexN(const glm::vec3& normal) const;
void scale(float scale);
const glm::vec3& getCorner() const { return _corner; }
float getScale() const { return _scale; }
glm::vec3 getDimensions() const { return glm::vec3(_scale,_scale,_scale); }
glm::vec3 calcCenter() const;
glm::vec3 calcTopFarLeft() const;
glm::vec3 getVertex(BoxVertex vertex) const;
bool contains(const glm::vec3& point) const;
bool contains(const AACube& otherCube) const;
bool touches(const AACube& otherCube) const;
bool contains(const AABox& otherBox) const;
bool touches(const AABox& otherBox) const;
bool expandedContains(const glm::vec3& point, float expansion) const;
bool expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const;
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const;
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const;
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const;
private:
glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const;
glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const;
glm::vec4 getPlane(BoxFace face) const;
static BoxFace getOppositeFace(BoxFace face);
glm::vec3 _corner;
float _scale;
};
#endif // hifi_AACube_h

View file

@ -0,0 +1,43 @@
//
// BoxBase.h
// libraries/octree/src
//
// Created by Brad Hefta-Gaub on 04/11/13.
// Copyright 2013 High Fidelity, Inc.
//
// Originally from lighthouse3d. Modified to utilize glm::vec3 and clean up to our coding standards
// Simple axis aligned box class.
//
// 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_BoxBase_h
#define hifi_BoxBase_h
#include <glm/glm.hpp>
enum BoxFace {
MIN_X_FACE,
MAX_X_FACE,
MIN_Y_FACE,
MAX_Y_FACE,
MIN_Z_FACE,
MAX_Z_FACE,
UNKNOWN_FACE
};
enum BoxVertex {
BOTTOM_LEFT_NEAR = 0,
BOTTOM_RIGHT_NEAR = 1,
TOP_RIGHT_NEAR = 2,
TOP_LEFT_NEAR = 3,
BOTTOM_LEFT_FAR = 4,
BOTTOM_RIGHT_FAR = 5,
TOP_RIGHT_FAR = 6,
TOP_LEFT_FAR = 7
};
const int FACE_COUNT = 6;
#endif // hifi_BoxBase_h

View file

@ -583,7 +583,7 @@ OctreeElement* Octree::getOrCreateChildElementAt(float x, float y, float z, floa
return getRoot()->getOrCreateChildElementAt(x, y, z, s);
}
OctreeElement* Octree::getOrCreateChildElementContaining(const AABox& box) {
OctreeElement* Octree::getOrCreateChildElementContaining(const AACube& box) {
return getRoot()->getOrCreateChildElementContaining(box);
}
@ -596,34 +596,26 @@ public:
OctreeElement*& element;
float& distance;
BoxFace& face;
void** intersectedObject;
bool found;
};
bool findRayIntersectionOp(OctreeElement* element, void* extraData) {
RayArgs* args = static_cast<RayArgs*>(extraData);
AABox box = element->getAABox();
float distance;
BoxFace face;
if (!box.findRayIntersection(args->origin, args->direction, distance, face)) {
return false;
}
if (!element->isLeaf()) {
return true; // recurse on children
}
distance *= TREE_SCALE;
if (element->hasContent() && (!args->found || distance < args->distance)) {
args->element = element;
args->distance = distance;
args->face = face;
bool keepSearching = true;
if (element->findRayIntersection(args->origin, args->direction, keepSearching,
args->element, args->distance, args->face, args->intersectedObject)) {
args->found = true;
}
return false;
return keepSearching;
}
bool Octree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
OctreeElement*& element, float& distance, BoxFace& face,
OctreeElement*& element, float& distance, BoxFace& face, void** intersectedObject,
Octree::lockType lockType, bool* accurateResult) {
RayArgs args = { origin / (float)(TREE_SCALE), direction, element, distance, face, false};
RayArgs args = { origin / (float)(TREE_SCALE), direction, element, distance, face, intersectedObject, false};
distance = FLT_MAX;
bool gotLock = false;
if (lockType == Octree::Lock) {
@ -664,7 +656,7 @@ bool findSpherePenetrationOp(OctreeElement* element, void* extraData) {
SphereArgs* args = static_cast<SphereArgs*>(extraData);
// coarse check against bounds
const AABox& box = element->getAABox();
const AACube& box = element->getAACube();
if (!box.expandedContains(args->center, args->radius)) {
return false;
}
@ -743,7 +735,7 @@ bool findCapsulePenetrationOp(OctreeElement* element, void* extraData) {
CapsuleArgs* args = static_cast<CapsuleArgs*>(extraData);
// coarse check against bounds
const AABox& box = element->getAABox();
const AACube& box = element->getAACube();
if (!box.expandedIntersectsSegment(args->start, args->end, args->radius)) {
return false;
}
@ -764,7 +756,7 @@ bool findShapeCollisionsOp(OctreeElement* element, void* extraData) {
ShapeArgs* args = static_cast<ShapeArgs*>(extraData);
// coarse check against bounds
AABox cube = element->getAABox();
AACube cube = element->getAACube();
cube.scale(TREE_SCALE);
if (!cube.expandedContains(args->shape->getPosition(), args->shape->getBoundingRadius())) {
return false;
@ -858,7 +850,7 @@ public:
// Find the smallest colored voxel enclosing a point (if there is one)
bool getElementEnclosingOperation(OctreeElement* element, void* extraData) {
GetElementEnclosingArgs* args = static_cast<GetElementEnclosingArgs*>(extraData);
AABox elementBox = element->getAABox();
AACube elementBox = element->getAACube();
if (elementBox.contains(args->point)) {
if (element->hasContent() && element->isLeaf()) {
// we've reached a solid leaf containing the point, return the element.
@ -1117,7 +1109,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
// If the user also asked for occlusion culling, check if this element is occluded, but only if it's not a leaf.
// leaf occlusion is handled down below when we check child nodes
if (params.wantOcclusionCulling && !element->isLeaf()) {
AABox voxelBox = element->getAABox();
AACube voxelBox = element->getAACube();
voxelBox.scale(TREE_SCALE);
OctreeProjectedPolygon* voxelPolygon = new OctreeProjectedPolygon(params.viewFrustum->getProjectedPolygon(voxelBox));
@ -1250,7 +1242,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElement* element,
if (params.wantOcclusionCulling && childElement->isLeaf()) {
// Don't check occlusion here, just add them to our distance ordered array...
AABox voxelBox = childElement->getAABox();
AACube voxelBox = childElement->getAACube();
voxelBox.scale(TREE_SCALE);
OctreeProjectedPolygon* voxelPolygon = new OctreeProjectedPolygon(
params.viewFrustum->getProjectedPolygon(voxelBox));

View file

@ -236,7 +236,7 @@ public:
OctreeElement* getOctreeEnclosingElementAt(float x, float y, float z, float s) const;
OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s);
OctreeElement* getOrCreateChildElementContaining(const AABox& box);
OctreeElement* getOrCreateChildElementContaining(const AACube& box);
void recurseTreeWithOperation(RecurseOctreeOperation operation, void* extraData = NULL);
void recurseTreeWithPostOperation(RecurseOctreeOperation operation, void* extraData = NULL);
@ -268,6 +268,7 @@ public:
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
OctreeElement*& node, float& distance, BoxFace& face,
void** intersectedObject = NULL,
Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL);
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject = NULL,

View file

@ -19,7 +19,7 @@
#include <PerfStat.h>
#include <assert.h>
#include "AABox.h"
#include "AACube.h"
#include "OctalCode.h"
#include "OctreeConstants.h"
#include "OctreeElement.h"
@ -93,7 +93,7 @@ void OctreeElement::init(unsigned char * octalCode) {
_isDirty = true;
_shouldRender = false;
_sourceUUIDKey = 0;
calculateAABox();
calculateAACube();
markWithChangedTime();
}
@ -190,15 +190,15 @@ void OctreeElement::setShouldRender(bool shouldRender) {
}
}
void OctreeElement::calculateAABox() {
void OctreeElement::calculateAACube() {
glm::vec3 corner;
// copy corner into box
// copy corner into cube
copyFirstVertexForCode(getOctalCode(),(float*)&corner);
// this tells you the "size" of the voxel
float voxelScale = 1 / powf(2, numberOfThreeBitSectionsInCode(getOctalCode()));
_box.setBox(corner,voxelScale);
_cube.setBox(corner,voxelScale);
}
void OctreeElement::deleteChildAtIndex(int childIndex) {
@ -1178,7 +1178,7 @@ void OctreeElement::printDebugDetails(const char* label) const {
QString resultString;
resultString.sprintf("%s - Voxel at corner=(%f,%f,%f) size=%f\n isLeaf=%s isDirty=%s shouldRender=%s\n children=", label,
_box.getCorner().x, _box.getCorner().y, _box.getCorner().z, _box.getScale(),
_cube.getCorner().x, _cube.getCorner().y, _cube.getCorner().z, _cube.getScale(),
debug::valueOf(isLeaf()), debug::valueOf(isDirty()), debug::valueOf(getShouldRender()));
elementDebug << resultString;
@ -1192,9 +1192,9 @@ float OctreeElement::getEnclosingRadius() const {
}
ViewFrustum::location OctreeElement::inFrustum(const ViewFrustum& viewFrustum) const {
AABox box = _box; // use temporary box so we can scale it
box.scale(TREE_SCALE);
return viewFrustum.boxInFrustum(box);
AACube cube = _cube; // use temporary cube so we can scale it
cube.scale(TREE_SCALE);
return viewFrustum.cubeInFrustum(cube);
}
// There are two types of nodes for which we want to "render"
@ -1228,27 +1228,27 @@ bool OctreeElement::calculateShouldRender(const ViewFrustum* viewFrustum, float
// does as much math as possible in voxel scale and then scales up to TREE_SCALE at end
float OctreeElement::furthestDistanceToCamera(const ViewFrustum& viewFrustum) const {
glm::vec3 furthestPoint;
viewFrustum.getFurthestPointFromCameraVoxelScale(getAABox(), furthestPoint);
viewFrustum.getFurthestPointFromCameraVoxelScale(getAACube(), furthestPoint);
glm::vec3 temp = viewFrustum.getPositionVoxelScale() - furthestPoint;
float distanceToFurthestPoint = sqrtf(glm::dot(temp, temp));
return distanceToFurthestPoint * (float)TREE_SCALE;
}
float OctreeElement::distanceToCamera(const ViewFrustum& viewFrustum) const {
glm::vec3 center = _box.calcCenter() * (float)TREE_SCALE;
glm::vec3 center = _cube.calcCenter() * (float)TREE_SCALE;
glm::vec3 temp = viewFrustum.getPosition() - center;
float distanceToVoxelCenter = sqrtf(glm::dot(temp, temp));
return distanceToVoxelCenter;
}
float OctreeElement::distanceSquareToPoint(const glm::vec3& point) const {
glm::vec3 temp = point - _box.calcCenter();
glm::vec3 temp = point - _cube.calcCenter();
float distanceSquare = glm::dot(temp, temp);
return distanceSquare;
}
float OctreeElement::distanceToPoint(const glm::vec3& point) const {
glm::vec3 temp = point - _box.calcCenter();
glm::vec3 temp = point - _cube.calcCenter();
float distance = sqrtf(glm::dot(temp, temp));
return distance;
}
@ -1302,9 +1302,58 @@ void OctreeElement::notifyUpdateHooks() {
}
}
bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
void** intersectedObject) {
keepSearching = true; // assume that we will continue searching after this.
// by default, we only allow intersections with leaves with content
if (!canRayIntersect()) {
return false; // we don't intersect with non-leaves, and we keep searching
}
AACube cube = getAACube();
float localDistance;
BoxFace localFace;
// if the ray doesn't intersect with our cube, we can stop searching!
if (!cube.findRayIntersection(origin, direction, localDistance, localFace)) {
keepSearching = false; // no point in continuing to search
return false; // we did not intersect
}
// we did hit this element, so calculate appropriate distances
localDistance *= TREE_SCALE;
if (localDistance < distance) {
if (findDetailedRayIntersection(origin, direction, keepSearching,
element, distance, face, intersectedObject)) {
distance = localDistance;
face = localFace;
return true;
}
}
return false;
}
bool OctreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
void** intersectedObject) {
// we did hit this element, so calculate appropriate distances
if (hasContent()) {
element = this;
if (intersectedObject) {
*intersectedObject = this;
}
return true; // we did intersect
}
return false; // we did not intersect
}
bool OctreeElement::findSpherePenetration(const glm::vec3& center, float radius,
glm::vec3& penetration, void** penetratedObject) const {
return _box.findSpherePenetration(center, radius, penetration);
return _cube.findSpherePenetration(center, radius, penetration);
}
@ -1323,7 +1372,7 @@ OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float
return this;
}
// otherwise, we need to find which of our children we should recurse
glm::vec3 ourCenter = _box.calcCenter();
glm::vec3 ourCenter = _cube.calcCenter();
int childIndex = CHILD_UNKNOWN;
// left half
@ -1381,31 +1430,31 @@ OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float
}
OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AABox& box) {
OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AACube& cube) {
OctreeElement* child = NULL;
float ourScale = getScale();
float boxScale = box.getScale();
float cubeScale = cube.getScale();
if(boxScale > ourScale) {
if(cubeScale > ourScale) {
qDebug("UNEXPECTED -- OctreeElement::getOrCreateChildElementContaining() "
"boxScale=[%f] > ourScale=[%f] ", boxScale, ourScale);
"cubeScale=[%f] > ourScale=[%f] ", cubeScale, ourScale);
}
// Determine which of our children the minimum and maximum corners of the box live in...
glm::vec3 boxCornerMinimum = box.getCorner();
glm::vec3 boxCornerMaximum = box.calcTopFarLeft();
// Determine which of our children the minimum and maximum corners of the cube live in...
glm::vec3 cubeCornerMinimum = cube.getCorner();
glm::vec3 cubeCornerMaximum = cube.calcTopFarLeft();
int childIndexBoxMinimum = getMyChildContainingPoint(boxCornerMinimum);
int childIndexBoxMaximum = getMyChildContainingPoint(boxCornerMaximum);
int childIndexCubeMinimum = getMyChildContainingPoint(cubeCornerMinimum);
int childIndexCubeMaximum = getMyChildContainingPoint(cubeCornerMaximum);
// If the minimum and maximum corners of the box are in two different children's boxes, then we are the containing element
if (childIndexBoxMinimum != childIndexBoxMaximum) {
// If the minimum and maximum corners of the cube are in two different children's cubes, then we are the containing element
if (childIndexCubeMinimum != childIndexCubeMaximum) {
return this;
}
// otherwise, they are the same and that child should be considered as the correct element
int childIndex = childIndexBoxMinimum; // both the same...
int childIndex = childIndexCubeMinimum; // both the same...
// Now, check if we have a child at that location
child = getChildAtIndex(childIndex);
@ -1419,11 +1468,11 @@ OctreeElement* OctreeElement::getOrCreateChildElementContaining(const AABox& box
}
// Now that we have the child to recurse down, let it answer the original question...
return child->getOrCreateChildElementContaining(box);
return child->getOrCreateChildElementContaining(cube);
}
int OctreeElement::getMyChildContainingPoint(const glm::vec3& point) const {
glm::vec3 ourCenter = _box.calcCenter();
glm::vec3 ourCenter = _cube.calcCenter();
int childIndex = CHILD_UNKNOWN;
// left half
if (point.x > ourCenter.x) {

View file

@ -20,7 +20,7 @@
#include <SharedUtil.h>
#include "AABox.h"
#include "AACube.h"
#include "ViewFrustum.h"
#include "OctreeConstants.h"
@ -102,6 +102,14 @@ public:
virtual bool deleteApproved() const { return true; }
virtual bool canRayIntersect() const { return isLeaf(); }
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
bool& keepSearching, OctreeElement*& node, float& distance, BoxFace& face,
void** intersectedObject = NULL);
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
void** intersectedObject);
virtual bool findSpherePenetration(const glm::vec3& center, float radius,
glm::vec3& penetration, void** penetratedObject) const;
@ -116,9 +124,9 @@ public:
bool safeDeepDeleteChildAtIndex(int childIndex, int recursionCount = 0);
const AABox& getAABox() const { return _box; }
const glm::vec3& getCorner() const { return _box.getCorner(); }
float getScale() const { return _box.getScale(); }
const AACube& getAACube() const { return _cube; }
const glm::vec3& getCorner() const { return _cube.getCorner(); }
float getScale() const { return _cube.getScale(); }
int getLevel() const { return numberOfThreeBitSectionsInCode(getOctalCode()) + 1; }
float getEnclosingRadius() const;
@ -223,7 +231,7 @@ public:
OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s);
OctreeElement* getOrCreateChildElementContaining(const AABox& box);
OctreeElement* getOrCreateChildElementContaining(const AACube& box);
int getMyChildContainingPoint(const glm::vec3& point) const;
protected:
@ -240,11 +248,11 @@ protected:
void encodeThreeOffsets(int64_t offsetOne, int64_t offsetTwo, int64_t offsetThree);
void checkStoreFourChildren(OctreeElement* childOne, OctreeElement* childTwo, OctreeElement* childThree, OctreeElement* childFour);
#endif
void calculateAABox();
void calculateAACube();
void notifyDeleteHooks();
void notifyUpdateHooks();
AABox _box; /// Client and server, axis aligned box for bounds of this voxel, 48 bytes
AACube _cube; /// Client and server, axis aligned box for bounds of this voxel, 48 bytes
/// Client and server, buffer containing the octal code or a pointer to octal code for this node, 8 bytes
union octalCode_t {

View file

@ -95,10 +95,10 @@ void OctreeHeadlessViewer::queryOctree() {
if (rootCode) {
VoxelPositionSize rootDetails;
voxelDetailsForCode(rootCode, rootDetails);
AABox serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
serverBounds.scale(TREE_SCALE);
ViewFrustum::location serverFrustumLocation = _viewFrustum.boxInFrustum(serverBounds);
ViewFrustum::location serverFrustumLocation = _viewFrustum.cubeInFrustum(serverBounds);
if (serverFrustumLocation != ViewFrustum::OUTSIDE) {
inViewServers++;
@ -161,10 +161,10 @@ void OctreeHeadlessViewer::queryOctree() {
if (rootCode) {
VoxelPositionSize rootDetails;
voxelDetailsForCode(rootCode, rootDetails);
AABox serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
serverBounds.scale(TREE_SCALE);
ViewFrustum::location serverFrustumLocation = _viewFrustum.boxInFrustum(serverBounds);
ViewFrustum::location serverFrustumLocation = _viewFrustum.cubeInFrustum(serverBounds);
if (serverFrustumLocation != ViewFrustum::OUTSIDE) {
inView = true;
} else {

View file

@ -141,7 +141,7 @@ void ViewFrustum::calculate() {
// Set up our keyhole bounding box...
glm::vec3 corner = _position - _keyholeRadius;
_keyholeBoundingBox = AABox(corner,(_keyholeRadius * 2.0f));
_keyholeBoundingCube = AACube(corner,(_keyholeRadius * 2.0f));
}
void ViewFrustum::calculateOrthographic() {
@ -184,7 +184,7 @@ void ViewFrustum::calculateOrthographic() {
// Set up our keyhole bounding box...
glm::vec3 corner = _position - _keyholeRadius;
_keyholeBoundingBox = AABox(corner, (_keyholeRadius * 2.0f));
_keyholeBoundingCube = AACube(corner, (_keyholeRadius * 2.0f));
}
//enum { TOP_PLANE = 0, BOTTOM_PLANE, LEFT_PLANE, RIGHT_PLANE, NEAR_PLANE, FAR_PLANE };
@ -231,6 +231,44 @@ ViewFrustum::location ViewFrustum::sphereInKeyhole(const glm::vec3& center, floa
}
// A box is inside a sphere if all of its corners are inside the sphere
// A box intersects a sphere if any of its edges (as rays) interesect the sphere
// A box is outside a sphere if none of its edges (as rays) interesect the sphere
ViewFrustum::location ViewFrustum::cubeInKeyhole(const AACube& cube) const {
// First check to see if the cube is in the bounding cube for the sphere, if it's not, then we can short circuit
// this and not check with sphere penetration which is more expensive
if (!_keyholeBoundingCube.contains(cube)) {
return OUTSIDE;
}
glm::vec3 penetration;
bool intersects = cube.findSpherePenetration(_position, _keyholeRadius, penetration);
ViewFrustum::location result = OUTSIDE;
// if the cube intersects the sphere, then it may also be inside... calculate further
if (intersects) {
result = INTERSECT;
// test all the corners, if they are all inside the sphere, the entire cube is in the sphere
bool allPointsInside = true; // assume the best
for (int v = BOTTOM_LEFT_NEAR; v < TOP_LEFT_FAR; v++) {
glm::vec3 vertex = cube.getVertex((BoxVertex)v);
if (!pointInKeyhole(vertex)) {
allPointsInside = false;
break;
}
}
if (allPointsInside) {
result = INSIDE;
}
}
return result;
}
// A box is inside a sphere if all of its corners are inside the sphere
// A box intersects a sphere if any of its edges (as rays) interesect the sphere
// A box is outside a sphere if none of its edges (as rays) interesect the sphere
@ -238,7 +276,7 @@ ViewFrustum::location ViewFrustum::boxInKeyhole(const AABox& box) const {
// First check to see if the box is in the bounding box for the sphere, if it's not, then we can short circuit
// this and not check with sphere penetration which is more expensive
if (!_keyholeBoundingBox.contains(box)) {
if (!_keyholeBoundingCube.contains(box)) {
return OUTSIDE;
}
@ -319,14 +357,14 @@ ViewFrustum::location ViewFrustum::sphereInFrustum(const glm::vec3& center, floa
}
ViewFrustum::location ViewFrustum::boxInFrustum(const AABox& box) const {
ViewFrustum::location ViewFrustum::cubeInFrustum(const AACube& cube) const {
ViewFrustum::location regularResult = INSIDE;
ViewFrustum::location keyholeResult = OUTSIDE;
// If we have a keyholeRadius, check that first, since it's cheaper
if (_keyholeRadius >= 0.0f) {
keyholeResult = boxInKeyhole(box);
keyholeResult = cubeInKeyhole(cube);
}
if (keyholeResult == INSIDE) {
return keyholeResult;
@ -338,10 +376,10 @@ ViewFrustum::location ViewFrustum::boxInFrustum(const AABox& box) const {
// also be able to test against the cone to the bounding sphere of the box.
for(int i=0; i < 6; i++) {
const glm::vec3& normal = _planes[i].getNormal();
const glm::vec3& boxVertexP = box.getVertexP(normal);
const glm::vec3& boxVertexP = cube.getVertexP(normal);
float planeToBoxVertexPDistance = _planes[i].distance(boxVertexP);
const glm::vec3& boxVertexN = box.getVertexN(normal);
const glm::vec3& boxVertexN = cube.getVertexN(normal);
float planeToBoxVertexNDistance = _planes[i].distance(boxVertexN);
if (planeToBoxVertexPDistance < 0) {
@ -610,7 +648,7 @@ glm::vec2 ViewFrustum::projectPoint(glm::vec3 point, bool& pointInView) const {
const int MAX_POSSIBLE_COMBINATIONS = 43;
const int hullVertexLookup[MAX_POSSIBLE_COMBINATIONS][MAX_PROJECTED_POLYGON_VERTEX_COUNT+1] = {
// Number of vertices in shadow polygon for the visible faces, then a list of the index of each vertice from the AABox
// Number of vertices in shadow polygon for the visible faces, then a list of the index of each vertice from the AACube
//0
{0}, // inside
@ -682,7 +720,7 @@ const int hullVertexLookup[MAX_POSSIBLE_COMBINATIONS][MAX_PROJECTED_POLYGON_VERT
{6, TOP_RIGHT_NEAR, TOP_RIGHT_FAR, BOTTOM_RIGHT_FAR, BOTTOM_LEFT_FAR, BOTTOM_LEFT_NEAR, TOP_LEFT_NEAR}, // back, top, left
};
OctreeProjectedPolygon ViewFrustum::getProjectedPolygon(const AABox& box) const {
OctreeProjectedPolygon ViewFrustum::getProjectedPolygon(const AACube& box) const {
const glm::vec3& bottomNearRight = box.getCorner();
glm::vec3 topFarLeft = box.calcTopFarLeft();
@ -749,7 +787,7 @@ OctreeProjectedPolygon ViewFrustum::getProjectedPolygon(const AABox& box) const
// Similar strategy to getProjectedPolygon() we use the knowledge of camera position relative to the
// axis-aligned voxels to determine which of the voxels vertices must be the furthest. No need for
// squares and square-roots. Just compares.
void ViewFrustum::getFurthestPointFromCamera(const AABox& box, glm::vec3& furthestPoint) const {
void ViewFrustum::getFurthestPointFromCamera(const AACube& box, glm::vec3& furthestPoint) const {
const glm::vec3& bottomNearRight = box.getCorner();
float scale = box.getScale();
float halfScale = scale * 0.5f;
@ -776,7 +814,7 @@ void ViewFrustum::getFurthestPointFromCamera(const AABox& box, glm::vec3& furthe
}
}
void ViewFrustum::getFurthestPointFromCameraVoxelScale(const AABox& box, glm::vec3& furthestPoint) const {
void ViewFrustum::getFurthestPointFromCameraVoxelScale(const AACube& box, glm::vec3& furthestPoint) const {
const glm::vec3& bottomNearRight = box.getCorner();
float scale = box.getScale();
float halfScale = scale * 0.5f;

View file

@ -18,6 +18,7 @@
#include <glm/gtc/quaternion.hpp>
#include "AABox.h"
#include "AACube.h"
#include "Plane.h"
#include "OctreeConstants.h"
#include "OctreeProjectedPolygon.h"
@ -94,6 +95,7 @@ public:
ViewFrustum::location pointInFrustum(const glm::vec3& point) const;
ViewFrustum::location sphereInFrustum(const glm::vec3& center, float radius) const;
ViewFrustum::location cubeInFrustum(const AACube& cube) const;
ViewFrustum::location boxInFrustum(const AABox& box) const;
// some frustum comparisons
@ -111,29 +113,30 @@ public:
void printDebugDetails() const;
glm::vec2 projectPoint(glm::vec3 point, bool& pointInView) const;
OctreeProjectedPolygon getProjectedPolygon(const AABox& box) const;
void getFurthestPointFromCamera(const AABox& box, glm::vec3& furthestPoint) const;
OctreeProjectedPolygon getProjectedPolygon(const AACube& box) const;
void getFurthestPointFromCamera(const AACube& box, glm::vec3& furthestPoint) const;
// assumes box is in voxel scale, not TREE_SCALE, will scale view frustum's position accordingly
void getFurthestPointFromCameraVoxelScale(const AABox& box, glm::vec3& furthestPoint) const;
void getFurthestPointFromCameraVoxelScale(const AACube& box, glm::vec3& furthestPoint) const;
private:
// Used for keyhole calculations
ViewFrustum::location pointInKeyhole(const glm::vec3& point) const;
ViewFrustum::location sphereInKeyhole(const glm::vec3& center, float radius) const;
ViewFrustum::location cubeInKeyhole(const AACube& cube) const;
ViewFrustum::location boxInKeyhole(const AABox& box) const;
void calculateOrthographic();
// camera location/orientation attributes
glm::vec3 _position; // the position in TREE_SCALE
glm::vec3 _positionVoxelScale; // the position in voxel scale
glm::quat _orientation;
glm::vec3 _position; // the position in TREE_SCALE
glm::vec3 _positionVoxelScale; // the position in voxel scale
glm::quat _orientation;
// calculated for orientation
glm::vec3 _direction;
glm::vec3 _up;
glm::vec3 _right;
glm::vec3 _direction;
glm::vec3 _up;
glm::vec3 _right;
// Lens attributes
bool _orthographic;
@ -148,23 +151,23 @@ private:
glm::quat _eyeOffsetOrientation;
// keyhole attributes
float _keyholeRadius;
AABox _keyholeBoundingBox;
float _keyholeRadius;
AACube _keyholeBoundingCube;
// Calculated values
glm::vec3 _offsetPosition;
glm::vec3 _offsetDirection;
glm::vec3 _offsetUp;
glm::vec3 _offsetRight;
glm::vec3 _farTopLeft;
glm::vec3 _farTopRight;
glm::vec3 _farBottomLeft;
glm::vec3 _farBottomRight;
glm::vec3 _nearTopLeft;
glm::vec3 _nearTopRight;
glm::vec3 _nearBottomLeft;
glm::vec3 _nearBottomRight;
glm::vec3 _offsetPosition;
glm::vec3 _offsetDirection;
glm::vec3 _offsetUp;
glm::vec3 _offsetRight;
glm::vec3 _farTopLeft;
glm::vec3 _farTopRight;
glm::vec3 _farBottomLeft;
glm::vec3 _farBottomRight;
glm::vec3 _nearTopLeft;
glm::vec3 _nearTopRight;
glm::vec3 _nearBottomLeft;
glm::vec3 _nearBottomRight;
enum { TOP_PLANE = 0, BOTTOM_PLANE, LEFT_PLANE, RIGHT_PLANE, NEAR_PLANE, FAR_PLANE };
::Plane _planes[6]; // How will this be used?

View file

@ -237,7 +237,7 @@ bool ParticleTree::findNearPointOperation(OctreeElement* element, void* extraDat
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
glm::vec3 penetration;
bool sphereIntersection = particleTreeElement->getAABox().findSpherePenetration(args->position,
bool sphereIntersection = particleTreeElement->getAACube().findSpherePenetration(args->position,
args->targetRadius, penetration);
// If this particleTreeElement contains the point, then search it...
@ -287,7 +287,7 @@ public:
bool ParticleTree::findInSphereOperation(OctreeElement* element, void* extraData) {
FindAllNearPointArgs* args = static_cast<FindAllNearPointArgs*>(extraData);
glm::vec3 penetration;
bool sphereIntersection = element->getAABox().findSpherePenetration(args->position,
bool sphereIntersection = element->getAACube().findSpherePenetration(args->position,
args->targetRadius, penetration);
// If this element contains the point, then search it...
@ -310,31 +310,31 @@ void ParticleTree::findParticles(const glm::vec3& center, float radius, QVector<
foundParticles.swap(args.particles);
}
class FindParticlesInBoxArgs {
class FindParticlesInCubeArgs {
public:
FindParticlesInBoxArgs(const AABox& box)
: _box(box), _foundParticles() {
FindParticlesInCubeArgs(const AACube& cube)
: _cube(cube), _foundParticles() {
}
AABox _box;
AACube _cube;
QVector<Particle*> _foundParticles;
};
bool ParticleTree::findInBoxForUpdateOperation(OctreeElement* element, void* extraData) {
FindParticlesInBoxArgs* args = static_cast< FindParticlesInBoxArgs*>(extraData);
const AABox& elementBox = element->getAABox();
if (elementBox.touches(args->_box)) {
bool ParticleTree::findInCubeForUpdateOperation(OctreeElement* element, void* extraData) {
FindParticlesInCubeArgs* args = static_cast< FindParticlesInCubeArgs*>(extraData);
const AACube& elementBox = element->getAACube();
if (elementBox.touches(args->_cube)) {
ParticleTreeElement* particleTreeElement = static_cast<ParticleTreeElement*>(element);
particleTreeElement->getParticlesForUpdate(args->_box, args->_foundParticles);
particleTreeElement->getParticlesForUpdate(args->_cube, args->_foundParticles);
return true;
}
return false;
}
void ParticleTree::findParticlesForUpdate(const AABox& box, QVector<Particle*> foundParticles) {
FindParticlesInBoxArgs args(box);
void ParticleTree::findParticlesForUpdate(const AACube& cube, QVector<Particle*> foundParticles) {
FindParticlesInCubeArgs args(cube);
lockForRead();
recurseTreeWithOperation(findInBoxForUpdateOperation, &args);
recurseTreeWithOperation(findInCubeForUpdateOperation, &args);
unlock();
// swap the two lists of particle pointers instead of copy
foundParticles.swap(args._foundParticles);
@ -473,7 +473,7 @@ void ParticleTree::update() {
bool shouldDie = args._movingParticles[i].getShouldDie();
// if the particle is still inside our total bounds, then re-add it
AABox treeBounds = getRoot()->getAABox();
AACube treeBounds = getRoot()->getAACube();
if (!shouldDie && treeBounds.contains(args._movingParticles[i].getPosition())) {
storeParticle(args._movingParticles[i]);

View file

@ -60,7 +60,7 @@ public:
/// \param box the query box
/// \param foundParticles[out] vector of non-const Particle*
/// \remark Side effect: any initial contents in particles will be lost
void findParticlesForUpdate(const AABox& box, QVector<Particle*> foundParticles);
void findParticlesForUpdate(const AACube& box, QVector<Particle*> foundParticles);
void addNewlyCreatedHook(NewlyCreatedParticleHook* hook);
void removeNewlyCreatedHook(NewlyCreatedParticleHook* hook);
@ -84,7 +84,7 @@ private:
static bool findByIDOperation(OctreeElement* element, void* extraData);
static bool findAndDeleteOperation(OctreeElement* element, void* extraData);
static bool findAndUpdateParticleIDOperation(OctreeElement* element, void* extraData);
static bool findInBoxForUpdateOperation(OctreeElement* element, void* extraData);
static bool findInCubeForUpdateOperation(OctreeElement* element, void* extraData);
void notifyNewlyCreatedParticle(const Particle& newParticle, const SharedNodePointer& senderNode);

View file

@ -79,7 +79,7 @@ void ParticleTreeElement::update(ParticleTreeUpdateArgs& args) {
// If the particle wants to die, or if it's left our bounding box, then move it
// into the arguments moving particles. These will be added back or deleted completely
if (particle.getShouldDie() || !_box.contains(particle.getPosition())) {
if (particle.getShouldDie() || !_cube.contains(particle.getPosition())) {
args._movingParticles.push_back(particle);
// erase this particle
@ -245,18 +245,18 @@ void ParticleTreeElement::getParticles(const glm::vec3& searchPosition, float se
}
}
void ParticleTreeElement::getParticlesForUpdate(const AABox& box, QVector<Particle*>& foundParticles) {
void ParticleTreeElement::getParticlesForUpdate(const AACube& box, QVector<Particle*>& foundParticles) {
QList<Particle>::iterator particleItr = _particles->begin();
QList<Particle>::iterator particleEnd = _particles->end();
AABox particleBox;
AACube particleCube;
while(particleItr != particleEnd) {
Particle* particle = &(*particleItr);
float radius = particle->getRadius();
// NOTE: we actually do box-box collision queries here, which is sloppy but good enough for now
// TODO: decide whether to replace particleBox-box query with sphere-box (requires a square root
// but will be slightly more accurate).
particleBox.setBox(particle->getPosition() - glm::vec3(radius), 2.f * radius);
if (particleBox.touches(_box)) {
particleCube.setBox(particle->getPosition() - glm::vec3(radius), 2.f * radius);
if (particleCube.touches(_cube)) {
foundParticles.push_back(particle);
}
++particleItr;

View file

@ -114,7 +114,7 @@ public:
/// finds all particles that touch a box
/// \param box the query box
/// \param particles[out] vector of non-const Particle*
void getParticlesForUpdate(const AABox& box, QVector<Particle*>& foundParticles);
void getParticlesForUpdate(const AACube& box, QVector<Particle*>& foundParticles);
const Particle* getParticleWithID(uint32_t id) const;

View file

@ -130,7 +130,7 @@ RayToVoxelIntersectionResult LocalVoxels::findRayIntersectionWorker(const PickRa
RayToVoxelIntersectionResult result;
if (_tree) {
OctreeElement* element;
result.intersects = _tree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face,
result.intersects = _tree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face, NULL,
lockType, &result.accurate);
if (result.intersects) {
VoxelTreeElement* voxel = (VoxelTreeElement*)element;

View file

@ -224,6 +224,7 @@ void ScriptEngine::init() {
qScriptRegisterMetaType(&_engine, ModelItemPropertiesToScriptValue, ModelItemPropertiesFromScriptValue);
qScriptRegisterMetaType(&_engine, ModelItemIDtoScriptValue, ModelItemIDfromScriptValue);
qScriptRegisterMetaType(&_engine, RayToModelIntersectionResultToScriptValue, RayToModelIntersectionResultFromScriptValue);
qScriptRegisterSequenceMetaType<QVector<ModelItemID> >(&_engine);
qScriptRegisterSequenceMetaType<QVector<glm::vec2> >(&_engine);

View file

@ -14,7 +14,7 @@
#include <QtScript/QScriptEngine>
#include <AABox.h>
#include <AACube.h>
#include <SharedUtil.h>
#include "VoxelConstants.h"

View file

@ -224,15 +224,15 @@ bool VoxelTreeElement::collapseChildren() {
bool VoxelTreeElement::findSpherePenetration(const glm::vec3& center, float radius,
glm::vec3& penetration, void** penetratedObject) const {
if (_box.findSpherePenetration(center, radius, penetration)) {
if (_cube.findSpherePenetration(center, radius, penetration)) {
// if the caller wants details about the voxel, then return them here...
if (penetratedObject) {
VoxelDetail* voxelDetails = new VoxelDetail;
voxelDetails->x = _box.getCorner().x;
voxelDetails->y = _box.getCorner().y;
voxelDetails->z = _box.getCorner().z;
voxelDetails->s = _box.getScale();
voxelDetails->x = _cube.getCorner().x;
voxelDetails->y = _cube.getCorner().y;
voxelDetails->z = _cube.getCorner().z;
voxelDetails->s = _cube.getScale();
voxelDetails->red = getColor()[RED_INDEX];
voxelDetails->green = getColor()[GREEN_INDEX];
voxelDetails->blue = getColor()[BLUE_INDEX];

View file

@ -18,7 +18,7 @@
#include <QReadWriteLock>
#include <AABox.h>
#include <AACube.h>
#include <OctreeElement.h>
#include <SharedUtil.h>

View file

@ -135,7 +135,7 @@ RayToVoxelIntersectionResult VoxelsScriptingInterface::findRayIntersectionWorker
RayToVoxelIntersectionResult result;
if (_tree) {
OctreeElement* element;
result.intersects = _tree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face,
result.intersects = _tree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face, NULL,
lockType, &result.accurate);
if (result.intersects) {
VoxelTreeElement* voxel = (VoxelTreeElement*)element;