mirror of
https://github.com/lubosz/overte.git
synced 2025-04-19 17:03:43 +02:00
first cut at octree storage of Triangle Set
This commit is contained in:
parent
a302c220f4
commit
a15c5999b5
6 changed files with 274 additions and 13 deletions
|
@ -336,7 +336,7 @@ public:
|
|||
|
||||
// Don't actually crash in debug builds, in case this apparent deadlock is simply from
|
||||
// the developer actively debugging code
|
||||
#ifdef NDEBUG
|
||||
#if 0 //def NDEBUG
|
||||
deadlockDetectionCrash();
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -376,7 +376,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
|
|||
glm::vec3 meshFrameOrigin = glm::vec3(worldToMeshMatrix * glm::vec4(origin, 1.0f));
|
||||
glm::vec3 meshFrameDirection = glm::vec3(worldToMeshMatrix * glm::vec4(direction, 0.0f));
|
||||
|
||||
for (const auto& triangleSet : _modelSpaceMeshTriangleSets) {
|
||||
for (auto& triangleSet : _modelSpaceMeshTriangleSets) {
|
||||
float triangleSetDistance = 0.0f;
|
||||
BoxFace triangleSetFace;
|
||||
glm::vec3 triangleSetNormal;
|
||||
|
@ -462,6 +462,8 @@ bool Model::convexHullContains(glm::vec3 point) {
|
|||
void Model::calculateTriangleSets() {
|
||||
PROFILE_RANGE(render, __FUNCTION__);
|
||||
|
||||
qDebug() << __FUNCTION__ << "url:" << _url;
|
||||
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
int numberOfMeshes = geometry.meshes.size();
|
||||
|
||||
|
|
|
@ -114,6 +114,10 @@ static bool isWithin(float value, float corner, float size) {
|
|||
return value >= corner && value <= corner + size;
|
||||
}
|
||||
|
||||
bool AABox::contains(const Triangle& triangle) const {
|
||||
return contains(triangle.v0) && contains(triangle.v1) && contains(triangle.v2);
|
||||
}
|
||||
|
||||
bool AABox::contains(const glm::vec3& point) const {
|
||||
return isWithin(point.x, _corner.x, _scale.x) &&
|
||||
isWithin(point.y, _corner.y, _scale.y) &&
|
||||
|
@ -622,3 +626,40 @@ void AABox::transform(const glm::mat4& matrix) {
|
|||
_corner = newCenter - newDir;
|
||||
_scale = newDir * 2.0f;
|
||||
}
|
||||
|
||||
AABox AABox::getOctreeChild(OctreeChild child) const {
|
||||
AABox result(*this); // self
|
||||
switch (child) {
|
||||
case topLeftNear:
|
||||
result._corner.y += _scale.y / 2.0f;
|
||||
break;
|
||||
case topLeftFar:
|
||||
result._corner.y += _scale.y / 2.0f;
|
||||
result._corner.z += _scale.z / 2.0f;
|
||||
break;
|
||||
case topRightNear:
|
||||
result._corner.y += _scale.y / 2.0f;
|
||||
result._corner.x += _scale.x / 2.0f;
|
||||
break;
|
||||
case topRightFar:
|
||||
result._corner.y += _scale.y / 2.0f;
|
||||
result._corner.x += _scale.x / 2.0f;
|
||||
result._corner.z += _scale.z / 2.0f;
|
||||
break;
|
||||
case bottomLeftNear:
|
||||
// _corner = same as parent
|
||||
break;
|
||||
case bottomLeftFar:
|
||||
result._corner.z += _scale.z / 2.0f;
|
||||
break;
|
||||
case bottomRightNear:
|
||||
result._corner.x += _scale.x / 2.0f;
|
||||
break;
|
||||
case bottomRightFar:
|
||||
result._corner.x += _scale.x / 2.0f;
|
||||
result._corner.z += _scale.z / 2.0f;
|
||||
break;
|
||||
}
|
||||
result._scale /= 2.0f; // everything is half the scale
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <QDebug>
|
||||
|
||||
#include "BoxBase.h"
|
||||
#include "GeometryUtil.h"
|
||||
#include "StreamUtils.h"
|
||||
|
||||
class AACube;
|
||||
|
@ -58,6 +59,7 @@ public:
|
|||
const glm::vec3& getMinimumPoint() const { return _corner; }
|
||||
glm::vec3 getMaximumPoint() const { return calcTopFarLeft(); }
|
||||
|
||||
bool contains(const Triangle& triangle) const;
|
||||
bool contains(const glm::vec3& point) const;
|
||||
bool contains(const AABox& otherBox) const;
|
||||
bool touches(const AABox& otherBox) const;
|
||||
|
@ -112,6 +114,19 @@ public:
|
|||
|
||||
void clear() { _corner = INFINITY_VECTOR; _scale = glm::vec3(0.0f); }
|
||||
|
||||
typedef enum {
|
||||
topLeftNear,
|
||||
topLeftFar,
|
||||
topRightNear,
|
||||
topRightFar,
|
||||
bottomLeftNear,
|
||||
bottomLeftFar,
|
||||
bottomRightNear,
|
||||
bottomRightFar
|
||||
} OctreeChild;
|
||||
|
||||
AABox getOctreeChild(OctreeChild child) const; // returns the AABox of the would be octree child of this AABox
|
||||
|
||||
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;
|
||||
|
|
|
@ -12,7 +12,22 @@
|
|||
#include "GLMHelpers.h"
|
||||
#include "TriangleSet.h"
|
||||
|
||||
void TriangleSet::insert(const Triangle& t) {
|
||||
|
||||
|
||||
bool TriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision) {
|
||||
|
||||
if (!_isBalanced) {
|
||||
balanceOctree();
|
||||
}
|
||||
|
||||
int trianglesTouched = 0;
|
||||
auto result = _triangleOctree.findRayIntersection(origin, direction, distance, face, surfaceNormal, precision, trianglesTouched);
|
||||
qDebug() << "trianglesTouched :" << trianglesTouched << "out of:" << _triangleOctree._population;
|
||||
return result;
|
||||
}
|
||||
|
||||
void InternalTriangleSet::insert(const Triangle& t) {
|
||||
_triangles.push_back(t);
|
||||
|
||||
_bounds += t.v0;
|
||||
|
@ -20,15 +35,15 @@ void TriangleSet::insert(const Triangle& t) {
|
|||
_bounds += t.v2;
|
||||
}
|
||||
|
||||
void TriangleSet::clear() {
|
||||
void InternalTriangleSet::clear() {
|
||||
_triangles.clear();
|
||||
_bounds.clear();
|
||||
}
|
||||
|
||||
// Determine of the given ray (origin/direction) in model space intersects with any triangles
|
||||
// in the set. If an intersection occurs, the distance and surface normal will be provided.
|
||||
bool TriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision) const {
|
||||
bool InternalTriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched) {
|
||||
|
||||
bool intersectedSomething = false;
|
||||
float boxDistance = std::numeric_limits<float>::max();
|
||||
|
@ -38,6 +53,7 @@ bool TriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3&
|
|||
if (precision) {
|
||||
for (const auto& triangle : _triangles) {
|
||||
float thisTriangleDistance;
|
||||
trianglesTouched++;
|
||||
if (findRayTriangleIntersection(origin, direction, triangle, thisTriangleDistance)) {
|
||||
if (thisTriangleDistance < bestDistance) {
|
||||
bestDistance = thisTriangleDistance;
|
||||
|
@ -57,7 +73,7 @@ bool TriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3&
|
|||
}
|
||||
|
||||
|
||||
bool TriangleSet::convexHullContains(const glm::vec3& point) const {
|
||||
bool InternalTriangleSet::convexHullContains(const glm::vec3& point) const {
|
||||
if (!_bounds.contains(point)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -74,3 +90,136 @@ bool TriangleSet::convexHullContains(const glm::vec3& point) const {
|
|||
return insideMesh;
|
||||
}
|
||||
|
||||
void TriangleSet::debugDump() {
|
||||
qDebug() << __FUNCTION__;
|
||||
qDebug() << "bounds:" << getBounds();
|
||||
qDebug() << "triangles:" << size() << "at top level....";
|
||||
qDebug() << "----- _triangleOctree -----";
|
||||
_triangleOctree.debugDump();
|
||||
}
|
||||
|
||||
void TriangleSet::balanceOctree() {
|
||||
_triangleOctree.reset(_bounds, 0);
|
||||
for (const auto& triangle : _triangles) {
|
||||
_triangleOctree.insert(triangle);
|
||||
}
|
||||
_isBalanced = true;
|
||||
}
|
||||
|
||||
static const int MAX_DEPTH = 3; // for now
|
||||
static const int MAX_CHILDREN = 8;
|
||||
|
||||
TriangleOctreeCell::TriangleOctreeCell(const AABox& bounds, int depth) {
|
||||
reset(bounds, depth);
|
||||
}
|
||||
|
||||
void TriangleOctreeCell::clear() {
|
||||
_triangleSet.clear();
|
||||
_population = 0;
|
||||
}
|
||||
|
||||
void TriangleOctreeCell::reset(const AABox& bounds, int depth) {
|
||||
//qDebug() << __FUNCTION__ << "bounds:" << bounds << "depth:" << depth;
|
||||
clear();
|
||||
_triangleSet._bounds = bounds;
|
||||
_depth = depth;
|
||||
if (depth <= MAX_DEPTH) {
|
||||
int childDepth = depth + 1;
|
||||
_children.clear();
|
||||
for (int child = 0; child < MAX_CHILDREN; child++) {
|
||||
AABox childBounds = getBounds().getOctreeChild((AABox::OctreeChild)child);
|
||||
/*
|
||||
qDebug() << __FUNCTION__ << "bounds:" << bounds << "depth:" << depth
|
||||
<< "child:" << child << "childBounds:" << childBounds << "childDepth:" << childDepth;
|
||||
*/
|
||||
|
||||
_children.push_back(TriangleOctreeCell(childBounds, childDepth));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TriangleOctreeCell::debugDump() {
|
||||
qDebug() << __FUNCTION__;
|
||||
qDebug() << "bounds:" << getBounds();
|
||||
qDebug() << "depth:" << _depth;
|
||||
qDebug() << "triangleSet:" << _triangleSet.size() << "at this level";
|
||||
qDebug() << "population:" << _population << "this level or below";
|
||||
if (_depth < MAX_DEPTH) {
|
||||
int childNum = 0;
|
||||
for (auto& child : _children) {
|
||||
qDebug() << "child:" << childNum;
|
||||
child.debugDump();
|
||||
childNum++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TriangleOctreeCell::insert(const Triangle& t) {
|
||||
_population++;
|
||||
// if we're not yet at the max depth, then check which child the triangle fits in
|
||||
if (_depth < MAX_DEPTH) {
|
||||
for (auto& child : _children) {
|
||||
if (child.getBounds().contains(t)) {
|
||||
child.insert(t);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// either we're at max depth, or the triangle doesn't fit in one of our
|
||||
// children and so we want to just record it here
|
||||
_triangleSet.insert(t);
|
||||
}
|
||||
|
||||
bool TriangleOctreeCell::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched) {
|
||||
|
||||
if (_population < 1) {
|
||||
return false; // no triangles below here, so we can't intersect
|
||||
}
|
||||
|
||||
float bestLocalDistance = std::numeric_limits<float>::max();
|
||||
BoxFace bestLocalFace;
|
||||
glm::vec3 bestLocalNormal;
|
||||
bool intersects = false;
|
||||
|
||||
// if the ray intersects our bounding box, then continue
|
||||
if (getBounds().findRayIntersection(origin, direction, bestLocalDistance, bestLocalFace, bestLocalNormal)) {
|
||||
bestLocalDistance = std::numeric_limits<float>::max();
|
||||
|
||||
float childDistance = std::numeric_limits<float>::max();
|
||||
BoxFace childFace;
|
||||
glm::vec3 childNormal;
|
||||
|
||||
// if we're not yet at the max depth, then check which child the triangle fits in
|
||||
if (_depth < MAX_DEPTH) {
|
||||
for (auto& child : _children) {
|
||||
// check each child, if there's an intersection, it will return some distance that we need
|
||||
// to compare against the other results, because there might be multiple intersections and
|
||||
// we will always choose the best (shortest) intersection
|
||||
if (child.findRayIntersection(origin, direction, childDistance, childFace, childNormal, precision, trianglesTouched)) {
|
||||
if (childDistance < bestLocalDistance) {
|
||||
bestLocalDistance = childDistance;
|
||||
bestLocalFace = childFace;
|
||||
bestLocalNormal = childNormal;
|
||||
intersects = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// also check our local triangle set
|
||||
if (_triangleSet.findRayIntersection(origin, direction, childDistance, childFace, childNormal, precision, trianglesTouched)) {
|
||||
if (childDistance < bestLocalDistance) {
|
||||
bestLocalDistance = childDistance;
|
||||
bestLocalFace = childFace;
|
||||
bestLocalNormal = childNormal;
|
||||
intersects = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (intersects) {
|
||||
distance = bestLocalDistance;
|
||||
face = bestLocalFace;
|
||||
surfaceNormal = bestLocalNormal;
|
||||
}
|
||||
return intersects;
|
||||
}
|
||||
|
|
|
@ -14,20 +14,21 @@
|
|||
#include "AABox.h"
|
||||
#include "GeometryUtil.h"
|
||||
|
||||
class TriangleSet {
|
||||
class InternalTriangleSet {
|
||||
public:
|
||||
InternalTriangleSet() { }
|
||||
|
||||
void reserve(size_t size) { _triangles.reserve(size); } // reserve space in the datastructure for size number of triangles
|
||||
size_t size() const { return _triangles.size(); }
|
||||
|
||||
const Triangle& getTriangle(size_t t) const { return _triangles[t]; }
|
||||
|
||||
void insert(const Triangle& t);
|
||||
virtual void insert(const Triangle& t);
|
||||
void clear();
|
||||
|
||||
// Determine if the given ray (origin/direction) in model space intersects with any triangles in the set. If an
|
||||
// intersection occurs, the distance and surface normal will be provided.
|
||||
// note: this might side-effect internal structures
|
||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision) const;
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched);
|
||||
|
||||
// Determine if a point is "inside" all the triangles of a convex hull. It is the responsibility of the caller to
|
||||
// determine that the triangle set is indeed a convex hull. If the triangles added to this set are not in fact a
|
||||
|
@ -35,7 +36,60 @@ public:
|
|||
bool convexHullContains(const glm::vec3& point) const;
|
||||
const AABox& getBounds() const { return _bounds; }
|
||||
|
||||
private:
|
||||
protected:
|
||||
std::vector<Triangle> _triangles;
|
||||
AABox _bounds;
|
||||
|
||||
friend class TriangleOctreeCell;
|
||||
};
|
||||
|
||||
class TriangleOctreeCell {
|
||||
public:
|
||||
TriangleOctreeCell() { }
|
||||
|
||||
void insert(const Triangle& t);
|
||||
void reset(const AABox& bounds, int depth = 0);
|
||||
void clear();
|
||||
|
||||
// Determine if the given ray (origin/direction) in model space intersects with any triangles in the set. If an
|
||||
// intersection occurs, the distance and surface normal will be provided.
|
||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision, int& trianglesTouched);
|
||||
|
||||
const AABox& getBounds() const { return _triangleSet.getBounds(); }
|
||||
|
||||
void debugDump();
|
||||
|
||||
protected:
|
||||
TriangleOctreeCell(const AABox& bounds, int depth);
|
||||
|
||||
InternalTriangleSet _triangleSet;
|
||||
std::vector<TriangleOctreeCell> _children;
|
||||
int _depth { 0 };
|
||||
int _population { 0 };
|
||||
|
||||
friend class TriangleSet;
|
||||
};
|
||||
|
||||
class TriangleSet : public InternalTriangleSet {
|
||||
// pass through public implementation all the features of InternalTriangleSet
|
||||
public:
|
||||
TriangleSet() { }
|
||||
|
||||
void debugDump();
|
||||
|
||||
virtual void insert(const Triangle& t) {
|
||||
_isBalanced = false;
|
||||
InternalTriangleSet::insert(t);
|
||||
}
|
||||
|
||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, bool precision);
|
||||
|
||||
void balanceOctree();
|
||||
|
||||
protected:
|
||||
|
||||
bool _isBalanced { false };
|
||||
TriangleOctreeCell _triangleOctree;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue