Implementing the octree selection from frustum

This commit is contained in:
samcake 2016-02-01 13:47:38 -08:00
parent 1b5499b3d6
commit 18d8a2fb42
4 changed files with 150 additions and 6 deletions

View file

@ -125,6 +125,9 @@ public:
float calculateRenderAccuracy(const AABox& bounds, float octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE,
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:
// Used for keyhole calculations
ViewFrustum::location pointInKeyhole(const glm::vec3& point) const;
@ -160,7 +163,7 @@ private:
float _fieldOfView = DEFAULT_FIELD_OF_VIEW_DEGREES;
glm::vec4 _corners[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?
const char* debugPlaneName (int plane) const;

View file

@ -80,6 +80,11 @@ void DrawSceneOctree::run(const SceneContextPointer& sceneContext,
return;
}
// Try that:
render::ItemIDs items;
scene->getSpatialTree().select(items, *args->_viewFrustum);
// Allright, something to render let's do it
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
glm::mat4 projMat;

View file

@ -10,6 +10,8 @@
//
#include "Octree.h"
#include <ViewFrustum.h>
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 {
Index currentIndex = ROOT;
Index currentIndex = ROOT_CELL;
Indices cellPath(1, currentIndex);
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;
}

View file

@ -85,6 +85,7 @@ namespace render {
// Max depth is 15 => 32Km root down to 1m cells
using Depth = int8_t;
static const Depth ROOT_DEPTH{ 0 };
static const Depth MAX_DEPTH { 15 };
static const double INV_DEPTH_DIM[Octree::MAX_DEPTH + 1];
@ -95,6 +96,8 @@ namespace render {
using Coord = int16_t;
using Coord3 = glm::i16vec3;
using Coord4 = glm::i16vec4;
using Coord3f = glm::vec3;
using Coord4f = glm::vec4;
static Coord depthBitmask(Depth depth) { return Coord(1 << (MAX_DEPTH - depth)); }
@ -122,7 +125,7 @@ namespace render {
Coord3 pos{ 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; }
@ -140,13 +143,22 @@ namespace render {
// Eval the location best fitting the specified range
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;
// Cell or Brick Indexing
using Index = ItemCell; // int32_t
static const Index INVALID = -1;
static const Index ROOT = 0;
static const Index ROOT_CELL = 0;
using Indices = std::vector<Index>;
// the cell description
@ -230,6 +242,10 @@ namespace render {
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:
Index allocateCell(Index parent, const Location& location);
Index allocateBrick();
@ -252,6 +268,7 @@ namespace render {
double _invSize{ 1.0 / _size };
glm::vec3 _origin{ -16384.0f };
public:
ItemSpatialTree() {}
float getSize() const { return _size; }
const glm::vec3& getOrigin() const { return _origin; }
@ -270,8 +287,11 @@ namespace render {
auto npos = (pos - getOrigin());
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
AABox evalBound(const Location& loc) const {
float cellWidth = getCellWidth(loc.depth);
@ -289,7 +309,10 @@ namespace render {
Index resetItem(Index oldCell, const Location& location, const ItemID& item);
ItemSpatialTree() {}
// Selection and traverse
int select(ItemIDs& selection, const ViewFrustum& frustum) const;
};
}