From 18d8a2fb42e6f8303f83a726f2665f88ccc2c7f6 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 1 Feb 2016 13:47:38 -0800 Subject: [PATCH] Implementing the octree selection from frustum --- libraries/octree/src/ViewFrustum.h | 5 +- .../render/src/render/DrawSceneOctree.cpp | 5 + libraries/render/src/render/Octree.cpp | 115 +++++++++++++++++- libraries/render/src/render/Octree.h | 31 ++++- 4 files changed, 150 insertions(+), 6 deletions(-) diff --git a/libraries/octree/src/ViewFrustum.h b/libraries/octree/src/ViewFrustum.h index 98e782b267..548bd6a940 100644 --- a/libraries/octree/src/ViewFrustum.h +++ b/libraries/octree/src/ViewFrustum.h @@ -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; diff --git a/libraries/render/src/render/DrawSceneOctree.cpp b/libraries/render/src/render/DrawSceneOctree.cpp index 55e0506a1d..53b0e2b87a 100644 --- a/libraries/render/src/render/DrawSceneOctree.cpp +++ b/libraries/render/src/render/DrawSceneOctree.cpp @@ -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; diff --git a/libraries/render/src/render/Octree.cpp b/libraries/render/src/render/Octree.cpp index 65187f1e4a..536e876e12 100644 --- a/libraries/render/src/render/Octree.cpp +++ b/libraries/render/src/render/Octree.cpp @@ -10,6 +10,8 @@ // #include "Octree.h" +#include + 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; +} \ No newline at end of file diff --git a/libraries/render/src/render/Octree.h b/libraries/render/src/render/Octree.h index bd54a297b0..4f148636b5 100644 --- a/libraries/render/src/render/Octree.h +++ b/libraries/render/src/render/Octree.h @@ -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; // 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; + + }; }