mirror of
https://github.com/overte-org/overte.git
synced 2025-04-15 11:29:00 +02:00
Merge pull request #2920 from ZappoMan/aacube
Add RayPick support for models
This commit is contained in:
commit
6bb933996f
37 changed files with 1157 additions and 276 deletions
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -150,6 +150,8 @@ public:
|
|||
QVector<glm::vec4> clusterWeights;
|
||||
|
||||
QVector<FBXCluster> clusters;
|
||||
|
||||
Extents meshExtents;
|
||||
|
||||
bool isEye;
|
||||
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
397
libraries/octree/src/AACube.cpp
Normal file
397
libraries/octree/src/AACube.cpp
Normal 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;
|
||||
}
|
||||
}
|
64
libraries/octree/src/AACube.h
Normal file
64
libraries/octree/src/AACube.h
Normal 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
|
43
libraries/octree/src/BoxBase.h
Normal file
43
libraries/octree/src/BoxBase.h
Normal 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
|
|
@ -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));
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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?
|
||||
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include <QtScript/QScriptEngine>
|
||||
|
||||
#include <AABox.h>
|
||||
#include <AACube.h>
|
||||
#include <SharedUtil.h>
|
||||
#include "VoxelConstants.h"
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#include <QReadWriteLock>
|
||||
|
||||
#include <AABox.h>
|
||||
#include <AACube.h>
|
||||
#include <OctreeElement.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue