mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 14:18:24 +02:00
Implementing the octree selection from frustum
This commit is contained in:
parent
1b5499b3d6
commit
18d8a2fb42
4 changed files with 150 additions and 6 deletions
|
@ -125,6 +125,9 @@ public:
|
||||||
float calculateRenderAccuracy(const AABox& bounds, float octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE,
|
float calculateRenderAccuracy(const AABox& bounds, float octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE,
|
||||||
int boundaryLevelAdjust = 0) const;
|
int boundaryLevelAdjust = 0) const;
|
||||||
|
|
||||||
|
enum PlaneIndex { TOP_PLANE = 0, BOTTOM_PLANE, LEFT_PLANE, RIGHT_PLANE, NEAR_PLANE, FAR_PLANE, NUM_PLANES };
|
||||||
|
|
||||||
|
const ::Plane* getPlanes() const { return _planes; }
|
||||||
private:
|
private:
|
||||||
// Used for keyhole calculations
|
// Used for keyhole calculations
|
||||||
ViewFrustum::location pointInKeyhole(const glm::vec3& point) const;
|
ViewFrustum::location pointInKeyhole(const glm::vec3& point) const;
|
||||||
|
@ -160,7 +163,7 @@ private:
|
||||||
float _fieldOfView = DEFAULT_FIELD_OF_VIEW_DEGREES;
|
float _fieldOfView = DEFAULT_FIELD_OF_VIEW_DEGREES;
|
||||||
glm::vec4 _corners[8];
|
glm::vec4 _corners[8];
|
||||||
glm::vec3 _cornersWorld[8];
|
glm::vec3 _cornersWorld[8];
|
||||||
enum { TOP_PLANE = 0, BOTTOM_PLANE, LEFT_PLANE, RIGHT_PLANE, NEAR_PLANE, FAR_PLANE };
|
// enum { TOP_PLANE = 0, BOTTOM_PLANE, LEFT_PLANE, RIGHT_PLANE, NEAR_PLANE, FAR_PLANE };
|
||||||
::Plane _planes[6]; // How will this be used?
|
::Plane _planes[6]; // How will this be used?
|
||||||
|
|
||||||
const char* debugPlaneName (int plane) const;
|
const char* debugPlaneName (int plane) const;
|
||||||
|
|
|
@ -80,6 +80,11 @@ void DrawSceneOctree::run(const SceneContextPointer& sceneContext,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try that:
|
||||||
|
render::ItemIDs items;
|
||||||
|
scene->getSpatialTree().select(items, *args->_viewFrustum);
|
||||||
|
|
||||||
|
|
||||||
// Allright, something to render let's do it
|
// Allright, something to render let's do it
|
||||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||||
glm::mat4 projMat;
|
glm::mat4 projMat;
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
//
|
//
|
||||||
#include "Octree.h"
|
#include "Octree.h"
|
||||||
|
|
||||||
|
#include <ViewFrustum.h>
|
||||||
|
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
|
|
||||||
|
@ -68,7 +70,7 @@ Octree::Location Octree::Location::evalFromRange(const Coord3& minCoord, const C
|
||||||
}
|
}
|
||||||
|
|
||||||
Octree::Indices Octree::indexConcreteCellPath(const Locations& path) const {
|
Octree::Indices Octree::indexConcreteCellPath(const Locations& path) const {
|
||||||
Index currentIndex = ROOT;
|
Index currentIndex = ROOT_CELL;
|
||||||
Indices cellPath(1, currentIndex);
|
Indices cellPath(1, currentIndex);
|
||||||
|
|
||||||
for (int l = 1; l < path.size(); l++) {
|
for (int l = 1; l < path.size(); l++) {
|
||||||
|
@ -217,3 +219,114 @@ ItemSpatialTree::Index ItemSpatialTree::resetItem(Index oldCell, const Location&
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ItemSpatialTree::select(ItemIDs& selection, const ViewFrustum& frustum) const {
|
||||||
|
auto worldPlanes = frustum.getPlanes();
|
||||||
|
Coord4f planes[6];
|
||||||
|
for (int i = 0; i < ViewFrustum::NUM_PLANES; i++) {
|
||||||
|
::Plane octPlane;
|
||||||
|
octPlane.setNormalAndPoint(worldPlanes[i].getNormal(), evalCoordf(worldPlanes[i].getPoint(), ROOT_DEPTH));
|
||||||
|
planes[i] = Coord4f(octPlane.getNormal(), octPlane.getDCoefficient());
|
||||||
|
}
|
||||||
|
return Octree::select(selection, planes);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Octree::select(ItemIDs& selection, const glm::vec4 frustum[6]) const {
|
||||||
|
|
||||||
|
Index cellID = ROOT_CELL;
|
||||||
|
selectTraverse(cellID, selection, frustum);
|
||||||
|
return selection.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Octree::selectTraverse(Index cellID, ItemIDs& selection, const Coord4f frustum[6]) const {
|
||||||
|
int numItemsIn = selection.size();
|
||||||
|
auto cell = getConcreteCell(cellID);
|
||||||
|
|
||||||
|
auto intersection = Octree::Location::intersectCell(cell.getlocation(), frustum);
|
||||||
|
switch (intersection) {
|
||||||
|
case Octree::Location::Outside:
|
||||||
|
// cell is outside, stop traversing this branch
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case Octree::Location::Inside: {
|
||||||
|
// traverse all the Cell Branch and collect items in the selection
|
||||||
|
selection.push_back(cellID);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Octree::Location::Intersect:
|
||||||
|
default: {
|
||||||
|
// Cell is partially in
|
||||||
|
selection.push_back(cellID);
|
||||||
|
|
||||||
|
// Collect the items of this cell
|
||||||
|
|
||||||
|
// then traverse further
|
||||||
|
for (int i = 0; i < NUM_OCTANTS; i++) {
|
||||||
|
Index subCellID = cell.child((Link)i);
|
||||||
|
if (subCellID != INVALID) {
|
||||||
|
selectTraverse(subCellID, selection, frustum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return selection.size() - numItemsIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Octree::Location::Intersection Octree::Location::intersectCell(const Location& cell, const Coord4f frustum[6]) {
|
||||||
|
const Coord3f CornerOffsets[8] = {
|
||||||
|
{ 0.0, 0.0, 0.0 },
|
||||||
|
{ 1.0, 0.0, 0.0 },
|
||||||
|
{ 0.0, 1.0, 0.0 },
|
||||||
|
{ 1.0, 1.0, 0.0 },
|
||||||
|
{ 0.0, 0.0, 1.0 },
|
||||||
|
{ 1.0, 0.0, 1.0 },
|
||||||
|
{ 0.0, 1.0, 1.0 },
|
||||||
|
{ 1.0, 1.0, 1.0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Tool {
|
||||||
|
static int normalToIndex(const Coord3f& n) {
|
||||||
|
int index = 0;
|
||||||
|
if (n.x >= 0.0) index |= 1;
|
||||||
|
if (n.y >= 0.0) index |= 2;
|
||||||
|
if (n.z >= 0.0) index |= 4;
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool halfPlaneTest(const Coord4f& plane, const Coord3f& pos) {
|
||||||
|
return (glm::dot(plane, Coord4f(pos, 1.0f)) >= 0.0f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Coord3f cellSize = Coord3f(Octree::getInvDepthDimension(cell.depth));
|
||||||
|
Coord3f cellPos = Coord3f(cell.pos) * cellSize;
|
||||||
|
|
||||||
|
bool partialFlag = false;
|
||||||
|
for (int p = 0; p < ViewFrustum::NUM_PLANES; p++) {
|
||||||
|
Coord4f plane = frustum[p];
|
||||||
|
Coord3f planeNormal(plane);
|
||||||
|
|
||||||
|
int index = Tool::normalToIndex(planeNormal);
|
||||||
|
|
||||||
|
auto negTestPoint = cellPos + cellSize * CornerOffsets[index];
|
||||||
|
|
||||||
|
if (!Tool::halfPlaneTest(plane, negTestPoint)) {
|
||||||
|
return Outside;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = Tool::normalToIndex(-planeNormal);
|
||||||
|
|
||||||
|
auto posTestPoint = cellPos + cellSize * CornerOffsets[index];
|
||||||
|
|
||||||
|
if (!Tool::halfPlaneTest(plane, posTestPoint)) {
|
||||||
|
partialFlag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (partialFlag) {
|
||||||
|
return Intersect;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Inside;
|
||||||
|
}
|
|
@ -85,6 +85,7 @@ namespace render {
|
||||||
|
|
||||||
// Max depth is 15 => 32Km root down to 1m cells
|
// Max depth is 15 => 32Km root down to 1m cells
|
||||||
using Depth = int8_t;
|
using Depth = int8_t;
|
||||||
|
static const Depth ROOT_DEPTH{ 0 };
|
||||||
static const Depth MAX_DEPTH { 15 };
|
static const Depth MAX_DEPTH { 15 };
|
||||||
static const double INV_DEPTH_DIM[Octree::MAX_DEPTH + 1];
|
static const double INV_DEPTH_DIM[Octree::MAX_DEPTH + 1];
|
||||||
|
|
||||||
|
@ -95,6 +96,8 @@ namespace render {
|
||||||
using Coord = int16_t;
|
using Coord = int16_t;
|
||||||
using Coord3 = glm::i16vec3;
|
using Coord3 = glm::i16vec3;
|
||||||
using Coord4 = glm::i16vec4;
|
using Coord4 = glm::i16vec4;
|
||||||
|
using Coord3f = glm::vec3;
|
||||||
|
using Coord4f = glm::vec4;
|
||||||
|
|
||||||
static Coord depthBitmask(Depth depth) { return Coord(1 << (MAX_DEPTH - depth)); }
|
static Coord depthBitmask(Depth depth) { return Coord(1 << (MAX_DEPTH - depth)); }
|
||||||
|
|
||||||
|
@ -122,7 +125,7 @@ namespace render {
|
||||||
|
|
||||||
Coord3 pos{ 0 };
|
Coord3 pos{ 0 };
|
||||||
uint8_t spare{ 0 };
|
uint8_t spare{ 0 };
|
||||||
Depth depth{ 0 };
|
Depth depth{ ROOT_DEPTH };
|
||||||
|
|
||||||
bool operator== (const Location& right) const { return pos == right.pos && depth == right.depth; }
|
bool operator== (const Location& right) const { return pos == right.pos && depth == right.depth; }
|
||||||
|
|
||||||
|
@ -140,13 +143,22 @@ namespace render {
|
||||||
|
|
||||||
// Eval the location best fitting the specified range
|
// Eval the location best fitting the specified range
|
||||||
static Location evalFromRange(const Coord3& minCoord, const Coord3& maxCoord, Depth rangeDepth = MAX_DEPTH);
|
static Location evalFromRange(const Coord3& minCoord, const Coord3& maxCoord, Depth rangeDepth = MAX_DEPTH);
|
||||||
|
|
||||||
|
// Eval the intersection test against a frustum
|
||||||
|
enum Intersection {
|
||||||
|
Outside = 0,
|
||||||
|
Intersect,
|
||||||
|
Inside,
|
||||||
|
};
|
||||||
|
static Intersection intersectCell(const Location& cell, const Coord4f frustum[6]);
|
||||||
|
|
||||||
};
|
};
|
||||||
using Locations = Location::vector;
|
using Locations = Location::vector;
|
||||||
|
|
||||||
// Cell or Brick Indexing
|
// Cell or Brick Indexing
|
||||||
using Index = ItemCell; // int32_t
|
using Index = ItemCell; // int32_t
|
||||||
static const Index INVALID = -1;
|
static const Index INVALID = -1;
|
||||||
static const Index ROOT = 0;
|
static const Index ROOT_CELL = 0;
|
||||||
using Indices = std::vector<Index>;
|
using Indices = std::vector<Index>;
|
||||||
|
|
||||||
// the cell description
|
// the cell description
|
||||||
|
@ -230,6 +242,10 @@ namespace render {
|
||||||
return _bricks[index];
|
return _bricks[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Selection and traverse
|
||||||
|
int select(ItemIDs& selection, const Coord4f frustum[6]) const;
|
||||||
|
int selectTraverse(Index cellID, ItemIDs& selection, const Coord4f frustum[6]) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Index allocateCell(Index parent, const Location& location);
|
Index allocateCell(Index parent, const Location& location);
|
||||||
Index allocateBrick();
|
Index allocateBrick();
|
||||||
|
@ -252,6 +268,7 @@ namespace render {
|
||||||
double _invSize{ 1.0 / _size };
|
double _invSize{ 1.0 / _size };
|
||||||
glm::vec3 _origin{ -16384.0f };
|
glm::vec3 _origin{ -16384.0f };
|
||||||
public:
|
public:
|
||||||
|
ItemSpatialTree() {}
|
||||||
|
|
||||||
float getSize() const { return _size; }
|
float getSize() const { return _size; }
|
||||||
const glm::vec3& getOrigin() const { return _origin; }
|
const glm::vec3& getOrigin() const { return _origin; }
|
||||||
|
@ -270,7 +287,10 @@ namespace render {
|
||||||
auto npos = (pos - getOrigin());
|
auto npos = (pos - getOrigin());
|
||||||
return Coord3(npos * getInvCellWidth(depth));
|
return Coord3(npos * getInvCellWidth(depth));
|
||||||
}
|
}
|
||||||
|
Coord3f evalCoordf(const glm::vec3& pos, Depth depth = Octree::MAX_DEPTH) const {
|
||||||
|
auto npos = (pos - getOrigin());
|
||||||
|
return Coord3f(npos * getInvCellWidth(depth));
|
||||||
|
}
|
||||||
|
|
||||||
// Bound to Location
|
// Bound to Location
|
||||||
AABox evalBound(const Location& loc) const {
|
AABox evalBound(const Location& loc) const {
|
||||||
|
@ -289,7 +309,10 @@ namespace render {
|
||||||
|
|
||||||
Index resetItem(Index oldCell, const Location& location, const ItemID& item);
|
Index resetItem(Index oldCell, const Location& location, const ItemID& item);
|
||||||
|
|
||||||
ItemSpatialTree() {}
|
// Selection and traverse
|
||||||
|
int select(ItemIDs& selection, const ViewFrustum& frustum) const;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue