From 24501e5c6805dde1cf959c2e8b0e2cc8921ad5a7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 8 May 2013 14:22:03 -0700 Subject: [PATCH 1/5] added contains() and remove() methods --- libraries/voxels/src/VoxelNodeBag.cpp | 36 +++++++++++++++++++++++++++ libraries/voxels/src/VoxelNodeBag.h | 2 ++ 2 files changed, 38 insertions(+) diff --git a/libraries/voxels/src/VoxelNodeBag.cpp b/libraries/voxels/src/VoxelNodeBag.cpp index 9646c2d2fc..20a469dec8 100644 --- a/libraries/voxels/src/VoxelNodeBag.cpp +++ b/libraries/voxels/src/VoxelNodeBag.cpp @@ -82,3 +82,39 @@ VoxelNode* VoxelNodeBag::extract() { } return NULL; } + +bool VoxelNodeBag::contains(VoxelNode* node) { + for (int i = 0; i < _elementsInUse; i++) { + // just compare the pointers... that's good enough + if (_bagElements[i] == node) { + return true; // exit early!! + } + // if we're past where it should be, then it's not here! + if (_bagElements[i] > node) { + return false; + } + } + // if we made it through the entire bag, it's not here! + return false; +} + +void VoxelNodeBag::remove(VoxelNode* node) { + int foundAt = -1; + for (int i = 0; i < _elementsInUse; i++) { + // just compare the pointers... that's good enough + if (_bagElements[i] == node) { + foundAt = i; + break; + } + // if we're past where it should be, then it's not here! + if (_bagElements[i] > node) { + break; + } + } + // if we found it, then we need to remove it.... + if (foundAt != -1) { + memmove(&_bagElements[foundAt], &_bagElements[foundAt + 1], (_elementsInUse - foundAt) * sizeof(VoxelNode*)); + _elementsInUse--; + } +} + diff --git a/libraries/voxels/src/VoxelNodeBag.h b/libraries/voxels/src/VoxelNodeBag.h index 9eb6a91e6a..ee6e5045d0 100644 --- a/libraries/voxels/src/VoxelNodeBag.h +++ b/libraries/voxels/src/VoxelNodeBag.h @@ -28,6 +28,8 @@ public: void insert(VoxelNode* node); // put a node into the bag VoxelNode* extract(); // pull a node out of the bag (could come in any order) + bool contains(VoxelNode* node); // is this node in the bag? + void remove(VoxelNode* node); // remove a specific item from the bag bool isEmpty() const { return (_elementsInUse == 0); }; int count() const { return _elementsInUse; }; From 66e416d4dda31977ba1e06857873c3e660b297cf Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 8 May 2013 14:23:36 -0700 Subject: [PATCH 2/5] added VoxelNode::inFrustum() which returns OUTSIDE, INTERSECT, INSIDE to allow more optimal frustum analysis --- libraries/voxels/src/ViewFrustum.cpp | 12 ++++++------ libraries/voxels/src/ViewFrustum.h | 6 +++--- libraries/voxels/src/VoxelNode.cpp | 6 ++++++ libraries/voxels/src/VoxelNode.h | 1 + 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index 51b04e9640..a107e2f869 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -158,12 +158,12 @@ const char* ViewFrustum::debugPlaneName (int plane) const { } -int ViewFrustum::pointInFrustum(const glm::vec3& point) const { +ViewFrustum::location ViewFrustum::pointInFrustum(const glm::vec3& point) const { //printf("ViewFrustum::pointInFrustum() point=%f,%f,%f\n",point.x,point.y,point.z); //dump(); - int result = INSIDE; + ViewFrustum::location result = INSIDE; for(int i=0; i < 6; i++) { float distance = _planes[i].distance(point); @@ -176,8 +176,8 @@ int ViewFrustum::pointInFrustum(const glm::vec3& point) const { return(result); } -int ViewFrustum::sphereInFrustum(const glm::vec3& center, float radius) const { - int result = INSIDE; +ViewFrustum::location ViewFrustum::sphereInFrustum(const glm::vec3& center, float radius) const { + ViewFrustum::location result = INSIDE; float distance; for(int i=0; i < 6; i++) { distance = _planes[i].distance(center); @@ -190,11 +190,11 @@ int ViewFrustum::sphereInFrustum(const glm::vec3& center, float radius) const { } -int ViewFrustum::boxInFrustum(const AABox& box) const { +ViewFrustum::location ViewFrustum::boxInFrustum(const AABox& box) const { //printf("ViewFrustum::boxInFrustum() box.corner=%f,%f,%f x=%f\n", // box.getCorner().x,box.getCorner().y,box.getCorner().z,box.getSize().x); - int result = INSIDE; + ViewFrustum::location result = INSIDE; for(int i=0; i < 6; i++) { //printf("plane[%d] -- point(%f,%f,%f) normal(%f,%f,%f) d=%f \n",i, diff --git a/libraries/voxels/src/ViewFrustum.h b/libraries/voxels/src/ViewFrustum.h index 9cf6890609..007654fcf4 100644 --- a/libraries/voxels/src/ViewFrustum.h +++ b/libraries/voxels/src/ViewFrustum.h @@ -94,9 +94,9 @@ public: typedef enum {OUTSIDE, INTERSECT, INSIDE} location; - int pointInFrustum(const glm::vec3& point) const; - int sphereInFrustum(const glm::vec3& center, float radius) const; - int boxInFrustum(const AABox& box) const; + ViewFrustum::location pointInFrustum(const glm::vec3& point) const; + ViewFrustum::location sphereInFrustum(const glm::vec3& center, float radius) const; + ViewFrustum::location boxInFrustum(const AABox& box) const; // some frustum comparisons bool matches(const ViewFrustum& compareTo) const; diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 02f1592126..9ee95f1e2a 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -259,6 +259,12 @@ bool VoxelNode::isInView(const ViewFrustum& viewFrustum) const { return inView; } +ViewFrustum::location VoxelNode::inFrustum(const ViewFrustum& viewFrustum) const { + AABox box = _box; // use temporary box so we can scale it + box.scale(TREE_SCALE); + return viewFrustum.boxInFrustum(box); +} + float VoxelNode::distanceToCamera(const ViewFrustum& viewFrustum) const { glm::vec3 center = _box.getCenter() * (float)TREE_SCALE; float distanceToVoxelCenter = sqrtf(powf(viewFrustum.getPosition().x - center.x, 2) + diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 386f95e634..51af8f6379 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -57,6 +57,7 @@ public: bool isColored() const { return (_trueColor[3]==1); }; bool isInView(const ViewFrustum& viewFrustum) const; + ViewFrustum::location inFrustum(const ViewFrustum& viewFrustum) const; float distanceToCamera(const ViewFrustum& viewFrustum) const; bool isLeaf() const; void printDebugDetails(const char* label) const; From 70557cd51c5cfa64a4e5d3d8d45cb3b020e6ff0b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 8 May 2013 14:24:08 -0700 Subject: [PATCH 3/5] Optimized removeOutOfView() - don't recurse down trees that are fully INSIDE of the view frustum, because those nodes are guaranteed to also be INSIDE - changes to extraData of the recurse operation to make this possible - adding debug stats to track how many nodes are inside, outside, intersect - change call to removeOutOfView() to not call if last elapsed time has not yet passed since last call (similar to treeToArrays() logic) --- interface/src/VoxelSystem.cpp | 83 ++++++++++++++++++++++++++++++----- interface/src/VoxelSystem.h | 1 + 2 files changed, 74 insertions(+), 10 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 3d5880c305..41977f23f7 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -146,9 +146,11 @@ void VoxelSystem::setupNewVoxelsForDrawing() { double sinceLastViewCulling = (start - _lastViewCulling) / 1000.0; // If the view frustum has changed, since last time, then remove nodes that are out of view - if ((sinceLastViewCulling >= VIEW_CULLING_RATE_IN_MILLISECONDS) && hasViewChanged()) { + if ((sinceLastViewCulling >= std::max(_lastViewCullingElapsed,VIEW_CULLING_RATE_IN_MILLISECONDS)) && hasViewChanged()) { _lastViewCulling = start; removeOutOfView(); + double endViewCulling = usecTimestampNow(); + _lastViewCullingElapsed = (endViewCulling - start)/1000.0; } if (_tree->isDirty()) { @@ -294,7 +296,7 @@ void VoxelSystem::init() { _callsToTreesToArrays = 0; _setupNewVoxelsForDrawingLastFinished = 0; _setupNewVoxelsForDrawingLastElapsed = 0; - _lastViewCulling = 0; + _lastViewCullingElapsed = _lastViewCulling = 0; // When we change voxels representations in the arrays, we'll update this _voxelsDirty = false; @@ -583,17 +585,71 @@ void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) { setupNewVoxelsForDrawing(); } +// combines the removeOutOfView args into a single class +class removeOutOfViewArgs { +public: + VoxelSystem* thisVoxelSystem; + VoxelNodeBag dontRecurseBag; + unsigned long nodesScanned; + unsigned long nodesRemoved; + unsigned long nodesInside; + unsigned long nodesIntersect; + unsigned long nodesOutside; + + removeOutOfViewArgs(VoxelSystem* voxelSystem) : + thisVoxelSystem(voxelSystem), + dontRecurseBag(), + nodesScanned(0), + nodesRemoved(0), + nodesInside(0), + nodesIntersect(0), + nodesOutside(0) + { } +}; + // "Remove" voxels from the tree that are not in view. We don't actually delete them, // we remove them from the tree and place them into a holding area for later deletion bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) { - VoxelSystem* thisVoxelSystem = (VoxelSystem*) extraData; - _nodeCount++; + removeOutOfViewArgs* args = (removeOutOfViewArgs*)extraData; + + // If our node was previously added to the don't recurse bag, then return false to + // stop the further recursion. This means that the whole node and it's children are + // known to be in view, so don't recurse them + if (args->dontRecurseBag.contains(node)) { + args->dontRecurseBag.remove(node); + return false; // stop recursion + } + + VoxelSystem* thisVoxelSystem = args->thisVoxelSystem; + args->nodesScanned++; // Need to operate on our child nodes, so we can remove them for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { VoxelNode* childNode = node->getChildAtIndex(i); - if (childNode && !childNode->isInView(*thisVoxelSystem->_viewFrustum)) { - node->removeChildAtIndex(i); - thisVoxelSystem->_removedVoxels.insert(childNode); + if (childNode) { + ViewFrustum::location inFrustum = childNode->inFrustum(*thisVoxelSystem->_viewFrustum); + switch (inFrustum) { + case ViewFrustum::OUTSIDE: { + args->nodesOutside++; + args->nodesRemoved++; + node->removeChildAtIndex(i); + thisVoxelSystem->_removedVoxels.insert(childNode); + // by removing the child, it will not get recursed! + } break; + case ViewFrustum::INSIDE: { + // if the child node is fully INSIDE the view, then there's no need to recurse it + // because we know all it's children will also be in the view, so we want to + // tell the caller to NOT recurse this child + args->nodesInside++; + args->dontRecurseBag.insert(childNode); + } break; + case ViewFrustum::INTERSECT: { + // if the child node INTERSECTs the view, then we don't want to remove it because + // it is at least partially in view. But we DO want to recurse the children because + // some of them may not be in view... nothing specifically to do, just keep iterating + // the children + args->nodesIntersect++; + } break; + } } } return true; // keep going! @@ -609,7 +665,14 @@ bool VoxelSystem::hasViewChanged() { } void VoxelSystem::removeOutOfView() { - PerformanceWarning warn(_renderWarningsOn, "removeOutOfView()"); // would like to include removedCount, _nodeCount, _removedVoxels.count() - _nodeCount = 0; - _tree->recurseTreeWithOperation(removeOutOfViewOperation,(void*)this); + PerformanceWarning warn(_renderWarningsOn, "removeOutOfView()"); + removeOutOfViewArgs args(this); + _tree->recurseTreeWithOperation(removeOutOfViewOperation,(void*)&args); + + if (_renderWarningsOn) { + printLog("removeOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld bag.count()=%d \n", + args.nodesScanned, args.nodesRemoved, args.nodesInside, + args.nodesIntersect, args.nodesOutside, args.dontRecurseBag.count() + ); + } } diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index f3968004b0..03877206ab 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -104,6 +104,7 @@ private: double _setupNewVoxelsForDrawingLastElapsed; double _setupNewVoxelsForDrawingLastFinished; double _lastViewCulling; + double _lastViewCullingElapsed; GLuint _vboVerticesID; GLuint _vboNormalsID; From ed30a03b2eebf455bf5a10e7a1e32e3b4cc3e1fb Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 8 May 2013 14:30:18 -0700 Subject: [PATCH 4/5] CR cleanup --- interface/src/VoxelSystem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 41977f23f7..5cd29fb4d1 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -139,14 +139,14 @@ void VoxelSystem::setupNewVoxelsForDrawing() { double start = usecTimestampNow(); double sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000.0; - if (sinceLastTime <= std::max(_setupNewVoxelsForDrawingLastElapsed,SIXTY_FPS_IN_MILLISECONDS)) { + if (sinceLastTime <= std::max(_setupNewVoxelsForDrawingLastElapsed, SIXTY_FPS_IN_MILLISECONDS)) { return; // bail early, it hasn't been long enough since the last time we ran } double sinceLastViewCulling = (start - _lastViewCulling) / 1000.0; // If the view frustum has changed, since last time, then remove nodes that are out of view - if ((sinceLastViewCulling >= std::max(_lastViewCullingElapsed,VIEW_CULLING_RATE_IN_MILLISECONDS)) && hasViewChanged()) { + if ((sinceLastViewCulling >= std::max(_lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS)) && hasViewChanged()) { _lastViewCulling = start; removeOutOfView(); double endViewCulling = usecTimestampNow(); From cb5ccee1e452b6cf269ed5848f514fec0a86ec52 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 8 May 2013 14:32:55 -0700 Subject: [PATCH 5/5] CR cleanup --- interface/src/VoxelSystem.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 5cd29fb4d1..5aedb698e0 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -144,19 +144,17 @@ void VoxelSystem::setupNewVoxelsForDrawing() { } double sinceLastViewCulling = (start - _lastViewCulling) / 1000.0; - // If the view frustum has changed, since last time, then remove nodes that are out of view if ((sinceLastViewCulling >= std::max(_lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS)) && hasViewChanged()) { _lastViewCulling = start; removeOutOfView(); double endViewCulling = usecTimestampNow(); - _lastViewCullingElapsed = (endViewCulling - start)/1000.0; + _lastViewCullingElapsed = (endViewCulling - start) / 1000.0; } if (_tree->isDirty()) { PerformanceWarning warn(_renderWarningsOn, "calling... newTreeToArrays()"); _callsToTreesToArrays++; - if (_alwaysRenderFullVBO) { _voxelsInWriteArrays = 0; // reset our VBO } @@ -173,7 +171,7 @@ void VoxelSystem::setupNewVoxelsForDrawing() { copyWrittenDataToReadArrays(); double end = usecTimestampNow(); - double elapsedmsec = (end - start)/1000.0; + double elapsedmsec = (end - start) / 1000.0; _setupNewVoxelsForDrawingLastFinished = end; _setupNewVoxelsForDrawingLastElapsed = elapsedmsec; }