From 9c601cedd06bc516ac6c100efdf980decc99cb55 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 19 Apr 2013 18:05:38 -0700 Subject: [PATCH 01/17] Adding support for false color to voxel nodes, also added AABox to get voxel bounding box --- libraries/voxels/src/VoxelNode.cpp | 88 +++++++++++++++++++++++------- libraries/voxels/src/VoxelNode.h | 21 ++++++- 2 files changed, 87 insertions(+), 22 deletions(-) diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 5f36ad9e59..7cae90f744 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -6,17 +6,21 @@ // // +#include #include #include "SharedUtil.h" //#include "voxels_Log.h" #include "VoxelNode.h" #include "OctalCode.h" +#include "AABox.h" // using voxels_lib::printLog; VoxelNode::VoxelNode() { octalCode = NULL; + _falseColored = false; // assume true color + // default pointers to child nodes to NULL for (int i = 0; i < 8; i++) { children[i] = NULL; @@ -28,10 +32,21 @@ VoxelNode::~VoxelNode() { // delete all of this node's children for (int i = 0; i < 8; i++) { - delete children[i]; + if (children[i]) { + delete children[i]; + } } } +void VoxelNode::getAABox(AABox& box) const { + // copy corner into box + copyFirstVertexForCode(octalCode,(float*)&box.corner); + + // this tells you the "size" of the voxel + float voxelScale = 1 / powf(2, *octalCode); + box.x = box.y = box.z = voxelScale; +} + void VoxelNode::addChildAtIndex(int childIndex) { children[childIndex] = new VoxelNode(); @@ -43,28 +58,54 @@ void VoxelNode::addChildAtIndex(int childIndex) { void VoxelNode::setColorFromAverageOfChildren() { int colorArray[4] = {0,0,0,0}; for (int i = 0; i < 8; i++) { - if (children[i] != NULL && children[i]->color[3] == 1) { + if (children[i] != NULL && children[i]->isColored()) { for (int j = 0; j < 3; j++) { - colorArray[j] += children[i]->color[j]; + colorArray[j] += children[i]->getTrueColor()[j]; // color averaging should always be based on true colors } colorArray[3]++; } } + nodeColor newColor = { 0, 0, 0, 0}; if (colorArray[3] > 4) { // we need at least 4 colored children to have an average color value // or if we have none we generate random values for (int c = 0; c < 3; c++) { // set the average color value - color[c] = colorArray[c] / colorArray[3]; + newColor[c] = colorArray[c] / colorArray[3]; } // set the alpha to 1 to indicate that this isn't transparent - color[3] = 1; - } else { - // some children, but not enough - // set this node's alpha to 0 - color[3] = 0; - } + newColor[3] = 1; + } + // actually set our color, note, if we didn't have enough children + // this will be the default value all zeros, and therefore be marked as + // transparent with a 4th element of 0 + setColor(newColor); +} + +void VoxelNode::setFalseColor(colorPart red, colorPart green, colorPart blue) { + _falseColored=true; + _currentColor[0] = red; + _currentColor[1] = green; + _currentColor[2] = blue; + _currentColor[3] = 1; // XXXBHG - False colors are always considered set +} + +void VoxelNode::setFalseColored(bool isFalseColored) { + // if we were false colored, and are no longer false colored, then swap back + if (_falseColored && !isFalseColored) { + memcpy(&_currentColor,&_trueColor,sizeof(nodeColor)); + } + _falseColored = isFalseColored; +}; + + +void VoxelNode::setColor(const nodeColor& color) { + //printf("VoxelNode::setColor() isFalseColored=%s\n",_falseColored ? "Yes" : "No"); + memcpy(&_trueColor,&color,sizeof(nodeColor)); + if (!_falseColored) { + memcpy(&_currentColor,&color,sizeof(nodeColor)); + } } // will detect if children are leaves AND the same color @@ -77,16 +118,17 @@ bool VoxelNode::collapseIdenticalLeaves() { int red,green,blue; for (int i = 0; i < 8; i++) { // if no child, or child doesn't have a color - if (children[i] == NULL || children[i]->color[3] != 1) { + if (children[i] == NULL || !children[i]->isColored()) { allChildrenMatch=false; //printLog("SADNESS child missing or not colored! i=%d\n",i); break; } else { if (i==0) { - red = children[i]->color[0]; - green = children[i]->color[1]; - blue = children[i]->color[2]; - } else if (red != children[i]->color[0] || green != children[i]->color[1] || blue != children[i]->color[2]) { + red = children[i]->getColor()[0]; + green = children[i]->getColor()[1]; + blue = children[i]->getColor()[2]; + } else if (red != children[i]->getColor()[0] || + green != children[i]->getColor()[1] || blue != children[i]->getColor()[2]) { allChildrenMatch=false; break; } @@ -100,18 +142,22 @@ bool VoxelNode::collapseIdenticalLeaves() { delete children[i]; // delete all the child nodes children[i]=NULL; // set it to NULL } - color[0]=red; - color[1]=green; - color[2]=blue; - color[3]=1; // color is set + nodeColor collapsedColor; + collapsedColor[0]=red; + collapsedColor[1]=green; + collapsedColor[2]=blue; + collapsedColor[3]=1; // color is set + setColor(collapsedColor); } return allChildrenMatch; } void VoxelNode::setRandomColor(int minimumBrightness) { + nodeColor newColor; for (int c = 0; c < 3; c++) { - color[c] = randomColorValue(minimumBrightness); + newColor[c] = randomColorValue(minimumBrightness); } - color[3] = 1; + newColor[3] = 1; + setColor(newColor); } diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index b82c07a09d..42b4331440 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -9,7 +9,16 @@ #ifndef __hifi__VoxelNode__ #define __hifi__VoxelNode__ +#include "AABox.h" + +typedef unsigned char colorPart; +typedef unsigned char nodeColor[4]; + class VoxelNode { +private: + nodeColor _trueColor; + nodeColor _currentColor; + bool _falseColored; public: VoxelNode(); ~VoxelNode(); @@ -20,8 +29,18 @@ public: bool collapseIdenticalLeaves(); unsigned char *octalCode; - unsigned char color[4]; VoxelNode *children[8]; + + bool isColored() const { return (_trueColor[3]==1); }; + void setFalseColor(colorPart red, colorPart green, colorPart blue); + void setFalseColored(bool isFalseColored); + bool getFalseColored() { return _falseColored; }; + + void setColor(const nodeColor& color); + const nodeColor& getTrueColor() const { return _trueColor; }; + const nodeColor& getColor() const { return _currentColor; }; + + void getAABox(AABox& box) const; }; #endif /* defined(__hifi__VoxelNode__) */ From b8692d8f46bbecf99fbddaec957784d00cc1b05c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 19 Apr 2013 18:07:03 -0700 Subject: [PATCH 02/17] add glm to voxel-server build scripts --- voxel-server/CMakeLists.txt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/voxel-server/CMakeLists.txt b/voxel-server/CMakeLists.txt index 5f9ff87fd7..99b72be9cb 100644 --- a/voxel-server/CMakeLists.txt +++ b/voxel-server/CMakeLists.txt @@ -5,6 +5,14 @@ set(TARGET_NAME voxel-server) set(ROOT_DIR ..) set(MACRO_DIR ${ROOT_DIR}/cmake/macros) +# setup for find modules +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") +set(GLM_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external) + +# set up the external glm library +include(${MACRO_DIR}/IncludeGLM.cmake) +include_glm(${TARGET_NAME} ${ROOT_DIR}) + include(${MACRO_DIR}/SetupHifiProject.cmake) setup_hifi_project(${TARGET_NAME}) @@ -14,4 +22,7 @@ include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) # link in the hifi voxels library -link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file +link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR}) + +# find required libraries +find_package(GLM REQUIRED) From 4085c94aa71fa257612f6d80d0d8bc3eedc7f184 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 19 Apr 2013 18:11:28 -0700 Subject: [PATCH 03/17] made a version of firstVertexForCode() that doesn't allocate memory, for improved performance and use - created new copyFirstVertexForCode(code,output) which copies to the output buffer - converted firstVertexForCode() to behave same way as before, but use copy version --- libraries/shared/src/OctalCode.cpp | 14 +++++++++----- libraries/shared/src/OctalCode.h | 5 +++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 2a687f1cd4..898eaed377 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -104,9 +104,8 @@ unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber return newCode; } -float * firstVertexForCode(unsigned char * octalCode) { - float * firstVertex = new float[3]; - memset(firstVertex, 0, 3 * sizeof(float)); +void copyFirstVertexForCode(unsigned char * octalCode, float* output) { + memset(output, 0, 3 * sizeof(float)); float currentScale = 0.5; @@ -114,11 +113,16 @@ float * firstVertexForCode(unsigned char * octalCode) { int sectionIndex = sectionValue(octalCode + 1 + (3 * i / 8), (3 * i) % 8); for (int j = 0; j < 3; j++) { - firstVertex[j] += currentScale * (int)oneAtBit(sectionIndex, 5 + j); + output[j] += currentScale * (int)oneAtBit(sectionIndex, 5 + j); } currentScale *= 0.5; } - +} + +float * firstVertexForCode(unsigned char * octalCode) { + float * firstVertex = new float[3]; + copyFirstVertexForCode(octalCode, firstVertex); return firstVertex; } + diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index d5367fbddf..7569e99868 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -16,6 +16,11 @@ int bytesRequiredForCodeLength(unsigned char threeBitCodes); bool isDirectParentOfChild(unsigned char *parentOctalCode, unsigned char * childOctalCode); int branchIndexWithDescendant(unsigned char * ancestorOctalCode, unsigned char * descendantOctalCode); unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber); + + +// Note: copyFirstVertexForCode() is preferred because it doesn't allocate memory for the return +// but other than that these do the same thing. float * firstVertexForCode(unsigned char * octalCode); +void copyFirstVertexForCode(unsigned char * octalCode, float* output); #endif /* defined(__hifi__OctalCode__) */ From 3ec920d1b81271d7138ae88b59a722956f22f473 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 19 Apr 2013 18:14:10 -0700 Subject: [PATCH 04/17] added scale() method to AABox --- libraries/voxels/src/AABox.cpp | 11 ++++++++++- libraries/voxels/src/AABox.h | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/libraries/voxels/src/AABox.cpp b/libraries/voxels/src/AABox.cpp index bc36bca7a9..4c2f18f863 100755 --- a/libraries/voxels/src/AABox.cpp +++ b/libraries/voxels/src/AABox.cpp @@ -19,8 +19,17 @@ AABox::AABox(void) { } -AABox::~AABox() {} +AABox::~AABox() { + // nothing to do +} + +void AABox::scale(float scale) { + corner = corner*scale; + x *= scale; + y *= scale; + z *= scale; +} void AABox::setBox(const glm::vec3& corner, float x, float y, float z) { diff --git a/libraries/voxels/src/AABox.h b/libraries/voxels/src/AABox.h index abc20f38d5..a00cda24c8 100755 --- a/libraries/voxels/src/AABox.h +++ b/libraries/voxels/src/AABox.h @@ -27,6 +27,8 @@ public: // for use in frustum computations glm::vec3 getVertexP(const glm::vec3& normal); glm::vec3 getVertexN(const glm::vec3& normal); + + void scale(float scale); }; From 2752918573e3a3dbf872d58ffc7d9525f336c176 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 19 Apr 2013 18:15:50 -0700 Subject: [PATCH 05/17] Fixed LOD bug, added recurseTree helper, change tree to use safe/true/false colors - Fixed LOD bug in server side sending - added recurseTreeWithOperation() helper - changed tree to use new VoxelNode color related API --- libraries/voxels/src/VoxelTree.cpp | 61 ++++++++++++++++++++++++------ libraries/voxels/src/VoxelTree.h | 7 ++++ 2 files changed, 56 insertions(+), 12 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 173fe1a38b..dc0913c513 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -69,6 +69,27 @@ VoxelTree::~VoxelTree() { } } +// Recurses voxel tree calling the RecurseVoxelTreeOperation function for each node. +// stops recursion if operation function returns false. +void VoxelTree::recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData) { + recurseNodeWithOperation(rootNode, operation,extraData); +} + +// Recurses voxel node with an operation function +void VoxelTree::recurseNodeWithOperation(VoxelNode* node,RecurseVoxelTreeOperation operation, void* extraData) { + // call the operation function going "down" first, stop deeper recursion if function returns false + if (operation(node,true,extraData)) { + for (int i = 0; i < sizeof(node->children)/sizeof(node->children[0]); i++) { + VoxelNode* child = node->children[i]; + if (child) { + recurseNodeWithOperation(child,operation,extraData); + } + } + // call operation on way back up + operation(node,false,extraData); + } +} + VoxelNode * VoxelTree::nodeForOctalCode(VoxelNode *ancestorNode, unsigned char * needleCode, VoxelNode** parentOfFoundNode) { // find the appropriate branch index based on this ancestorNode if (*needleCode > 0) { @@ -130,8 +151,10 @@ int VoxelTree::readNodeData(VoxelNode *destinationNode, } // pull the color for this child - memcpy(destinationNode->children[i]->color, nodeData + bytesRead, 3); - destinationNode->children[i]->color[3] = 1; + nodeColor newColor; + memcpy(newColor, nodeData + bytesRead, 3); + newColor[3] = 1; + destinationNode->children[i]->setColor(newColor); this->voxelsColored++; this->voxelsColoredStats.recordSample(this->voxelsColored); @@ -236,8 +259,11 @@ void VoxelTree::readCodeColorBufferToTree(unsigned char *codeColorBuffer) { // give this node its color int octalCodeBytes = bytesRequiredForCodeLength(*codeColorBuffer); - memcpy(lastCreatedNode->color, codeColorBuffer + octalCodeBytes, 3); - lastCreatedNode->color[3] = 1; + + nodeColor newColor; + memcpy(newColor, codeColorBuffer + octalCodeBytes, 3); + newColor[3] = 1; + lastCreatedNode->setColor(newColor); } unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, @@ -276,7 +302,7 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, // coords of the voxel space. This flip flop causes LOD behavior to be extremely odd. This is my temporary hack // to fix this behavior. To disable this swap, set swapXandZ to false. // XXXBHG - 2013/04/11 - adding a note to my branch, I think this code is now broken. - bool swapXandZ=true; + bool swapXandZ=false; float agentX = swapXandZ ? agentPosition[2] : agentPosition[0]; float agentZ = swapXandZ ? agentPosition[0] : agentPosition[2]; @@ -320,10 +346,10 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, // check if the child exists and is not transparent if (currentVoxelNode->children[i] != NULL - && currentVoxelNode->children[i]->color[3] != 0) { + && currentVoxelNode->children[i]->isColored()) { // copy in the childs color to bitstreamBuffer - memcpy(colorPointer, currentVoxelNode->children[i]->color, 3); + memcpy(colorPointer, currentVoxelNode->children[i]->getTrueColor(), 3); colorPointer += 3; // set the colorMask by bitshifting the value of childExists @@ -361,9 +387,19 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, currentMarkerNode->children[i] = new MarkerNode(); } - // calculate the child's position based on the parent position float childNodePosition[3]; - + copyFirstVertexForCode(currentVoxelNode->children[i]->octalCode,(float*)&childNodePosition); + childNodePosition[0] *= TREE_SCALE; // scale it up + childNodePosition[1] *= TREE_SCALE; // scale it up + childNodePosition[2] *= TREE_SCALE; // scale it up + + /**** disabled ***************************************************************************************** + // Note: Stephen, I intentionally left this in so you would talk to me about it. Here's the deal, this + // code doesn't seem to work correctly. It returns X and Z flipped and the values are negative. Since + // we use the firstVertexForCode() function in VoxelSystem to calculate the child vertex and that DOES + // work, I've decided to use that function to calculate our position for LOD handling. + // + // calculate the child's position based on the parent position for (int j = 0; j < 3; j++) { childNodePosition[j] = thisNodePosition[j]; @@ -373,6 +409,7 @@ unsigned char * VoxelTree::loadBitstreamBuffer(unsigned char *& bitstreamBuffer, childNodePosition[j] -= (powf(0.5, *currentVoxelNode->children[i]->octalCode) * TREE_SCALE); } } + **** disabled *****************************************************************************************/ // ask the child to load the bitstream buffer with their data childStopOctalCode = loadBitstreamBuffer(bitstreamBuffer, @@ -440,7 +477,7 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { // create the color mask for (int i = 0; i < 8; i++) { - if (startNode->children[i] != NULL && startNode->children[i]->color[3] != 0) { + if (startNode->children[i] != NULL && startNode->children[i]->isColored()) { colorMask += (1 << (7 - i)); } } @@ -449,9 +486,9 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { // output the colors we have for (int j = 0; j < 8; j++) { - if (startNode->children[j] != NULL && startNode->children[j]->color[3] != 0) { + if (startNode->children[j] != NULL && startNode->children[j]->isColored()) { for (int c = 0; c < 3; c++) { - outputBits(startNode->children[j]->color[c]); + outputBits(startNode->children[j]->getTrueColor()[c]); } } } diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 618a3710ae..79c7b75fa4 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -18,6 +18,9 @@ const int MAX_VOXEL_PACKET_SIZE = 1492; const int MAX_TREE_SLICE_BYTES = 26; const int TREE_SCALE = 10; +// Callback function, for recuseTreeWithOperation +typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, bool down, void* extraData); + class VoxelTree { public: long voxelsCreated; @@ -51,7 +54,11 @@ public: void loadVoxelsFile(const char* fileName, bool wantColorRandomizer); void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer); + + void recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData=NULL); + private: + void recurseNodeWithOperation(VoxelNode* node,RecurseVoxelTreeOperation operation, void* extraData); VoxelNode * nodeForOctalCode(VoxelNode *ancestorNode, unsigned char * needleCode, VoxelNode** parentOfFoundNode); VoxelNode * createMissingNode(VoxelNode *lastParentNode, unsigned char *deepestCodeToCreate); int readNodeData(VoxelNode *destinationNode, unsigned char * nodeData, int bufferSizeBytes); From 8ad51b6c0833ca2112f65162c6c086ccc6760901 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 19 Apr 2013 19:56:03 -0700 Subject: [PATCH 06/17] got rid of a bunch of this-> at Stephen's request. Added debuging for box in view --- libraries/voxels/src/ViewFrustum.cpp | 127 ++++++++++++++++----------- 1 file changed, 76 insertions(+), 51 deletions(-) diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index 867b47922f..704289d977 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -53,92 +53,92 @@ void ViewFrustum::calculate() { glm::vec3 front = _direction; // Calculating field of view. - float fovInRadians = this->_fieldOfView * PI_OVER_180; + float fovInRadians = _fieldOfView * PI_OVER_180; float twoTimesTanHalfFOV = 2.0f * tan(fovInRadians/2.0f); // Do we need this? //tang = (float)tan(ANG2RAD * angle * 0.5) ; - float nearClip = this->_nearClip; - float farClip = this->_farClip; + float nearClip = _nearClip; + float farClip = _farClip; - this->_nearHeight = (twoTimesTanHalfFOV * nearClip); - this->_nearWidth = this->_nearHeight * this->_aspectRatio; - this->_farHeight = (twoTimesTanHalfFOV * farClip); - this->_farWidth = this->_farHeight * this->_aspectRatio; + _nearHeight = (twoTimesTanHalfFOV * nearClip); + _nearWidth = _nearHeight * _aspectRatio; + _farHeight = (twoTimesTanHalfFOV * farClip); + _farWidth = _farHeight * _aspectRatio; - float farHalfHeight = (this->_farHeight * 0.5f); - float farHalfWidth = (this->_farWidth * 0.5f); - this->_farCenter = this->_position+front * farClip; - this->_farTopLeft = this->_farCenter + (this->_up * farHalfHeight) - (this->_right * farHalfWidth); - this->_farTopRight = this->_farCenter + (this->_up * farHalfHeight) + (this->_right * farHalfWidth); - this->_farBottomLeft = this->_farCenter - (this->_up * farHalfHeight) - (this->_right * farHalfWidth); - this->_farBottomRight = this->_farCenter - (this->_up * farHalfHeight) + (this->_right * farHalfWidth); + float farHalfHeight = (_farHeight * 0.5f); + float farHalfWidth = (_farWidth * 0.5f); + _farCenter = _position+front * farClip; + _farTopLeft = _farCenter + (_up * farHalfHeight) - (_right * farHalfWidth); + _farTopRight = _farCenter + (_up * farHalfHeight) + (_right * farHalfWidth); + _farBottomLeft = _farCenter - (_up * farHalfHeight) - (_right * farHalfWidth); + _farBottomRight = _farCenter - (_up * farHalfHeight) + (_right * farHalfWidth); - float nearHalfHeight = (this->_nearHeight * 0.5f); - float nearHalfWidth = (this->_nearWidth * 0.5f); - this->_nearCenter = this->_position+front * nearClip; - this->_nearTopLeft = this->_nearCenter + (this->_up * nearHalfHeight) - (this->_right * nearHalfWidth); - this->_nearTopRight = this->_nearCenter + (this->_up * nearHalfHeight) + (this->_right * nearHalfWidth); - this->_nearBottomLeft = this->_nearCenter - (this->_up * nearHalfHeight) - (this->_right * nearHalfWidth); - this->_nearBottomRight = this->_nearCenter - (this->_up * nearHalfHeight) + (this->_right * nearHalfWidth); + float nearHalfHeight = (_nearHeight * 0.5f); + float nearHalfWidth = (_nearWidth * 0.5f); + _nearCenter = _position+front * nearClip; + _nearTopLeft = _nearCenter + (_up * nearHalfHeight) - (_right * nearHalfWidth); + _nearTopRight = _nearCenter + (_up * nearHalfHeight) + (_right * nearHalfWidth); + _nearBottomLeft = _nearCenter - (_up * nearHalfHeight) - (_right * nearHalfWidth); + _nearBottomRight = _nearCenter - (_up * nearHalfHeight) + (_right * nearHalfWidth); // compute the six planes // the function set3Points assumes that the points // are given in counter clockwise order - this->_planes[TOPP].set3Points(this->_nearTopRight,this->_nearTopLeft,this->_farTopLeft); - this->_planes[BOTTOMP].set3Points(this->_nearBottomLeft,this->_nearBottomRight,this->_farBottomRight); - this->_planes[LEFTP].set3Points(this->_nearTopLeft,this->_nearBottomLeft,this->_farBottomLeft); - this->_planes[RIGHTP].set3Points(this->_nearBottomRight,this->_nearTopRight,this->_farBottomRight); - this->_planes[NEARP].set3Points(this->_nearTopLeft,this->_nearTopRight,this->_nearBottomRight); - this->_planes[FARP].set3Points(this->_farTopRight,this->_farTopLeft,this->_farBottomLeft); + _planes[TOPP].set3Points(_nearTopRight,_nearTopLeft,_farTopLeft); + _planes[BOTTOMP].set3Points(_nearBottomLeft,_nearBottomRight,_farBottomRight); + _planes[LEFTP].set3Points(_nearTopLeft,_nearBottomLeft,_farBottomLeft); + _planes[RIGHTP].set3Points(_nearBottomRight,_nearTopRight,_farBottomRight); + _planes[NEARP].set3Points(_nearTopLeft,_nearTopRight,_nearBottomRight); + _planes[FARP].set3Points(_farTopRight,_farTopLeft,_farBottomLeft); } void ViewFrustum::dump() { - printLog("position.x=%f, position.y=%f, position.z=%f\n", this->_position.x, this->_position.y, this->_position.z); - printLog("direction.x=%f, direction.y=%f, direction.z=%f\n", this->_direction.x, this->_direction.y, this->_direction.z); - printLog("up.x=%f, up.y=%f, up.z=%f\n", this->_up.x, this->_up.y, this->_up.z); - printLog("right.x=%f, right.y=%f, right.z=%f\n", this->_right.x, this->_right.y, this->_right.z); + printLog("position.x=%f, position.y=%f, position.z=%f\n", _position.x, _position.y, _position.z); + printLog("direction.x=%f, direction.y=%f, direction.z=%f\n", _direction.x, _direction.y, _direction.z); + printLog("up.x=%f, up.y=%f, up.z=%f\n", _up.x, _up.y, _up.z); + printLog("right.x=%f, right.y=%f, right.z=%f\n", _right.x, _right.y, _right.z); - printLog("farDist=%f\n", this->_farClip); - printLog("farHeight=%f\n", this->_farHeight); - printLog("farWidth=%f\n", this->_farWidth); + printLog("farDist=%f\n", _farClip); + printLog("farHeight=%f\n", _farHeight); + printLog("farWidth=%f\n", _farWidth); - printLog("nearDist=%f\n", this->_nearClip); - printLog("nearHeight=%f\n", this->_nearHeight); - printLog("nearWidth=%f\n", this->_nearWidth); + printLog("nearDist=%f\n", _nearClip); + printLog("nearHeight=%f\n", _nearHeight); + printLog("nearWidth=%f\n", _nearWidth); printLog("farCenter.x=%f, farCenter.y=%f, farCenter.z=%f\n", - this->_farCenter.x, this->_farCenter.y, this->_farCenter.z); + _farCenter.x, _farCenter.y, _farCenter.z); printLog("farTopLeft.x=%f, farTopLeft.y=%f, farTopLeft.z=%f\n", - this->_farTopLeft.x, this->_farTopLeft.y, this->_farTopLeft.z); + _farTopLeft.x, _farTopLeft.y, _farTopLeft.z); printLog("farTopRight.x=%f, farTopRight.y=%f, farTopRight.z=%f\n", - this->_farTopRight.x, this->_farTopRight.y, this->_farTopRight.z); + _farTopRight.x, _farTopRight.y, _farTopRight.z); printLog("farBottomLeft.x=%f, farBottomLeft.y=%f, farBottomLeft.z=%f\n", - this->_farBottomLeft.x, this->_farBottomLeft.y, this->_farBottomLeft.z); + _farBottomLeft.x, _farBottomLeft.y, _farBottomLeft.z); printLog("farBottomRight.x=%f, farBottomRight.y=%f, farBottomRight.z=%f\n", - this->_farBottomRight.x, this->_farBottomRight.y, this->_farBottomRight.z); + _farBottomRight.x, _farBottomRight.y, _farBottomRight.z); printLog("nearCenter.x=%f, nearCenter.y=%f, nearCenter.z=%f\n", - this->_nearCenter.x, this->_nearCenter.y, this->_nearCenter.z); + _nearCenter.x, _nearCenter.y, _nearCenter.z); printLog("nearTopLeft.x=%f, nearTopLeft.y=%f, nearTopLeft.z=%f\n", - this->_nearTopLeft.x, this->_nearTopLeft.y, this->_nearTopLeft.z); + _nearTopLeft.x, _nearTopLeft.y, _nearTopLeft.z); printLog("nearTopRight.x=%f, nearTopRight.y=%f, nearTopRight.z=%f\n", - this->_nearTopRight.x, this->_nearTopRight.y, this->_nearTopRight.z); + _nearTopRight.x, _nearTopRight.y, _nearTopRight.z); printLog("nearBottomLeft.x=%f, nearBottomLeft.y=%f, nearBottomLeft.z=%f\n", - this->_nearBottomLeft.x, this->_nearBottomLeft.y, this->_nearBottomLeft.z); + _nearBottomLeft.x, _nearBottomLeft.y, _nearBottomLeft.z); printLog("nearBottomRight.x=%f, nearBottomRight.y=%f, nearBottomRight.z=%f\n", - this->_nearBottomRight.x, this->_nearBottomRight.y, this->_nearBottomRight.z); + _nearBottomRight.x, _nearBottomRight.y, _nearBottomRight.z); } int ViewFrustum::pointInFrustum(glm::vec3 &p) { int result = INSIDE; for(int i=0; i < 6; i++) { - if (this->_planes[i].distance(p) < 0) + if (_planes[i].distance(p) < 0) return OUTSIDE; } return(result); @@ -148,7 +148,7 @@ int ViewFrustum::sphereInFrustum(glm::vec3 ¢er, float radius) { int result = INSIDE; float distance; for(int i=0; i < 6; i++) { - distance = this->_planes[i].distance(center); + distance = _planes[i].distance(center); if (distance < -radius) return OUTSIDE; else if (distance < radius) @@ -159,12 +159,37 @@ int ViewFrustum::sphereInFrustum(glm::vec3 ¢er, float radius) { int ViewFrustum::boxInFrustum(AABox &b) { + +printf("ViewFrustum::boxInFrustum() box.corner=%f,%f,%f x=%f\n",b.corner.x,b.corner.y,b.corner.z,b.x); int result = INSIDE; for(int i=0; i < 6; i++) { - if (this->_planes[i].distance(b.getVertexP(this->_planes[i].normal)) < 0) + + printf("plane[%d] -- point(%f,%f,%f) normal(%f,%f,%f) d=%f \n",i, + _planes[i].point.x, _planes[i].point.y, _planes[i].point.z, + _planes[i].normal.x, _planes[i].normal.y, _planes[i].normal.z, + _planes[i].d + ); + + glm::vec3 normal = _planes[i].normal; + glm::vec3 boxVertexP = b.getVertexP(normal); + float planeToBoxVertexPDistance = _planes[i].distance(boxVertexP); + + glm::vec3 boxVertexN = b.getVertexN(normal); + float planeToBoxVertexNDistance = _planes[i].distance(boxVertexN); + + + + printf("plane[%d] normal=(%f,%f,%f) bVertexP=(%f,%f,%f) planeToBoxVertexPDistance=%f boxVertexN=(%f,%f,%f) planeToBoxVertexNDistance=%f\n",i, + normal.x,normal.y,normal.z, + boxVertexP.x,boxVertexP.y,boxVertexP.z,planeToBoxVertexPDistance, + boxVertexN.x,boxVertexN.y,boxVertexN.z,planeToBoxVertexNDistance + ); + + if (planeToBoxVertexPDistance < 0) { return OUTSIDE; - else if (this->_planes[i].distance(b.getVertexN(this->_planes[i].normal)) < 0) + } else if (planeToBoxVertexNDistance < 0) { result = INTERSECT; + } } return(result); } From 7dbc6bc986eb99b7a502c6237ca075b1b5fdacef Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 19 Apr 2013 19:56:53 -0700 Subject: [PATCH 07/17] Added inline getters for camera attributes --- libraries/voxels/src/ViewFrustum.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/voxels/src/ViewFrustum.h b/libraries/voxels/src/ViewFrustum.h index 15bdb484fb..9b496544c5 100644 --- a/libraries/voxels/src/ViewFrustum.h +++ b/libraries/voxels/src/ViewFrustum.h @@ -54,6 +54,12 @@ public: void setOrientation (const glm::vec3& d, const glm::vec3& u, const glm::vec3& r ) { _direction = d; _up = u; _right = r; } + // getters for camera attributes + const glm::vec3& getPosition() const { return _position; }; + const glm::vec3& getDirection() const { return _direction; }; + const glm::vec3& getUp() const { return _up; }; + const glm::vec3& getRight() const { return _right; }; + // setters for lens attributes void setFieldOfView ( float f ) { _fieldOfView = f; } void setAspectRatio ( float a ) { _aspectRatio = a; } From 75a79a09ed3a95db066d430fb84ba63efc218b8b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 19 Apr 2013 19:58:37 -0700 Subject: [PATCH 08/17] fixed LOD bug, added support for false colors - fixed LOD bug related to mismatch with getting node position - changed VoxelSystem to honor new VoxelNode color support for false color - added some implementations of tree recursion that do things like false color the tree for distance, randomly, or resetting to true color, or stomping on the local version of the true color to debug packet sending --- interface/src/VoxelSystem.cpp | 334 ++++++++++++++++++++++++++++++---- interface/src/VoxelSystem.h | 23 ++- 2 files changed, 316 insertions(+), 41 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 412c0aac75..5b388d351c 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -161,9 +161,8 @@ void VoxelSystem::setupNewVoxelsForDrawing() { writeVerticesEndPointer = writeVerticesArray; // call recursive function to populate in memory arrays // it will return the number of voxels added - float treeRoot[3] = {0,0,0}; + glm::vec3 treeRoot = glm::vec3(0,0,0); voxelsRendered = treeToArrays(tree->rootNode, treeRoot); - // copy the newly written data to the arrays designated for reading copyWrittenDataToReadArrays(); } @@ -176,42 +175,35 @@ void VoxelSystem::copyWrittenDataToReadArrays() { // copy the vertices and colors memcpy(readVerticesArray, writeVerticesArray, (endOfCurrentVerticesData - writeVerticesArray) * sizeof(GLfloat)); memcpy(readColorsArray, writeColorsArray, (endOfCurrentVerticesData - writeVerticesArray) * sizeof(GLubyte)); - // set the read vertices end pointer to the correct spot so the GPU knows how much to pull readVerticesEndPointer = readVerticesArray + (endOfCurrentVerticesData - writeVerticesArray); pthread_mutex_unlock(&bufferWriteLock); } -int VoxelSystem::treeToArrays(VoxelNode *currentNode, float nodePosition[3]) { +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 = viewerHead->getBodyPosition(); - // XXXBHG - Note: It appears as if the X and Z coordinates of Head or Agent are flip-flopped relative to the - // coords of the voxel space. This flip flop causes LOD behavior to be extremely odd. This is my temporary hack - // to fix this behavior. To disable this swap, set swapXandZ to false. - bool swapXandZ=true; - float viewerX = swapXandZ ? viewerPosition[2] : viewerPosition[0]; - float viewerZ = swapXandZ ? viewerPosition[0] : viewerPosition[2]; + // debug LOD code + glm::vec3 debugNodePosition; + copyFirstVertexForCode(currentNode->octalCode,(float*)&debugNodePosition); - // debugging code. - //printLog("treeToArrays() halfUnitForVoxel=%f\n",halfUnitForVoxel); - //printLog("treeToArrays() viewerPosition {x,y,z or [0],[1],[2]} ={%f,%f,%f}\n", - // viewerPosition[0],viewerPosition[1],viewerPosition[2]); - //printLog("treeToArrays() nodePosition {x,y,z or [0],[1],[2]} = {%f,%f,%f}\n", - // nodePosition[0],nodePosition[1],nodePosition[2]); - //float* vertices = firstVertexForCode(currentNode->octalCode); - //printLog("treeToArrays() firstVerticesForCode(currentNode->octalCode)={x,y,z or [0],[1],[2]} = {%f,%f,%f}\n", - // vertices[0],vertices[1],vertices[2]); - //delete []vertices; - - float distanceToVoxelCenter = sqrtf(powf(viewerX - nodePosition[0] - halfUnitForVoxel, 2) + - powf(viewerPosition[1] - nodePosition[1] - halfUnitForVoxel, 2) + - powf(viewerZ - nodePosition[2] - halfUnitForVoxel, 2)); + //printf("-----------------\n"); + //printf("halfUnitForVoxel=%f\n",halfUnitForVoxel); + //printf("viewer.x=%f y=%f z=%f \n", viewerPosition.x, viewerPosition.y, viewerPosition.z); + //printf("node.x=%f y=%f z=%f \n", nodePosition[0], nodePosition[1], nodePosition[2]); + //printf("debugNodePosition.x=%f y=%f z=%f \n", debugNodePosition[0], debugNodePosition[1], debugNodePosition[2]); - int boundaryPosition = boundaryDistanceForRenderLevel(*currentNode->octalCode + 1); - //printLog("treeToArrays() distanceToVoxelCenter=%f boundaryPosition=%d\n",distanceToVoxelCenter,boundaryPosition); + float distanceToVoxelCenter = sqrtf(powf(viewerPosition.x - nodePosition[0] - halfUnitForVoxel, 2) + + powf(viewerPosition.y - nodePosition[1] - halfUnitForVoxel, 2) + + powf(viewerPosition.z - nodePosition[2] - halfUnitForVoxel, 2)); + + int renderLevel = *currentNode->octalCode + 1; + int boundaryPosition = boundaryDistanceForRenderLevel(renderLevel); + //printLog("treeToArrays() renderLevel=%d distanceToVoxelCenter=%f boundaryPosition=%d\n", + // renderLevel,distanceToVoxelCenter,boundaryPosition); bool alwaysDraw = false; // XXXBHG - temporary debug code. Flip this to true to disable LOD blurring @@ -220,43 +212,46 @@ int VoxelSystem::treeToArrays(VoxelNode *currentNode, float nodePosition[3]) { // check if there is a child here if (currentNode->children[i] != NULL) { - // calculate the child's position based on the parent position - float childNodePosition[3]; + glm::vec3 childNodePosition; + copyFirstVertexForCode(currentNode->children[i]->octalCode,(float*)&childNodePosition); + childNodePosition *= (float)TREE_SCALE; // scale it up + /**** disabled ************************************************************************************************ + // Note: Stephen, I intentionally left this in so you would talk to me about it. Here's the deal, this code + // doesn't seem to work correctly. It returns X and Z flipped and the values are negative. Since we use the + // firstVertexForCode() function below to calculate the child vertex and that DOES work, I've decided to use + // that function to calculate our position for LOD handling. + // + // calculate the child's position based on the parent position for (int j = 0; j < 3; j++) { childNodePosition[j] = nodePosition[j]; - if (oneAtBit(branchIndexWithDescendant(currentNode->octalCode, - currentNode->children[i]->octalCode), - (7 - j))) { + if (oneAtBit(branchIndexWithDescendant(currentNode->octalCode,currentNode->children[i]->octalCode),(7 - j))) { childNodePosition[j] -= (powf(0.5, *currentNode->children[i]->octalCode) * TREE_SCALE); } } + **** disabled ************************************************************************************************/ voxelsAdded += treeToArrays(currentNode->children[i], childNodePosition); } } } - - - + // if we didn't get any voxels added then we're a leaf // add our vertex and color information to the interleaved array - if (voxelsAdded == 0 && currentNode->color[3] == 1) { - float * startVertex = firstVertexForCode(currentNode->octalCode); + if (voxelsAdded == 0 && currentNode->isColored()) { + float startVertex[3]; + copyFirstVertexForCode(currentNode->octalCode,(float*)&startVertex); float voxelScale = 1 / powf(2, *currentNode->octalCode); // populate the array with points for the 8 vertices // and RGB color for each added vertex for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) { *writeVerticesEndPointer = startVertex[j % 3] + (identityVertices[j] * voxelScale); - *(writeColorsArray + (writeVerticesEndPointer - writeVerticesArray)) = currentNode->color[j % 3]; + *(writeColorsArray + (writeVerticesEndPointer - writeVerticesArray)) = currentNode->getColor()[j % 3]; writeVerticesEndPointer++; } - voxelsAdded++; - - delete [] startVertex; } return voxelsAdded; @@ -363,4 +358,263 @@ void VoxelSystem::simulate(float deltaTime) { } +int VoxelSystem::_nodeCount = 0; +bool VoxelSystem::randomColorOperation(VoxelNode* node, bool down, void* extraData) { + + // we do our operations on the way up! + if (down) { + return true; + } + + _nodeCount++; + if (node->isColored()) { + nodeColor newColor = { 0,0,0,1 }; + newColor[0] = randomColorValue(150); + newColor[1] = randomColorValue(150); + newColor[1] = randomColorValue(150); + + //printf("randomize color node %d was %x,%x,%x NOW %x,%x,%x\n", + // _nodeCount,node->getTrueColor()[0],node->getTrueColor()[1],node->getTrueColor()[2], + // newColor[0],newColor[1],newColor[2]); + node->setColor(newColor); + } else { + //printf("not randomizing color node of %d since it has no color\n",_nodeCount); + } + return true; +} + +void VoxelSystem::randomizeVoxelColors() { + _nodeCount = 0; + tree->recurseTreeWithOperation(randomColorOperation); + printf("setting randomized true color for %d nodes\n",_nodeCount); + setupNewVoxelsForDrawing(); +} + +bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, bool down, void* extraData) { + + // we do our operations on the way up! + if (down) { + return true; + } + + _nodeCount++; + + // always false colorize + unsigned char newR = randomColorValue(150); + unsigned char newG = randomColorValue(150); + unsigned char newB = randomColorValue(150); + + printf("randomize FALSE color node %d was %x,%x,%x NOW %x,%x,%x\n", + _nodeCount,node->getTrueColor()[0],node->getTrueColor()[1],node->getTrueColor()[2], + newR,newG,newB); + node->setFalseColor(newR,newG,newB); + + return true; // keep going! +} + +void VoxelSystem::falseColorizeRandom() { + _nodeCount = 0; + tree->recurseTreeWithOperation(falseColorizeRandomOperation); + printf("setting randomized false color for %d nodes\n",_nodeCount); + setupNewVoxelsForDrawing(); +} + +bool VoxelSystem::trueColorizeOperation(VoxelNode* node, bool down, void* extraData) { + + // we do our operations on the way up! + if (down) { + return true; + } + + _nodeCount++; + node->setFalseColored(false); + //printf("setting true color for node %d\n",_nodeCount); + return true; +} + +void VoxelSystem::trueColorize() { + _nodeCount = 0; + tree->recurseTreeWithOperation(trueColorizeOperation); + printf("setting true color for %d nodes\n",_nodeCount); + setupNewVoxelsForDrawing(); +} + +// Will false colorize voxels that are not in view +bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, bool down, void* extraData) { + + // we do our operations on the way up! + if (down) { + return true; + } + + ViewFrustum* viewFrustum = (ViewFrustum*) extraData; + + _nodeCount++; + + // only do this for truely colored voxels... + if (node->isColored()) { + // first calculate the AAbox for the voxel + AABox voxelBox; + node->getAABox(voxelBox); + + voxelBox.scale(TREE_SCALE); + + printf("voxelBox corner=(%f,%f,%f) x=%f y=%f z=%f\n", + voxelBox.corner.x, voxelBox.corner.y, voxelBox.corner.z, + voxelBox.x, voxelBox.y, voxelBox.z); + + // If the voxel is outside of the view frustum, then false color it red + if (ViewFrustum::OUTSIDE == viewFrustum->boxInFrustum(voxelBox)) { + // Out of view voxels are colored RED + unsigned char newR = 255; + unsigned char newG = 0; + unsigned char newB = 0; + + //printf("voxel OUTSIDE view - FALSE colorizing node %d TRUE color is %x,%x,%x \n", + // _nodeCount,node->getTrueColor()[0],node->getTrueColor()[1],node->getTrueColor()[2]); + node->setFalseColor(newR,newG,newB); + } else { + printf("voxel NOT OUTSIDE view\n"); + } + } else { + printf("voxel not colored, don't consider it\n"); + } + + return true; // keep going! +} + +void VoxelSystem::falseColorizeInView(ViewFrustum* viewFrustum) { + _nodeCount = 0; + tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)viewFrustum); + printf("setting in view false color for %d nodes\n",_nodeCount); + setupNewVoxelsForDrawing(); +} + +// Will false colorize voxels based on distance from view +bool VoxelSystem::falseColorizeDistanceFromViewOperation(VoxelNode* node, bool down, void* extraData) { + + //printf("falseColorizeDistanceFromViewOperation() down=%s\n",(down ? "TRUE" : "FALSE")); + + // we do our operations on the way up! + if (down) { + return true; + } + + ViewFrustum* viewFrustum = (ViewFrustum*) extraData; + + // only do this for truly colored voxels... + if (node->isColored()) { + + // We need our distance for both up and down + glm::vec3 nodePosition; + float* startVertex = firstVertexForCode(node->octalCode); + nodePosition.x = startVertex[0]; + nodePosition.y = startVertex[1]; + nodePosition.z = startVertex[2]; + delete startVertex; + + // scale up the node position + nodePosition = nodePosition*(float)TREE_SCALE; + + float halfUnitForVoxel = powf(0.5, *node->octalCode) * (0.5 * TREE_SCALE); + glm::vec3 viewerPosition = viewFrustum->getPosition(); + + //printf("halfUnitForVoxel=%f\n",halfUnitForVoxel); + //printf("viewer.x=%f y=%f z=%f \n", viewerPosition.x, viewerPosition.y, viewerPosition.z); + //printf("node.x=%f y=%f z=%f \n", nodePosition.x, nodePosition.y, nodePosition.z); + + float distance = sqrtf(powf(viewerPosition.x - nodePosition.x - halfUnitForVoxel, 2) + + powf(viewerPosition.y - nodePosition.y - halfUnitForVoxel, 2) + + powf(viewerPosition.z - nodePosition.z - halfUnitForVoxel, 2)); + + // actually colorize + _nodeCount++; + + float distanceRatio = (_minDistance==_maxDistance) ? 1 : (distance - _minDistance)/(_maxDistance - _minDistance); + + // We want to colorize this in 16 bug chunks of color + const unsigned char maxColor = 255; + const unsigned char colorBands = 16; + const unsigned char gradientOver = 128; + unsigned char colorBand = (colorBands*distanceRatio); + unsigned char newR = (colorBand*(gradientOver/colorBands))+(maxColor-gradientOver); + unsigned char newG = 0; + unsigned char newB = 0; + //printf("Setting color down=%s distance=%f min=%f max=%f distanceRatio=%f color=%d \n", + // (down ? "TRUE" : "FALSE"), distance, _minDistance, _maxDistance, distanceRatio, (int)newR); + + node->setFalseColor(newR,newG,newB); + } else { + //printf("voxel not colored, don't consider it - down=%s\n",(down ? "TRUE" : "FALSE")); + } + return true; // keep going! +} + +float VoxelSystem::_maxDistance = 0.0; +float VoxelSystem::_minDistance = FLT_MAX; + +// Helper function will get the distance from view range, would be nice if you could just keep track +// of this as voxels are created and/or colored... seems like some transform math could do that so +// we wouldn't need to do two passes of the tree +bool VoxelSystem::getDistanceFromViewRangeOperation(VoxelNode* node, bool down, void* extraData) { + + // we do our operations on the way up! + if (down) { + return true; + } + + //printf("getDistanceFromViewRangeOperation() down=%s\n",(down ? "TRUE" : "FALSE")); + + ViewFrustum* viewFrustum = (ViewFrustum*) extraData; + + // only do this for truly colored voxels... + if (node->isColored()) { + + // We need our distance for both up and down + glm::vec3 nodePosition; + float* startVertex = firstVertexForCode(node->octalCode); + nodePosition.x = startVertex[0]; + nodePosition.y = startVertex[1]; + nodePosition.z = startVertex[2]; + delete startVertex; + + // scale up the node position + nodePosition = nodePosition*(float)TREE_SCALE; + + float halfUnitForVoxel = powf(0.5, *node->octalCode) * (0.5 * TREE_SCALE); + glm::vec3 viewerPosition = viewFrustum->getPosition(); + + float distance = sqrtf(powf(viewerPosition.x - nodePosition.x - halfUnitForVoxel, 2) + + powf(viewerPosition.y - nodePosition.y - halfUnitForVoxel, 2) + + powf(viewerPosition.z - nodePosition.z - halfUnitForVoxel, 2)); + + // on way down, calculate the range of distances + if (distance > _maxDistance) { + _maxDistance = distance; + //printf("new maxDistance=%f down=%s\n",_maxDistance, (down ? "TRUE" : "FALSE")); + } + if (distance < _minDistance) { + _minDistance = distance; + //printf("new minDistance=%f down=%s\n",_minDistance, (down ? "TRUE" : "FALSE")); + } + + _nodeCount++; + } + return true; // keep going! +} + +void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) { + _nodeCount = 0; + + _maxDistance = 0.0; + _minDistance = FLT_MAX; + tree->recurseTreeWithOperation(getDistanceFromViewRangeOperation,(void*)viewFrustum); + printf("determining distance range for %d nodes\n",_nodeCount); + + _nodeCount = 0; + + tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum); + printf("setting in distance false color for %d nodes\n",_nodeCount); + setupNewVoxelsForDrawing(); +} diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 5395ce700a..6c9b5d972e 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -14,6 +14,7 @@ #include #include #include +#include #include "Head.h" #include "Util.h" #include "world.h" @@ -44,7 +45,27 @@ public: long int getVoxelsColoredRunningAverage(); long int getVoxelsBytesReadRunningAverage(); + // Methods that recurse tree + void randomizeVoxelColors(); + void falseColorizeRandom(); + void trueColorize(); + void falseColorizeInView(ViewFrustum* viewFrustum); + void falseColorizeDistanceFromView(ViewFrustum* viewFrustum); + private: + // Operation functions for tree recursion methods + static int _nodeCount; + static bool randomColorOperation(VoxelNode* node, bool down, void* extraData); + static bool falseColorizeRandomOperation(VoxelNode* node, bool down, void* extraData); + static bool trueColorizeOperation(VoxelNode* node, bool down, void* extraData); + static bool falseColorizeInViewOperation(VoxelNode* node, bool down, void* extraData); + static bool falseColorizeDistanceFromViewOperation(VoxelNode* node, bool down, void* extraData); + static bool getDistanceFromViewRangeOperation(VoxelNode* node, bool down, void* extraData); + + // these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here + static float _maxDistance; + static float _minDistance; + int voxelsRendered; Head *viewerHead; VoxelTree *tree; @@ -59,7 +80,7 @@ private: GLuint vboIndicesID; pthread_mutex_t bufferWriteLock; - int treeToArrays(VoxelNode *currentNode, float nodePosition[3]); + int treeToArrays(VoxelNode *currentNode, const glm::vec3& nodePosition); void setupNewVoxelsForDrawing(); void copyWrittenDataToReadArrays(); }; From 8c4536199f58f2dba3010e11fe6b98726058e1b4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 19 Apr 2013 20:02:14 -0700 Subject: [PATCH 09/17] added menu items for false color operations --- interface/src/main.cpp | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 0b02b9ecf3..86b39fee2f 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -1021,6 +1021,39 @@ int setFrustumRenderMode(int state) { return ::frustumDrawingMode; } +int doRandomizeVoxelColors(int state) { + if (state == MENU_ROW_PICKED) { + ::voxels.randomizeVoxelColors(); + } + return state; +} + + +int doFalseRandomizeVoxelColors(int state) { + if (state == MENU_ROW_PICKED) { + ::voxels.falseColorizeRandom(); + } + return state; +} + +int doTrueVoxelColors(int state) { + if (state == MENU_ROW_PICKED) { + ::voxels.trueColorize(); + } + return state; +} + +int doFalseColorizeInView(int state) { + if (state == MENU_ROW_PICKED) { + if (::frustumOn) { + // we probably want to make sure the viewFrustum is initialized first + voxels.falseColorizeDistanceFromView(&::viewFrustum); + } + } + return state; +} + + const char* modeAll = " - All "; const char* modeVectors = " - Vectors "; const char* modePlanes = " - Planes "; @@ -1075,7 +1108,10 @@ void initMenu() { // Debug menuColumnDebug = menu.addColumn("Debug"); - + menuColumnDebug->addRow("Randomize Voxel Colors (Z)", doRandomizeVoxelColors); + menuColumnDebug->addRow("Randomize FALSE Voxel Colors", doFalseRandomizeVoxelColors); + menuColumnDebug->addRow("FALSE Color Voxel Out of View", doFalseColorizeInView); + menuColumnDebug->addRow("True Colors", doTrueVoxelColors); } void testPointToVoxel() @@ -1239,6 +1275,8 @@ void key(unsigned char k, int x, int y) // if (k == '\\') ViewFrustum::fovAngleAdust += 0.05; if (k == 'R') setFrustumRenderMode(MENU_ROW_PICKED); + + if (k == 'Z') doRandomizeVoxelColors(MENU_ROW_PICKED); if (k == '&') { ::paintOn = !::paintOn; // toggle paint From 34b401d13fe6261984f8e3c25e450a53ac62158d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 21 Apr 2013 12:01:54 -0700 Subject: [PATCH 10/17] changed render_view_frustum() to match coding standard, added menu items, cleanup - split render_view_frustum() into two parts: loadViewFrustum() and renderViewFrustum() - cleaned up debug menu items to match actual false color behaviors - coding standard cleanup --- interface/src/main.cpp | 99 +++++++++++++++++++++++++----------------- 1 file changed, 60 insertions(+), 39 deletions(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index fba8633ac1..8d996d85e5 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -555,34 +555,14 @@ void updateAvatar(float frametime) } ///////////////////////////////////////////////////////////////////////////////////// -// render_view_frustum() +// renderViewFrustum() // -// Description: this will render the view frustum bounds for EITHER the head +// Description: this will load the view frustum bounds for EITHER the head // or the "myCamera". // -// Frustum rendering mode. For debug purposes, we allow drawing the frustum in a couple of different ways. -// We can draw it with each of these parts: -// * Origin Direction/Up/Right vectors - these will be drawn at the point of the camera -// * Near plane - this plane is drawn very close to the origin point. -// * Right/Left planes - these two planes are drawn between the near and far planes. -// * Far plane - the plane is drawn in the distance. -// Modes - the following modes, will draw the following parts. -// * All - draws all the parts listed above -// * Planes - draws the planes but not the origin vectors -// * Origin Vectors - draws the origin vectors ONLY -// * Near Plane - draws only the near plane -// * Far Plane - draws only the far plane -#define FRUSTUM_DRAW_MODE_ALL 0 -#define FRUSTUM_DRAW_MODE_VECTORS 1 -#define FRUSTUM_DRAW_MODE_PLANES 2 -#define FRUSTUM_DRAW_MODE_NEAR_PLANE 3 -#define FRUSTUM_DRAW_MODE_FAR_PLANE 4 -#define FRUSTUM_DRAW_MODE_COUNT 5 -// These global scoped variables are used by our render_view_frustum() function below, but are also available as globals -// so that the keyboard and menu can manipulate them. - -int frustumDrawingMode = FRUSTUM_DRAW_MODE_ALL; // the mode we're drawing the frustum in, see notes above +// These global scoped variables are used by our loadViewFrustum() and renderViewFrustum functions below, but are also +// available as globals so that the keyboard and menu can manipulate them. bool frustumOn = false; // Whether or not to display the debug view frustum bool cameraFrustum = true; // which frustum to look at @@ -594,8 +574,7 @@ float viewFrustumOffsetRoll = 0.0; float viewFrustumOffsetDistance = 25.0; float viewFrustumOffsetUp = 0.0; -void render_view_frustum() { - +void loadViewFrustum(ViewFrustum& viewFrustum) { // We will use these below, from either the camera or head vectors calculated above glm::vec3 position; glm::vec3 direction; @@ -654,8 +633,44 @@ void render_view_frustum() { // Ask the ViewFrustum class to calculate our corners viewFrustum.calculate(); - - //viewFrustum.dump(); +} + +///////////////////////////////////////////////////////////////////////////////////// +// renderViewFrustum() +// +// Description: this will render the view frustum bounds for EITHER the head +// or the "myCamera". +// +// Frustum rendering mode. For debug purposes, we allow drawing the frustum in a couple of different ways. +// We can draw it with each of these parts: +// * Origin Direction/Up/Right vectors - these will be drawn at the point of the camera +// * Near plane - this plane is drawn very close to the origin point. +// * Right/Left planes - these two planes are drawn between the near and far planes. +// * Far plane - the plane is drawn in the distance. +// Modes - the following modes, will draw the following parts. +// * All - draws all the parts listed above +// * Planes - draws the planes but not the origin vectors +// * Origin Vectors - draws the origin vectors ONLY +// * Near Plane - draws only the near plane +// * Far Plane - draws only the far plane +#define FRUSTUM_DRAW_MODE_ALL 0 +#define FRUSTUM_DRAW_MODE_VECTORS 1 +#define FRUSTUM_DRAW_MODE_PLANES 2 +#define FRUSTUM_DRAW_MODE_NEAR_PLANE 3 +#define FRUSTUM_DRAW_MODE_FAR_PLANE 4 +#define FRUSTUM_DRAW_MODE_COUNT 5 + +int frustumDrawingMode = FRUSTUM_DRAW_MODE_ALL; // the mode we're drawing the frustum in, see notes above + +void renderViewFrustum(ViewFrustum& viewFrustum) { + + // Load it with the latest details! + loadViewFrustum(viewFrustum); + + glm::vec3 position = viewFrustum.getPosition(); + glm::vec3 direction = viewFrustum.getDirection(); + glm::vec3 up = viewFrustum.getUp(); + glm::vec3 right = viewFrustum.getRight(); // Get ready to draw some lines glDisable(GL_LIGHTING); @@ -816,7 +831,7 @@ void display(void) // is the viewFrustumOffsetCamera. But theoretically, we could use this same mechanism // to add other cameras. // - // Why have two cameras? Well, one reason is that because in the case of the render_view_frustum() + // Why have two cameras? Well, one reason is that because in the case of the renderViewFrustum() // code, we want to keep the state of "myCamera" intact, so we can render what the view frustum of // myCamera is. But we also want to do meaningful camera transforms on OpenGL for the offset camera Camera whichCamera = myCamera; @@ -910,7 +925,7 @@ void display(void) if (!displayHead && statsOn) render_world_box(); // brad's frustum for debugging - if (::frustumOn) render_view_frustum(); + if (::frustumOn) renderViewFrustum(::viewFrustum); //Render my own avatar myAvatar.render(true); @@ -1112,12 +1127,19 @@ int doTrueVoxelColors(int state) { return state; } +int doFalseColorizeByDistance(int state) { + if (state == MENU_ROW_PICKED) { + loadViewFrustum(::viewFrustum); + voxels.falseColorizeDistanceFromView(&::viewFrustum); + } + return state; +} + int doFalseColorizeInView(int state) { if (state == MENU_ROW_PICKED) { - if (::frustumOn) { - // we probably want to make sure the viewFrustum is initialized first - voxels.falseColorizeDistanceFromView(&::viewFrustum); - } + loadViewFrustum(::viewFrustum); + // we probably want to make sure the viewFrustum is initialized first + voxels.falseColorizeInView(&::viewFrustum); } return state; } @@ -1177,10 +1199,11 @@ void initMenu() { // Debug menuColumnDebug = menu.addColumn("Debug"); - menuColumnDebug->addRow("Randomize Voxel Colors (Z)", doRandomizeVoxelColors); - menuColumnDebug->addRow("Randomize FALSE Voxel Colors", doFalseRandomizeVoxelColors); + menuColumnDebug->addRow("Randomize Voxel TRUE Colors", doRandomizeVoxelColors); + menuColumnDebug->addRow("FALSE Color Voxels Randomly", doFalseRandomizeVoxelColors); + menuColumnDebug->addRow("FALSE Color Voxels by Distance", doFalseColorizeByDistance); menuColumnDebug->addRow("FALSE Color Voxel Out of View", doFalseColorizeInView); - menuColumnDebug->addRow("True Colors", doTrueVoxelColors); + menuColumnDebug->addRow("Show TRUE Colors", doTrueVoxelColors); } void testPointToVoxel() @@ -1345,8 +1368,6 @@ void key(unsigned char k, int x, int y) if (k == 'R') setFrustumRenderMode(MENU_ROW_PICKED); - if (k == 'Z') doRandomizeVoxelColors(MENU_ROW_PICKED); - if (k == '&') { ::paintOn = !::paintOn; // toggle paint ::setupPaintingVoxel(); // also randomizes colors From 7a632115e412fe22ac842269fcc7bd00efcd6f00 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 21 Apr 2013 12:18:42 -0700 Subject: [PATCH 11/17] fixed crash when no avatar mixer is present and display stats is enabled --- interface/src/main.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 8d996d85e5..8712700efc 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -341,11 +341,15 @@ void displayStats(void) Agent *avatarMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER); char avatarMixerStats[200]; - sprintf(avatarMixerStats, "Avatar Mixer - %.f kbps, %.f pps", - roundf(avatarMixer->getAverageKilobitsPerSecond()), - roundf(avatarMixer->getAveragePacketsPerSecond())); + if (avatarMixer) { + sprintf(avatarMixerStats, "Avatar Mixer - %.f kbps, %.f pps", + roundf(avatarMixer->getAverageKilobitsPerSecond()), + roundf(avatarMixer->getAveragePacketsPerSecond())); + } else { + sprintf(avatarMixerStats, "No Avatar Mixer"); + } drawtext(10, statsVerticalOffset + 330, 0.10f, 0, 1.0, 0, avatarMixerStats); - + if (::perfStatsOn) { // Get the PerfStats group details. We need to allocate and array of char* long enough to hold 1+groups char** perfStatLinesArray = new char*[PerfStat::getGroupCount()+1]; From 8a150d27b8ad84754739a570011294b7a8e6a3b4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 21 Apr 2013 15:18:17 -0700 Subject: [PATCH 12/17] Cleanup for coding standard fix bug in creation of plane from points - cleaned up code to match HiFi Coding standard - fixed bug in creation of plane related to cross product --- libraries/voxels/src/Plane.cpp | 109 ++++++++++++++++++--------------- libraries/voxels/src/Plane.h | 39 +++++++----- 2 files changed, 84 insertions(+), 64 deletions(-) diff --git a/libraries/voxels/src/Plane.cpp b/libraries/voxels/src/Plane.cpp index 2f0d43925b..10d1e2fb6b 100755 --- a/libraries/voxels/src/Plane.cpp +++ b/libraries/voxels/src/Plane.cpp @@ -1,6 +1,12 @@ -// Plane.cpp // -////////////////////////////////////////////////////////////////////// +// Plane.h +// hifi +// +// Created by Brad Hefta-Gaub on 04/11/13. +// Originally from lighthouse3d. Modified to utilize glm::vec3 and clean up to our coding standards +// +// Simple plane class. +// #include "Plane.h" #include @@ -10,78 +16,83 @@ using voxels_lib::printLog; // These are some useful utilities that vec3 is missing -float vec3_length(const glm::vec3& v) { - return((float)sqrt(v.x*v.x + v.y*v.y + v.z*v.z)); +float length(const glm::vec3& v) { + return((float)sqrt(v.x * v.x + v.y * v.y + v.z * v.z)); } -void vec3_normalize(glm::vec3& v) { - - float len; - - len = vec3_length(v); - if (len) { - v.x /= len;; - v.y /= len; - v.z /= len; - } +void normalize(glm::vec3& v) { + float len; + len = length(v); + if (len) { + v.x /= len;; + v.y /= len; + v.z /= len; + } } -float vec3_innerProduct(const glm::vec3& v1,const glm::vec3& v2) { - - return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z); +// cross product +glm::vec3 crossProduct(const glm::vec3& lhs, const glm::vec3& rhs) { + glm::vec3 result; + result.x = lhs.y * rhs.z - lhs.z * rhs.y; + result.y = lhs.z * rhs.x - lhs.x * rhs.z; + result.z = lhs.x * rhs.y - lhs.y * rhs.x; + return result; } - -Plane::Plane(const glm::vec3 &v1, const glm::vec3 &v2, const glm::vec3 &v3) { - - set3Points(v1,v2,v3); +float innerProduct(const glm::vec3& v1,const glm::vec3& v2) { + return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z); } - -Plane::Plane() {} - -Plane::~Plane() {} - +void printVec3(const char* name, const glm::vec3& v) { + printf("%s x=%f y=%f z=%f\n", name, v.x, v.y, v.z); +} void Plane::set3Points(const glm::vec3 &v1, const glm::vec3 &v2, const glm::vec3 &v3) { + glm::vec3 linev1v2, linev1v3; + linev1v2 = v2 - v1; + linev1v3 = v3 - v1; - glm::vec3 aux1, aux2; + // this will be perpendicular to both lines + _normal = crossProduct(linev1v2,linev1v3); + normalize(_normal); - aux1 = v1 - v2; - aux2 = v3 - v2; + // this is a point on the plane + _point = v2; - normal = aux2 * aux1; - - vec3_normalize(normal); - point = v2; - d = -(vec3_innerProduct(normal,point)); + // the D coefficient from the form Ax+By+Cz=D + _dCoefficient = -(innerProduct(_normal,_point)); } void Plane::setNormalAndPoint(const glm::vec3 &normal, const glm::vec3 &point) { + _point = point; + _normal = normal; + normalize(_normal); - this->normal = normal; - vec3_normalize(this->normal); - d = -(vec3_innerProduct(this->normal,point)); + // the D coefficient from the form Ax+By+Cz=D + _dCoefficient = -(innerProduct(_normal,_point)); } void Plane::setCoefficients(float a, float b, float c, float d) { + // set the normal vector + _normal = glm::vec3(a,b,c); - // set the normal vector - normal = glm::vec3(a,b,c); - //compute the lenght of the vector - float l = normal.length(); - // normalize the vector - normal = glm::vec3(a/l,b/l,c/l); - // and divide d by th length as well - this->d = d/l; + //compute the lenght of the vector + float l = length(_normal); + + // normalize the vector + _normal = glm::vec3(a/l,b/l,c/l); + + // and divide d by th length as well + _dCoefficient = d/l; } -float Plane::distance(const glm::vec3 &p) { - return (d + vec3_innerProduct(normal,p)); +float Plane::distance(const glm::vec3 &point) const { + return (_dCoefficient + innerProduct(_normal,point)); } -void Plane::print() { - //printLog("Plane(");normal.print();printLog("# %f)",d); +void Plane::print() const { + printf("Plane - point (x=%f y=%f z=%f) normal (x=%f y=%f z=%f) d=%f\n", + _point.x, _point.y, _point.z, _normal.x, _normal.y, _normal.z, _dCoefficient); } diff --git a/libraries/voxels/src/Plane.h b/libraries/voxels/src/Plane.h index 5c23993dc9..8ce0e5042e 100755 --- a/libraries/voxels/src/Plane.h +++ b/libraries/voxels/src/Plane.h @@ -1,34 +1,43 @@ -////////////////////////////////////////////////////////////////////// -// Plane.h - inspired and modified from lighthouse3d.com // - +// Plane.h +// hifi +// +// Created by Brad Hefta-Gaub on 04/11/13. +// Originally from lighthouse3d. Modified to utilize glm::vec3 and clean up to our coding standards +// +// Simple plane class. +// #ifndef _PLANE_ #define _PLANE_ #include - class Plane { - public: + Plane(const glm::vec3 &v1, const glm::vec3 &v2, const glm::vec3 &v3) { set3Points(v1,v2,v3); } + Plane() : _normal(0,0,0), _point(0,0,0), _dCoefficient(0) {}; + ~Plane() {} ; - glm::vec3 normal,point; - float d; - - - Plane(const glm::vec3 &v1, const glm::vec3 &v2, const glm::vec3 &v3); - Plane(void); - ~Plane(); - + // methods for defining the plane void set3Points(const glm::vec3 &v1, const glm::vec3 &v2, const glm::vec3 &v3); void setNormalAndPoint(const glm::vec3 &normal, const glm::vec3 &point); void setCoefficients(float a, float b, float c, float d); - float distance(const glm::vec3 &p); - void print(); + // getters + const glm::vec3& getNormal() const { return _normal; }; + const glm::vec3& getPoint() const { return _point; }; + float getDCoefficient() const { return _dCoefficient; }; + // utilities + float distance(const glm::vec3 &point) const; + void print() const; + +private: + glm::vec3 _normal; + glm::vec3 _point; + float _dCoefficient; }; From a02a75f5166ee8fe43ed794481fffdd382f6e778 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 21 Apr 2013 15:21:03 -0700 Subject: [PATCH 13/17] fix bug in definition of frustum planes, and general code cleanup - Fixed bug in definition of frustum planes, namely making sure the points are given in the correct order so that our plane normals point in correct direction - general code cleanup to match coding standard --- libraries/voxels/src/ViewFrustum.cpp | 52 ++++++++++++++++++++-------- libraries/voxels/src/ViewFrustum.h | 4 ++- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index 704289d977..53371d5268 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -85,14 +85,23 @@ void ViewFrustum::calculate() { _nearBottomRight = _nearCenter - (_up * nearHalfHeight) + (_right * nearHalfWidth); // compute the six planes - // the function set3Points assumes that the points - // are given in counter clockwise order - _planes[TOPP].set3Points(_nearTopRight,_nearTopLeft,_farTopLeft); - _planes[BOTTOMP].set3Points(_nearBottomLeft,_nearBottomRight,_farBottomRight); - _planes[LEFTP].set3Points(_nearTopLeft,_nearBottomLeft,_farBottomLeft); - _planes[RIGHTP].set3Points(_nearBottomRight,_nearTopRight,_farBottomRight); - _planes[NEARP].set3Points(_nearTopLeft,_nearTopRight,_nearBottomRight); - _planes[FARP].set3Points(_farTopRight,_farTopLeft,_farBottomLeft); + // The planes are defined such that the normal points towards the inside of the view frustum. + // Testing if an object is inside the view frustum is performed by computing on which side of + // the plane the object resides. This can be done computing the signed distance from the point + // to the plane. If it is on the side that the normal is pointing, i.e. the signed distance + // is positive, then it is on the right side of the respective plane. If an object is on the + // right side of all six planes then the object is inside the frustum. + + // the function set3Points assumes that the points are given in counter clockwise order, assume you + // are inside the frustum, facing the plane. Start with any point, and go counter clockwise for + // three consecutive points + + _planes[TOP_PLANE ].set3Points(_nearTopRight,_nearTopLeft,_farTopLeft); + _planes[BOTTOM_PLANE].set3Points(_nearBottomLeft,_nearBottomRight,_farBottomRight); + _planes[LEFT_PLANE ].set3Points(_nearBottomLeft,_farBottomLeft,_farTopLeft); + _planes[RIGHT_PLANE ].set3Points(_farBottomRight,_nearBottomRight,_nearTopRight); + _planes[NEAR_PLANE ].set3Points(_nearBottomRight,_nearBottomLeft,_nearTopLeft); + _planes[FAR_PLANE ].set3Points(_farBottomLeft,_farBottomRight,_farTopRight); } @@ -135,11 +144,26 @@ void ViewFrustum::dump() { } +//enum { TOP_PLANE = 0, BOTTOM_PLANE, LEFT_PLANE, RIGHT_PLANE, NEAR_PLANE, FAR_PLANE }; +const char* ViewFrustum::debugPlaneName (int plane) const { + switch (plane) { + case TOP_PLANE: return "Top Plane"; + case BOTTOM_PLANE: return "Bottom Plane"; + case LEFT_PLANE: return "Left Plane"; + case RIGHT_PLANE: return "Right Plane"; + case NEAR_PLANE: return "Near Plane"; + case FAR_PLANE: return "Far Plane"; + } + return "Unknown"; +} + + int ViewFrustum::pointInFrustum(glm::vec3 &p) { int result = INSIDE; for(int i=0; i < 6; i++) { - if (_planes[i].distance(p) < 0) + if (_planes[i].distance(p) < 0) { return OUTSIDE; + } } return(result); } @@ -160,17 +184,17 @@ int ViewFrustum::sphereInFrustum(glm::vec3 ¢er, float radius) { int ViewFrustum::boxInFrustum(AABox &b) { -printf("ViewFrustum::boxInFrustum() box.corner=%f,%f,%f x=%f\n",b.corner.x,b.corner.y,b.corner.z,b.x); + printf("ViewFrustum::boxInFrustum() box.corner=%f,%f,%f x=%f\n",b.corner.x,b.corner.y,b.corner.z,b.x); int result = INSIDE; for(int i=0; i < 6; i++) { printf("plane[%d] -- point(%f,%f,%f) normal(%f,%f,%f) d=%f \n",i, - _planes[i].point.x, _planes[i].point.y, _planes[i].point.z, - _planes[i].normal.x, _planes[i].normal.y, _planes[i].normal.z, - _planes[i].d + _planes[i].getPoint().x, _planes[i].getPoint().y, _planes[i].getPoint().z, + _planes[i].getNormal().x, _planes[i].getNormal().y, _planes[i].getNormal().z, + _planes[i].getDCoefficient() ); - glm::vec3 normal = _planes[i].normal; + glm::vec3 normal = _planes[i].getNormal(); glm::vec3 boxVertexP = b.getVertexP(normal); float planeToBoxVertexPDistance = _planes[i].distance(boxVertexP); diff --git a/libraries/voxels/src/ViewFrustum.h b/libraries/voxels/src/ViewFrustum.h index 9b496544c5..5746f21cb8 100644 --- a/libraries/voxels/src/ViewFrustum.h +++ b/libraries/voxels/src/ViewFrustum.h @@ -45,9 +45,11 @@ private: glm::vec3 _nearTopRight; glm::vec3 _nearBottomLeft; glm::vec3 _nearBottomRight; - enum { TOPP = 0, BOTTOMP, LEFTP, RIGHTP, NEARP, FARP }; + 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; + public: // setters for camera attributes void setPosition (const glm::vec3& p) { _position = p; } From 3dc818d31e479eff88f844cabaab6d4d250ff33b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 21 Apr 2013 15:22:36 -0700 Subject: [PATCH 14/17] Changed false colorization to use point in frustum for now, since that works --- interface/src/VoxelSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 93f9f414b3..005bd089a8 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -465,7 +465,7 @@ bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, bool down, void* voxelBox.x, voxelBox.y, voxelBox.z); // If the voxel is outside of the view frustum, then false color it red - if (ViewFrustum::OUTSIDE == viewFrustum->boxInFrustum(voxelBox)) { + if (ViewFrustum::OUTSIDE == viewFrustum->pointInFrustum(voxelBox.corner)) { // Out of view voxels are colored RED unsigned char newR = 255; unsigned char newG = 0; From e93ece0f52eb06b2df3c57bd63adeacab0150692 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 21 Apr 2013 19:45:54 -0700 Subject: [PATCH 15/17] Added support for NO_FALSE_COLOR define. - changed VoxelNode to have implementation option for NO_FALSE_COLOR Need some help from Stephen and/or Leo on how to make cmake support building the voxels library in NO_FALSE_COLOR mode for the server but keep false color support in the client --- libraries/voxels/src/VoxelNode.cpp | 8 +++++++- libraries/voxels/src/VoxelNode.h | 13 ++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 7cae90f744..4aef3a0fe8 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -19,7 +19,9 @@ VoxelNode::VoxelNode() { octalCode = NULL; +#ifdef HAS_FALSE_COLOR _falseColored = false; // assume true color +#endif // default pointers to child nodes to NULL for (int i = 0; i < 8; i++) { @@ -83,6 +85,9 @@ void VoxelNode::setColorFromAverageOfChildren() { setColor(newColor); } +// Note: !NO_FALSE_COLOR implementations of setFalseColor(), setFalseColored(), and setColor() here. +// the actual NO_FALSE_COLOR version are inline in the VoxelNode.h +#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color void VoxelNode::setFalseColor(colorPart red, colorPart green, colorPart blue) { _falseColored=true; _currentColor[0] = red; @@ -91,7 +96,7 @@ void VoxelNode::setFalseColor(colorPart red, colorPart green, colorPart blue) { _currentColor[3] = 1; // XXXBHG - False colors are always considered set } -void VoxelNode::setFalseColored(bool isFalseColored) { +void VoxelNode::setFalseColored(bool isFalseColored) { // if we were false colored, and are no longer false colored, then swap back if (_falseColored && !isFalseColored) { memcpy(&_currentColor,&_trueColor,sizeof(nodeColor)); @@ -107,6 +112,7 @@ void VoxelNode::setColor(const nodeColor& color) { memcpy(&_currentColor,&color,sizeof(nodeColor)); } } +#endif // will detect if children are leaves AND the same color // and in that case will delete the children and make this node diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 42b4331440..cf644a1fd1 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -17,8 +17,10 @@ typedef unsigned char nodeColor[4]; class VoxelNode { private: nodeColor _trueColor; +#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color nodeColor _currentColor; bool _falseColored; +#endif public: VoxelNode(); ~VoxelNode(); @@ -32,13 +34,22 @@ public: VoxelNode *children[8]; bool isColored() const { return (_trueColor[3]==1); }; + +#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color void setFalseColor(colorPart red, colorPart green, colorPart blue); void setFalseColored(bool isFalseColored); bool getFalseColored() { return _falseColored; }; - void setColor(const nodeColor& color); const nodeColor& getTrueColor() const { return _trueColor; }; const nodeColor& getColor() const { return _currentColor; }; +#else + void setFalseColor(colorPart red, colorPart green, colorPart blue) { /* no op */ }; + void setFalseColored(bool isFalseColored) { /* no op */ }; + bool getFalseColored() { return false; }; + void setColor(const nodeColor& color) { memcpy(_trueColor,color,sizeof(nodeColor)); }; + const nodeColor& getTrueColor() const { return _trueColor; }; + const nodeColor& getColor() const { return _trueColor; }; +#endif void getAABox(AABox& box) const; }; From 358efb472ddcd2131eaf06f84e0bd5b3d7a6a8bf Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 21 Apr 2013 22:46:13 -0700 Subject: [PATCH 16/17] Clean up AABox to coding standard, made several methods const - Cleaned up AABox to be consistent with the coding standard - converted some methods to const and fixed up callers --- interface/src/VoxelSystem.cpp | 8 +-- libraries/voxels/src/AABox.cpp | 87 +++++++++++----------------- libraries/voxels/src/AABox.h | 39 ++++++++----- libraries/voxels/src/ViewFrustum.cpp | 15 ++--- libraries/voxels/src/ViewFrustum.h | 6 +- libraries/voxels/src/VoxelNode.cpp | 10 +++- 6 files changed, 82 insertions(+), 83 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 005bd089a8..b2bcc701e0 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -460,12 +460,12 @@ bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, bool down, void* voxelBox.scale(TREE_SCALE); - printf("voxelBox corner=(%f,%f,%f) x=%f y=%f z=%f\n", - voxelBox.corner.x, voxelBox.corner.y, voxelBox.corner.z, - voxelBox.x, voxelBox.y, voxelBox.z); + printf("voxelBox corner=(%f,%f,%f) x=%f\n", + voxelBox.getCorner().x, voxelBox.getCorner().y, voxelBox.getCorner().z, + voxelBox.getSize().x); // If the voxel is outside of the view frustum, then false color it red - if (ViewFrustum::OUTSIDE == viewFrustum->pointInFrustum(voxelBox.corner)) { + if (ViewFrustum::OUTSIDE == viewFrustum->pointInFrustum(voxelBox.getCorner())) { // Out of view voxels are colored RED unsigned char newR = 255; unsigned char newG = 0; diff --git a/libraries/voxels/src/AABox.cpp b/libraries/voxels/src/AABox.cpp index 4c2f18f863..0187bae853 100755 --- a/libraries/voxels/src/AABox.cpp +++ b/libraries/voxels/src/AABox.cpp @@ -1,85 +1,68 @@ -/* ------------------------------------------------------ - - Axis Aligned Boxes - Lighthouse3D - - -----------------------------------------------------*/ +// +// AABox.h - Axis Aligned Boxes +// hifi +// +// Added by Brad Hefta-Gaub on 04/11/13. +// Originally from lighthouse3d. Modified to utilize glm::vec3 and clean up to our coding standards +// +// Simple axis aligned box class. +// #include "AABox.h" -AABox::AABox(const glm::vec3& corner, float x, float y, float z) { - setBox(corner,x,y,z); -} - -AABox::AABox(void) { - corner.x = 0; corner.y = 0; corner.z = 0; - x = 1.0f; - y = 1.0f; - z = 1.0f; -} - - -AABox::~AABox() { - // nothing to do -} - - void AABox::scale(float scale) { - corner = corner*scale; - x *= scale; - y *= scale; - z *= scale; + _corner = _corner*scale; + _size = _size*scale; } -void AABox::setBox(const glm::vec3& corner, float x, float y, float z) { - this->corner = corner; - if (x < 0.0) { - x = -x; - this->corner.x -= x; +void AABox::setBox(const glm::vec3& corner, const glm::vec3& size) { + _corner = corner; + _size = size; + + // In the event that the caller gave us negative sizes, fix things up to be reasonable + if (_size.x < 0.0) { + _size.x = -size.x; + _corner.x -= _size.x; } - if (y < 0.0) { - y = -y; - this->corner.y -= y; + if (_size.y < 0.0) { + _size.y = -size.y; + _corner.y -= _size.y; } - if (z < 0.0) { - z = -z; - this->corner.z -= z; + if (_size.z < 0.0) { + _size.z = -size.z; + _corner.z -= _size.z; } - this->x = x; - this->y = y; - this->z = z; } - - -glm::vec3 AABox::getVertexP(const glm::vec3 &normal) { - glm::vec3 res = corner; +glm::vec3 AABox::getVertexP(const glm::vec3 &normal) const { + glm::vec3 res = _corner; if (normal.x > 0) - res.x += x; + res.x += _size.x; if (normal.y > 0) - res.y += y; + res.y += _size.y; if (normal.z > 0) - res.z += z; + res.z += _size.z; return(res); } -glm::vec3 AABox::getVertexN(const glm::vec3 &normal) { - glm::vec3 res = corner; +glm::vec3 AABox::getVertexN(const glm::vec3 &normal) const { + glm::vec3 res = _corner; if (normal.x < 0) - res.x += x; + res.x += _size.x; if (normal.y < 0) - res.y += y; + res.y += _size.y; if (normal.z < 0) - res.z += z; + res.z += _size.z; return(res); } diff --git a/libraries/voxels/src/AABox.h b/libraries/voxels/src/AABox.h index a00cda24c8..0a69b8608d 100755 --- a/libraries/voxels/src/AABox.h +++ b/libraries/voxels/src/AABox.h @@ -1,9 +1,12 @@ -/* ------------------------------------------------------ - - Axis Aligned Boxes - Lighthouse3D - - -----------------------------------------------------*/ - +// +// AABox.h - Axis Aligned Boxes +// hifi +// +// Added by Brad Hefta-Gaub on 04/11/13. +// Originally from lighthouse3d. Modified to utilize glm::vec3 and clean up to our coding standards +// +// Simple axis aligned box class. +// #ifndef _AABOX_ #define _AABOX_ @@ -15,20 +18,26 @@ class AABox public: - glm::vec3 corner; - float x,y,z; + AABox(const glm::vec3& corner, float x, float y, float z) : _corner(corner), _size(x,y,z) { }; + AABox(const glm::vec3& corner, const glm::vec3& size) : _corner(corner), _size(size) { }; + AABox() : _corner(0,0,0), _size(0,0,0) { } + ~AABox() { } - AABox(const glm::vec3 &corner, float x, float y, float z); - AABox(void); - ~AABox(); - - void setBox(const glm::vec3& corner, float x, float y, float z); + void setBox(const glm::vec3& corner, float x, float y, float z) { setBox(corner,glm::vec3(x,y,z)); }; + void setBox(const glm::vec3& corner, const glm::vec3& size); // for use in frustum computations - glm::vec3 getVertexP(const glm::vec3& normal); - glm::vec3 getVertexN(const glm::vec3& normal); + glm::vec3 getVertexP(const glm::vec3& normal) const; + glm::vec3 getVertexN(const glm::vec3& normal) const; void scale(float scale); + + const glm::vec3& getCorner() const { return _corner; }; + const glm::vec3& getSize() const { return _size; }; + +private: + glm::vec3 _corner; + glm::vec3 _size; }; diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index 53371d5268..9fdeafa449 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -158,17 +158,17 @@ const char* ViewFrustum::debugPlaneName (int plane) const { } -int ViewFrustum::pointInFrustum(glm::vec3 &p) { +int ViewFrustum::pointInFrustum(const glm::vec3& point) { int result = INSIDE; for(int i=0; i < 6; i++) { - if (_planes[i].distance(p) < 0) { + if (_planes[i].distance(point) < 0) { return OUTSIDE; } } return(result); } -int ViewFrustum::sphereInFrustum(glm::vec3 ¢er, float radius) { +int ViewFrustum::sphereInFrustum(const glm::vec3& center, float radius) { int result = INSIDE; float distance; for(int i=0; i < 6; i++) { @@ -182,9 +182,10 @@ int ViewFrustum::sphereInFrustum(glm::vec3 ¢er, float radius) { } -int ViewFrustum::boxInFrustum(AABox &b) { +int ViewFrustum::boxInFrustum(const AABox& box) { - printf("ViewFrustum::boxInFrustum() box.corner=%f,%f,%f x=%f\n",b.corner.x,b.corner.y,b.corner.z,b.x); + 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; for(int i=0; i < 6; i++) { @@ -195,10 +196,10 @@ int ViewFrustum::boxInFrustum(AABox &b) { ); glm::vec3 normal = _planes[i].getNormal(); - glm::vec3 boxVertexP = b.getVertexP(normal); + glm::vec3 boxVertexP = box.getVertexP(normal); float planeToBoxVertexPDistance = _planes[i].distance(boxVertexP); - glm::vec3 boxVertexN = b.getVertexN(normal); + glm::vec3 boxVertexN = box.getVertexN(normal); float planeToBoxVertexNDistance = _planes[i].distance(boxVertexN); diff --git a/libraries/voxels/src/ViewFrustum.h b/libraries/voxels/src/ViewFrustum.h index 5746f21cb8..6114953099 100644 --- a/libraries/voxels/src/ViewFrustum.h +++ b/libraries/voxels/src/ViewFrustum.h @@ -94,9 +94,9 @@ public: enum {OUTSIDE, INTERSECT, INSIDE}; - int pointInFrustum(glm::vec3 &p); - int sphereInFrustum(glm::vec3 ¢er, float radius); - int boxInFrustum(AABox &b); + int pointInFrustum(const glm::vec3& point); + int sphereInFrustum(const glm::vec3& center, float radius); + int boxInFrustum(const AABox& box); }; diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 4aef3a0fe8..9fab2c1092 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -41,12 +41,18 @@ VoxelNode::~VoxelNode() { } void VoxelNode::getAABox(AABox& box) const { + + glm::vec3 corner; + glm::vec3 size; + // copy corner into box - copyFirstVertexForCode(octalCode,(float*)&box.corner); + copyFirstVertexForCode(octalCode,(float*)&corner); // this tells you the "size" of the voxel float voxelScale = 1 / powf(2, *octalCode); - box.x = box.y = box.z = voxelScale; + size = glm::vec3(voxelScale,voxelScale,voxelScale); + + box.setBox(corner,size); } void VoxelNode::addChildAtIndex(int childIndex) { From 400ecf6b86c2b096c93bbea9dd093fdf5ca05011 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 21 Apr 2013 22:57:01 -0700 Subject: [PATCH 17/17] Convert over to standard glm functions for length, normalize, cross, and dot product --- libraries/voxels/src/Plane.cpp | 42 ++++++---------------------------- 1 file changed, 7 insertions(+), 35 deletions(-) diff --git a/libraries/voxels/src/Plane.cpp b/libraries/voxels/src/Plane.cpp index 10d1e2fb6b..a5dc9a93bf 100755 --- a/libraries/voxels/src/Plane.cpp +++ b/libraries/voxels/src/Plane.cpp @@ -16,34 +16,6 @@ using voxels_lib::printLog; // These are some useful utilities that vec3 is missing -float length(const glm::vec3& v) { - return((float)sqrt(v.x * v.x + v.y * v.y + v.z * v.z)); -} - -void normalize(glm::vec3& v) { - float len; - len = length(v); - if (len) { - v.x /= len;; - v.y /= len; - v.z /= len; - } -} - -// cross product -glm::vec3 crossProduct(const glm::vec3& lhs, const glm::vec3& rhs) { - glm::vec3 result; - result.x = lhs.y * rhs.z - lhs.z * rhs.y; - result.y = lhs.z * rhs.x - lhs.x * rhs.z; - result.z = lhs.x * rhs.y - lhs.y * rhs.x; - return result; -} - - -float innerProduct(const glm::vec3& v1,const glm::vec3& v2) { - return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z); -} - void printVec3(const char* name, const glm::vec3& v) { printf("%s x=%f y=%f z=%f\n", name, v.x, v.y, v.z); } @@ -55,23 +27,23 @@ void Plane::set3Points(const glm::vec3 &v1, const glm::vec3 &v2, const glm::vec3 linev1v3 = v3 - v1; // this will be perpendicular to both lines - _normal = crossProduct(linev1v2,linev1v3); - normalize(_normal); + _normal = glm::cross(linev1v2,linev1v3); + glm::normalize(_normal); // this is a point on the plane _point = v2; // the D coefficient from the form Ax+By+Cz=D - _dCoefficient = -(innerProduct(_normal,_point)); + _dCoefficient = -(glm::dot(_normal,_point)); } void Plane::setNormalAndPoint(const glm::vec3 &normal, const glm::vec3 &point) { _point = point; _normal = normal; - normalize(_normal); + glm::normalize(_normal); // the D coefficient from the form Ax+By+Cz=D - _dCoefficient = -(innerProduct(_normal,_point)); + _dCoefficient = -(glm::dot(_normal,_point)); } void Plane::setCoefficients(float a, float b, float c, float d) { @@ -79,7 +51,7 @@ void Plane::setCoefficients(float a, float b, float c, float d) { _normal = glm::vec3(a,b,c); //compute the lenght of the vector - float l = length(_normal); + float l = glm::length(_normal); // normalize the vector _normal = glm::vec3(a/l,b/l,c/l); @@ -89,7 +61,7 @@ void Plane::setCoefficients(float a, float b, float c, float d) { } float Plane::distance(const glm::vec3 &point) const { - return (_dCoefficient + innerProduct(_normal,point)); + return (_dCoefficient + glm::dot(_normal,point)); } void Plane::print() const {