From accda966d5113cc4a276be8e9d1fbaaad1170421 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 29 Apr 2013 17:38:52 -0700 Subject: [PATCH] Add LOD culling to the server protocol. - Add LOD/distance culling to VoxelTree:encodeTreeBitstreamRecursion() and VoxelTree::searchForColoredNodesRecursion() - added new levels to boundaryDistanceForRenderLevel() - added more spheres to the scene to get a better sense of LOD behavior --- interface/src/VoxelSystem.cpp | 6 +-- interface/src/VoxelSystem.h | 7 ++- interface/src/main.cpp | 1 + libraries/voxels/src/VoxelTree.cpp | 73 +++++++++++++++++++++--------- voxel-server/src/main.cpp | 33 +++++++++++++- 5 files changed, 90 insertions(+), 30 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index b018bd1f96..e9040ac48a 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -55,10 +55,6 @@ VoxelSystem::~VoxelSystem() { pthread_mutex_destroy(&bufferWriteLock); } -void VoxelSystem::setViewerAvatar(Avatar *newViewerAvatar) { - viewerAvatar = newViewerAvatar; -} - ////////////////////////////////////////////////////////////////////////////////////////// // Method: VoxelSystem::loadVoxelsFile() // Description: Loads HiFidelity encoded Voxels from a binary file. The current file @@ -180,7 +176,7 @@ void VoxelSystem::copyWrittenDataToReadArrays() { int VoxelSystem::treeToArrays(VoxelNode* currentNode, const glm::vec3& nodePosition) { int voxelsAdded = 0; float halfUnitForVoxel = powf(0.5, *currentNode->octalCode) * (0.5 * TREE_SCALE); - glm::vec3 viewerPosition = viewerAvatar->getPosition(); + glm::vec3 viewerPosition = _camera->getPosition(); //_viewerAvatar->getPosition(); // debug LOD code glm::vec3 debugNodePosition; diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index ca4825121b..f12cc7521a 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -16,6 +16,7 @@ #include #include #include "Avatar.h" +#include "Camera.h" #include "Util.h" #include "world.h" @@ -34,7 +35,8 @@ public: void render(); void setVoxelsRendered(int v) {voxelsRendered = v;}; int getVoxelsRendered() {return voxelsRendered;}; - void setViewerAvatar(Avatar *newViewerAvatar); + void setViewerAvatar(Avatar *newViewerAvatar) { _viewerAvatar = newViewerAvatar; }; + void setCamera(Camera* newCamera) { _camera = newCamera; }; void loadVoxelsFile(const char* fileName,bool wantColorRandomizer); void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer); @@ -67,7 +69,8 @@ private: static float _minDistance; int voxelsRendered; - Avatar *viewerAvatar; + Avatar* _viewerAvatar; + Camera* _camera; VoxelTree *tree; GLfloat *readVerticesArray; GLubyte *readColorsArray; diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 37c15ecbeb..fe914b2e52 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -299,6 +299,7 @@ void init(void) { voxels.init(); voxels.setViewerAvatar(&myAvatar); + voxels.setCamera(&myCamera); handControl.setScreenDimensions(WIDTH, HEIGHT); diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index d6934c4042..ecdb77a617 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -84,9 +84,27 @@ int boundaryDistanceForRenderLevel(unsigned int renderLevel) { case 7: return 12; break; - default: + case 8: + return 10; + break; + case 9: return 6; break; + case 10: + return 4.5; + break; + case 11: + return 3; + break; + case 12: + return 2.25; + break; + case 13: + return 1.5; + break; + default: + return 1; + break; } } @@ -817,10 +835,12 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe } float distance = childNode->distanceToCamera(viewFrustum); - - inViewCount = insertIntoSortedArrays((void*)childNode, distance, i, - (void**)&inViewChildren, (float*)&distancesToChildren, (int*)&positionOfChildren, - inViewCount, MAX_CHILDREN); + + if (distance < boundaryDistanceForRenderLevel(*childNode->octalCode + 1)) { + inViewCount = insertIntoSortedArrays((void*)childNode, distance, i, + (void**)&inViewChildren, (float*)&distancesToChildren, (int*)&positionOfChildren, + inViewCount, MAX_CHILDREN); + } } } @@ -920,6 +940,14 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco return bytesAtThisLevel; } + float distance = node->distanceToCamera(viewFrustum); + float boundaryDistance = boundaryDistanceForRenderLevel(*node->octalCode + 1); + + // If we're too far away for our render level, then just return + if (distance >= boundaryDistance) { + return bytesAtThisLevel; + } + // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! // although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if // we're out of view @@ -954,26 +982,28 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco for (int i = 0; i < MAX_CHILDREN; i++) { VoxelNode* childNode = node->children[i]; bool childExists = (childNode != NULL); - - bool childIsColored = (childExists && childNode->isColored()); bool childIsInView = (childExists && childNode->isInView(viewFrustum)); - bool childIsLeaf = (childExists && childNode->isLeaf()); - if (childIsInView) { - inViewCount++; + // Before we determine consider this further, let's see if it's in our LOD scope... + float distance = childNode->distanceToCamera(viewFrustum); + float boundaryDistance = boundaryDistanceForRenderLevel(*childNode->octalCode + 1); + + if (distance < boundaryDistance) { + inViewCount++; - // track children in view as existing and not a leaf, if they're a leaf, - // we don't care about recursing deeper on them, and we don't consider their - // subtree to exist - if (!childIsLeaf) { - childrenExistBits += (1 << (7 - i)); - inViewNotLeafCount++; - } + // track children in view as existing and not a leaf, if they're a leaf, + // we don't care about recursing deeper on them, and we don't consider their + // subtree to exist + if (!(childExists && childNode->isLeaf())) { + childrenExistBits += (1 << (7 - i)); + inViewNotLeafCount++; + } - // track children with actual color - if (childIsColored) { - childrenColoredBits += (1 << (7 - i)); - inViewWithColorCount++; + // track children with actual color + if (childExists && childNode->isColored()) { + childrenColoredBits += (1 << (7 - i)); + inViewWithColorCount++; + } } } } @@ -1016,7 +1046,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco // of handling things. For example, in case of child iteration, it needs to unset the child exist bit for // this child. // add our node the the list of extra nodes to output later... - bag.insert(node); return 0; } diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 319723e7e3..9eff5451a7 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -38,7 +38,7 @@ const float DEATH_STAR_RADIUS = 4.0; const float MAX_CUBE = 0.05f; const int VOXEL_SEND_INTERVAL_USECS = 100 * 1000; -const int PACKETS_PER_CLIENT_PER_INTERVAL = 5; +const int PACKETS_PER_CLIENT_PER_INTERVAL = 2; const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4; @@ -68,6 +68,16 @@ void addSphere(VoxelTree * tree,bool random, bool wantColorRandomizer) { tree->createSphere(r,xc,yc,zc,s,solid,wantColorRandomizer); } +int _nodeCount=0; +bool countVoxelsOperation(VoxelNode* node, bool down, void* extraData) { + if (down) { + if (node->isColored()){ + _nodeCount++; + } + } + return true; // keep going +} + void addSphereScene(VoxelTree * tree, bool wantColorRandomizer) { printf("adding scene of spheres...\n"); @@ -80,6 +90,8 @@ void addSphereScene(VoxelTree * tree, bool wantColorRandomizer) { tree->createSphere(0.25,0.5,0.5,0.5,(1.0/sphereBaseSize),true,wantColorRandomizer); printf("one sphere added...\n"); tree->createSphere(0.030625,0.5,0.5,(0.25-0.06125),(1.0/(sphereBaseSize*2)),true,true); + + printf("two spheres added...\n"); tree->createSphere(0.030625,(1.0-0.030625),(1.0-0.030625),(1.0-0.06125),(1.0/(sphereBaseSize*2)),true,true); printf("three spheres added...\n"); @@ -88,6 +100,25 @@ void addSphereScene(VoxelTree * tree, bool wantColorRandomizer) { tree->createSphere(0.030625,(1.0-0.030625),0.06125,(1.0-0.06125),(1.0/(sphereBaseSize*2)),true,true); printf("five spheres added...\n"); tree->createSphere(0.06125,0.125,0.125,(1.0-0.125),(1.0/(sphereBaseSize*2)),true,true); + + float radius = 0.0125f; + printf("6 spheres added...\n"); + tree->createSphere(radius,0.25,radius*5.0f,0.25,(1.0/(4096)),true,true); + printf("7 spheres added...\n"); + tree->createSphere(radius,0.125,radius*5.0f,0.25,(1.0/(4096)),true,true); + printf("8 spheres added...\n"); + tree->createSphere(radius,0.075,radius*5.0f,0.25,(1.0/(4096)),true,true); + printf("9 spheres added...\n"); + tree->createSphere(radius,0.05,radius*5.0f,0.25,(1.0/(4096)),true,true); + printf("10 spheres added...\n"); + tree->createSphere(radius,0.025,radius*5.0f,0.25,(1.0/(4096)),true,true); + printf("11 spheres added...\n"); + + _nodeCount=0; + tree->recurseTreeWithOperation(countVoxelsOperation); + printf("Nodes after adding scene %d nodes\n",_nodeCount); + + printf("DONE adding scene of spheres...\n"); }