Merge pull request #183 from ZappoMan/render_voxels_optimization

Render voxels optimization
This commit is contained in:
Philip Rosedale 2013-05-02 22:42:20 -07:00
commit 33b9534e7f
8 changed files with 326 additions and 61 deletions

View file

@ -97,8 +97,26 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
switch(command) {
case PACKET_HEADER_VOXEL_DATA:
{
double start = usecTimestampNow();
// ask the VoxelTree to read the bitstream into the tree
_tree->readBitstreamToTree(voxelData, numBytes - 1);
if (_renderWarningsOn && _tree->getNodesChangedFromBitstream()) {
printLog("readBitstreamToTree()... getNodesChangedFromBitstream=%ld _tree->isDirty()=%s \n",
_tree->getNodesChangedFromBitstream(), (_tree->isDirty() ? "yes" : "no") );
}
double end = usecTimestampNow();
double elapsedmsec = (end - start)/1000.0;
if (_renderWarningsOn && elapsedmsec > 1) {
if (elapsedmsec > 1000) {
double elapsedsec = (end - start)/1000000.0;
printLog("WARNING! readBitstreamToTree() took %lf seconds\n",elapsedsec);
} else {
printLog("WARNING! readBitstreamToTree() took %lf milliseconds\n",elapsedmsec);
}
}
}
break;
case PACKET_HEADER_ERASE_VOXEL:
// ask the tree to read the "remove" bitstream
@ -135,17 +153,48 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
}
void VoxelSystem::setupNewVoxelsForDrawing() {
_voxelsUpdated = newTreeToArrays(_tree->rootNode);
double start = usecTimestampNow();
double sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished);
if (sinceLastTime <= std::max(_setupNewVoxelsForDrawingLastElapsed,SIXTY_FPS_IN_MILLISECONDS)) {
return; // bail early, it hasn't been long enough since the last time we ran
}
if (_tree->isDirty()) {
_callsToTreesToArrays++;
_voxelsUpdated = newTreeToArrays(_tree->rootNode);
_tree->clearDirtyBit(); // after we pull the trees into the array, we can consider the tree clean
} else {
_voxelsUpdated = 0;
}
if (_voxelsUpdated) {
_voxelsDirty=true;
}
// copy the newly written data to the arrays designated for reading
copyWrittenDataToReadArrays();
if (_voxelsDirty) {
// copy the newly written data to the arrays designated for reading
copyWrittenDataToReadArrays();
}
double end = usecTimestampNow();
double elapsedmsec = (end - start)/1000.0;
if (_renderWarningsOn && elapsedmsec > 1) {
if (elapsedmsec > 1000) {
double elapsedsec = (end - start)/1000000.0;
printLog("WARNING! newTreeToArrays() took %lf seconds %ld voxels updated\n", elapsedsec, _voxelsUpdated);
} else {
printLog("WARNING! newTreeToArrays() took %lf milliseconds %ld voxels updated\n", elapsedmsec, _voxelsUpdated);
}
}
_setupNewVoxelsForDrawingLastFinished = end;
_setupNewVoxelsForDrawingLastElapsed = elapsedmsec;
}
void VoxelSystem::copyWrittenDataToReadArrays() {
if (_voxelsDirty) {
double start = usecTimestampNow();
if (_voxelsDirty && _voxelsUpdated) {
// lock on the buffer write lock so we can't modify the data when the GPU is reading it
pthread_mutex_lock(&_bufferWriteLock);
int bytesOfVertices = (_voxelsInArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLfloat);
@ -154,6 +203,18 @@ void VoxelSystem::copyWrittenDataToReadArrays() {
memcpy(_readColorsArray, _writeColorsArray, bytesOfColors );
pthread_mutex_unlock(&_bufferWriteLock);
}
double end = usecTimestampNow();
double elapsedmsec = (end - start)/1000.0;
if (_renderWarningsOn && elapsedmsec > 1) {
if (elapsedmsec > 1000) {
double elapsedsec = (end - start)/1000000.0;
printLog("WARNING! copyWrittenDataToReadArrays() took %lf seconds for %ld voxels %ld updated\n",
elapsedsec, _voxelsInArrays, _voxelsUpdated);
} else {
printLog("WARNING! copyWrittenDataToReadArrays() took %lf milliseconds for %ld voxels %ld updated\n",
elapsedmsec, _voxelsInArrays, _voxelsUpdated);
}
}
}
int VoxelSystem::newTreeToArrays(VoxelNode* node) {
@ -164,7 +225,7 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) {
float childBoundary = boundaryDistanceForRenderLevel(*node->octalCode + 2);
bool inBoundary = (distanceToNode <= boundary);
bool inChildBoundary = (distanceToNode <= childBoundary);
bool shouldRender = node->isColored() && ((node->isLeaf() && inChildBoundary) || (inBoundary && !inChildBoundary));
bool shouldRender = node->isColored() && ((node->isLeaf() && inChildBoundary) || (inBoundary && !inChildBoundary));
node->setShouldRender(shouldRender);
// let children figure out their renderness
@ -213,8 +274,8 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) {
_voxelsInArrays++; // our know vertices in the arrays
}
voxelsUpdated++;
node->clearDirtyBit();
}
node->clearDirtyBit(); // always clear the dirty bit, even if it doesn't need to be rendered
return voxelsUpdated;
}
@ -225,6 +286,11 @@ VoxelSystem* VoxelSystem::clone() const {
void VoxelSystem::init() {
_renderWarningsOn = false;
_callsToTreesToArrays = 0;
_setupNewVoxelsForDrawingLastFinished = 0;
_setupNewVoxelsForDrawingLastElapsed = 0;
// When we change voxels representations in the arrays, we'll update this
_voxelsDirty = false;
_voxelsInArrays = 0;
@ -296,6 +362,7 @@ void VoxelSystem::init() {
}
void VoxelSystem::updateVBOs() {
double start = usecTimestampNow();
if (_voxelsDirty) {
glBufferIndex segmentStart = 0;
glBufferIndex segmentEnd = 0;
@ -327,9 +394,27 @@ void VoxelSystem::updateVBOs() {
}
_voxelsDirty = false;
}
double end = usecTimestampNow();
double elapsedmsec = (end - start)/1000.0;
if (_renderWarningsOn && elapsedmsec > 1) {
if (elapsedmsec > 1) {
if (elapsedmsec > 1000) {
double elapsedsec = (end - start)/1000000.0;
printLog("WARNING! updateVBOs() took %lf seconds after %d calls to newTreeToArrays()\n",
elapsedsec, _callsToTreesToArrays);
} else {
printLog("WARNING! updateVBOs() took %lf milliseconds after %d calls to newTreeToArrays()\n",
elapsedmsec, _callsToTreesToArrays);
}
} else {
printLog("WARNING! updateVBOs() called after %d calls to newTreeToArrays()\n",_callsToTreesToArrays);
}
}
_callsToTreesToArrays = 0; // clear it
}
void VoxelSystem::render() {
double start = usecTimestampNow();
glPushMatrix();
updateVBOs();
// tell OpenGL where to find vertex and color information
@ -362,14 +447,31 @@ void VoxelSystem::render() {
// scale back down to 1 so heads aren't massive
glPopMatrix();
double end = usecTimestampNow();
double elapsedmsec = (end - start)/1000.0;
if (_renderWarningsOn && elapsedmsec > 1) {
if (elapsedmsec > 1000) {
double elapsedsec = (end - start)/1000000.0;
printLog("WARNING! render() took %lf seconds\n",elapsedsec);
} else {
printLog("WARNING! render() took %lf milliseconds\n",elapsedmsec);
}
}
}
int VoxelSystem::_nodeCount = 0;
void VoxelSystem::killLocalVoxels() {
_tree->eraseAllVoxels();
_voxelsInArrays = 0; // better way to do this??
//setupNewVoxelsForDrawing();
}
bool VoxelSystem::randomColorOperation(VoxelNode* node, void* extraData) {
_nodeCount++;
if (node->isColored()) {
nodeColor newColor = { randomColorValue(150), randomColorValue(150), randomColorValue(150), 1 };
nodeColor newColor = { 255, randomColorValue(150), randomColorValue(150), 1 };
node->setColor(newColor);
}
return true;
@ -385,7 +487,7 @@ void VoxelSystem::randomizeVoxelColors() {
bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, void* extraData) {
_nodeCount++;
// always false colorize
node->setFalseColor(randomColorValue(150), randomColorValue(150), randomColorValue(150));
node->setFalseColor(255, randomColorValue(150), randomColorValue(150));
return true; // keep going!
}

View file

@ -58,7 +58,14 @@ public:
void falseColorizeInView(ViewFrustum* viewFrustum);
void falseColorizeDistanceFromView(ViewFrustum* viewFrustum);
void killLocalVoxels();
void setRenderPipelineWarnings(bool on) { _renderWarningsOn = on; };
bool getRenderPipelineWarnings() const { return _renderWarningsOn; };
private:
int _callsToTreesToArrays;
bool _renderWarningsOn;
// Operation functions for tree recursion methods
static int _nodeCount;
static bool randomColorOperation(VoxelNode* node, void* extraData);
@ -83,6 +90,10 @@ private:
unsigned long _voxelsUpdated;
unsigned long _voxelsInArrays;
double _setupNewVoxelsForDrawingLastElapsed;
double _setupNewVoxelsForDrawingLastFinished;
GLuint _vboVerticesID;
GLuint _vboNormalsID;
GLuint _vboColorsID;

View file

@ -130,6 +130,9 @@ glm::vec3 box(WORLD_SIZE,WORLD_SIZE,WORLD_SIZE);
VoxelSystem voxels;
bool wantToKillLocalVoxels = false;
#ifndef _WIN32
Audio audio(&audioScope, &myAvatar);
#endif
@ -140,6 +143,8 @@ Audio audio(&audioScope, &myAvatar);
// Where one's own agent begins in the world (needs to become a dynamic thing passed to the program)
glm::vec3 start_location(6.1f, 0, 1.4f);
bool renderWarningsOn = false; // Whether to show render pipeline warnings
bool statsOn = false; // Whether to show onscreen text overlay with stats
bool starsOn = false; // Whether to display the stars
bool paintOn = false; // Whether to paint voxels as you fly around
@ -1031,6 +1036,14 @@ int setMenu(int state) {
return setValue(state, &::menuOn);
}
int setRenderWarnings(int state) {
int value = setValue(state, &::renderWarningsOn);
if (state == MENU_ROW_PICKED) {
::voxels.setRenderPipelineWarnings(::renderWarningsOn);
}
return value;
}
int setDisplayFrustum(int state) {
return setValue(state, &::frustumOn);
}
@ -1064,6 +1077,13 @@ int setFrustumRenderMode(int state) {
return ::frustumDrawingMode;
}
int doKillLocalVoxels(int state) {
if (state == MENU_ROW_PICKED) {
::wantToKillLocalVoxels = true;
}
return state;
}
int doRandomizeVoxelColors(int state) {
if (state == MENU_ROW_PICKED) {
::voxels.randomizeVoxelColors();
@ -1161,6 +1181,8 @@ void initMenu() {
// Debug
menuColumnDebug = menu.addColumn("Debug");
menuColumnDebug->addRow("Show Render Pipeline Warnings", setRenderWarnings);
menuColumnDebug->addRow("Kill Local Voxels", doKillLocalVoxels);
menuColumnDebug->addRow("Randomize Voxel TRUE Colors", doRandomizeVoxelColors);
menuColumnDebug->addRow("FALSE Color Voxels Randomly", doFalseRandomizeVoxelColors);
menuColumnDebug->addRow("FALSE Color Voxels by Distance", doFalseColorizeByDistance);
@ -1405,6 +1427,12 @@ void* networkReceive(void* args)
ssize_t bytesReceived;
while (!stopNetworkReceiveThread) {
// check to see if the UI thread asked us to kill the voxel tree. since we're the only thread allowed to do that
if (::wantToKillLocalVoxels) {
::voxels.killLocalVoxels();
::wantToKillLocalVoxels = false;
}
if (AgentList::getInstance()->getAgentSocket().receive(&senderAddress, incomingPacket, &bytesReceived)) {
packetCount++;
bytesCount += bytesReceived;

View file

@ -24,4 +24,5 @@ const int COLOR_VALUES_PER_VOXEL = 3 * VERTICES_PER_VOXEL;
typedef unsigned long int glBufferIndex;
const glBufferIndex GLBUFFER_INDEX_UNKNOWN = ULONG_MAX;
const double SIXTY_FPS_IN_MILLISECONDS = 1000.0/60;
#endif

View file

@ -125,7 +125,9 @@ void VoxelNode::setFalseColor(colorPart red, colorPart green, colorPart blue) {
_currentColor[1] = green;
_currentColor[2] = blue;
_currentColor[3] = 1; // XXXBHG - False colors are always considered set
_isDirty = true;
//if (_shouldRender) {
_isDirty = true;
//}
}
}
@ -136,18 +138,24 @@ void VoxelNode::setFalseColored(bool isFalseColored) {
memcpy(&_currentColor,&_trueColor,sizeof(nodeColor));
}
_falseColored = isFalseColored;
_isDirty = true;
//if (_shouldRender) {
_isDirty = true;
//}
}
};
void VoxelNode::setColor(const nodeColor& color) {
if (_trueColor[0] != color[0] || _trueColor[1] != color[1] || _trueColor[2] != color[2]) {
//printLog("VoxelNode::setColor() was: (%d,%d,%d) is: (%d,%d,%d)\n",
// _trueColor[0],_trueColor[1],_trueColor[2],color[0],color[1],color[2]);
memcpy(&_trueColor,&color,sizeof(nodeColor));
if (!_falseColored) {
memcpy(&_currentColor,&color,sizeof(nodeColor));
}
_isDirty = true;
//if (_shouldRender) {
_isDirty = true;
//}
}
}
#endif
@ -234,6 +242,7 @@ bool VoxelNode::isInView(const ViewFrustum& viewFrustum) const {
float VoxelNode::distanceToCamera(const ViewFrustum& viewFrustum) const {
AABox box;
getAABox(box);
box.scale(TREE_SCALE);
float distanceToVoxelCenter = sqrtf(powf(viewFrustum.getPosition().x - (box.getCorner().x + box.getSize().x), 2) +
powf(viewFrustum.getPosition().y - (box.getCorner().y + box.getSize().y), 2) +
powf(viewFrustum.getPosition().z - (box.getCorner().z + box.getSize().z), 2));

View file

@ -35,7 +35,8 @@ VoxelTree::VoxelTree() :
voxelsBytesRead(0),
voxelsCreatedStats(100),
voxelsColoredStats(100),
voxelsBytesReadStats(100) {
voxelsBytesReadStats(100),
_isDirty(true) {
rootNode = new VoxelNode();
rootNode->octalCode = new unsigned char[1];
@ -127,17 +128,29 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode,
// check the colors mask to see if we have a child to color in
if (oneAtBit(*nodeData, i)) {
// create the child if it doesn't exist
if (destinationNode->children[i] == NULL) {
if (!destinationNode->children[i]) {
destinationNode->addChildAtIndex(i);
this->voxelsCreated++;
this->voxelsCreatedStats.updateAverage(1);
if (destinationNode->isDirty()) {
_isDirty = true;
_nodesChangedFromBitstream++;
}
voxelsCreated++;
voxelsCreatedStats.updateAverage(1);
}
// pull the color for this child
nodeColor newColor;
memcpy(newColor, nodeData + bytesRead, 3);
newColor[3] = 1;
bool nodeWasDirty = destinationNode->children[i]->isDirty();
destinationNode->children[i]->setColor(newColor);
bool nodeIsDirty = destinationNode->children[i]->isDirty();
if (nodeIsDirty) {
_isDirty = true;
}
if (!nodeWasDirty && nodeIsDirty) {
_nodesChangedFromBitstream++;
}
this->voxelsColored++;
this->voxelsColoredStats.updateAverage(1);
@ -145,7 +158,15 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode,
}
}
// average node's color based on color of children
bool nodeWasDirty = destinationNode->isDirty();
destinationNode->setColorFromAverageOfChildren();
bool nodeIsDirty = destinationNode->isDirty();
if (nodeIsDirty) {
_isDirty = true;
}
if (!nodeWasDirty && nodeIsDirty) {
_nodesChangedFromBitstream++;
}
// give this destination node the child mask from the packet
unsigned char childMask = *(nodeData + bytesRead);
@ -157,9 +178,17 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode,
// check the exists mask to see if we have a child to traverse into
if (oneAtBit(childMask, childIndex)) {
if (destinationNode->children[childIndex] == NULL) {
if (!destinationNode->children[childIndex]) {
// add a child at that index, if it doesn't exist
bool nodeWasDirty = destinationNode->isDirty();
destinationNode->addChildAtIndex(childIndex);
bool nodeIsDirty = destinationNode->isDirty();
if (nodeIsDirty) {
_isDirty = true;
}
if (!nodeWasDirty && nodeIsDirty) {
_nodesChangedFromBitstream++;
}
this->voxelsCreated++;
this->voxelsCreatedStats.updateAverage(this->voxelsCreated);
}
@ -179,6 +208,8 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode,
void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeBytes) {
int bytesRead = 0;
unsigned char* bitstreamAt = bitstream;
_nodesChangedFromBitstream = 0;
// Keep looping through the buffer calling readNodeData() this allows us to pack multiple root-relative Octal codes
// into a single network packet. readNodeData() basically goes down a tree from the root, and fills things in from there
@ -193,6 +224,10 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, int bufferSizeByt
// Note: we need to create this node relative to root, because we're assuming that the bitstream for the initial
// octal code is always relative to root!
bitstreamRootNode = createMissingNode(rootNode, (unsigned char*) bitstreamAt);
if (bitstreamRootNode->isDirty()) {
_isDirty = true;
_nodesChangedFromBitstream++;
}
}
int octalCodeBytes = bytesRequiredForCodeLength(*bitstreamAt);
@ -403,6 +438,12 @@ void VoxelTree::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) {
}
}
void VoxelTree::createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue) {
unsigned char* voxelData = pointToVoxel(x,y,z,s,red,green,blue);
this->readCodeColorBufferToTree(voxelData);
delete voxelData;
}
void VoxelTree::createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer) {
// About the color of the sphere... we're going to make this sphere be a gradient
// between two RGB colors. We will do the gradient along the phi spectrum
@ -498,10 +539,10 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe
// Keep track of how deep we've searched.
currentSearchLevel++;
// If we've reached our max Search Level, then stop searching.
if (currentSearchLevel >= maxSearchLevel) {
return currentSearchLevel;
}
// If we've passed our max Search Level, then stop searching. return last level searched
if (currentSearchLevel > maxSearchLevel) {
return currentSearchLevel-1;
}
// If we're at a node that is out of view, then we can return, because no nodes below us will be in view!
if (!node->isInView(viewFrustum)) {

View file

@ -46,6 +46,7 @@ public:
void reaverageVoxelColors(VoxelNode *startNode);
void loadVoxelsFile(const char* fileName, bool wantColorRandomizer);
void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer);
void createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue);
void recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData=NULL);
@ -54,6 +55,10 @@ public:
VoxelNodeBag& bag);
int searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag);
bool isDirty() const { return _isDirty; };
void clearDirtyBit() { _isDirty = false; };
unsigned long int getNodesChangedFromBitstream() const { return _nodesChangedFromBitstream; };
private:
int encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel,
@ -68,6 +73,9 @@ private:
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);
bool _isDirty;
unsigned long int _nodesChangedFromBitstream;
};
int boundaryDistanceForRenderLevel(unsigned int renderLevel);

View file

@ -38,15 +38,14 @@ 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 = 20;
int PACKETS_PER_CLIENT_PER_INTERVAL = 20;
const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4;
VoxelTree randomTree;
bool wantColorRandomizer = false;
bool debugViewFrustum = false;
bool viewFrustumCulling = true; // for now
bool debugVoxelSending = false;
void addSphere(VoxelTree * tree,bool random, bool wantColorRandomizer) {
float r = random ? randFloatInRange(0.05,0.1) : 0.25;
@ -76,43 +75,57 @@ bool countVoxelsOperation(VoxelNode* node, void* extraData) {
}
void addSphereScene(VoxelTree * tree, bool wantColorRandomizer) {
printf("adding scene of spheres...\n");
int sphereBaseSize = 512;
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("adding scene of spheres...\n");
int sphereBaseSize = 512;
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");
tree->createSphere(0.030625, (1.0 - 0.030625), (1.0 - 0.030625), 0.06125, (1.0 / (sphereBaseSize * 2)), true, true);
printf("four spheres added...\n");
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);
printf("two spheres added...\n");
tree->createSphere(0.030625, (0.75 - 0.030625), (0.75 - 0.030625), (0.75 - 0.06125), (1.0 / (sphereBaseSize * 2)), true, true);
printf("three spheres added...\n");
tree->createSphere(0.030625, (0.75 - 0.030625), (0.75 - 0.030625), 0.06125, (1.0 / (sphereBaseSize * 2)), true, true);
printf("four spheres added...\n");
tree->createSphere(0.030625, (0.75 - 0.030625), 0.06125, (0.75 - 0.06125), (1.0 / (sphereBaseSize * 2)), true, true);
printf("five spheres added...\n");
tree->createSphere(0.06125, 0.125, 0.125, (0.75 - 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");
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");
float voxelSize = 0.99f/8;
printf("creating corner points...\n");
tree->createVoxel(0 , 0 , 0 , voxelSize, 255, 255 ,255);
tree->createVoxel(1.0 - voxelSize, 0 , 0 , voxelSize, 255, 0 ,0 );
tree->createVoxel(0 , 1.0 - voxelSize, 0 , voxelSize, 0 , 255 ,0 );
tree->createVoxel(0 , 0 , 1.0 - voxelSize, voxelSize, 0 , 0 ,255);
tree->createVoxel(1.0 - voxelSize, 0 , 1.0 - voxelSize, voxelSize, 255, 0 ,255);
tree->createVoxel(0 , 1.0 - voxelSize, 1.0 - voxelSize, voxelSize, 0 , 255 ,255);
tree->createVoxel(1.0 - voxelSize, 1.0 - voxelSize, 1.0 - voxelSize, voxelSize, 255, 255 ,255);
tree->createVoxel(1.0 - voxelSize, 1.0 - voxelSize, 0 , voxelSize, 255, 255 ,0 );
printf("DONE creating corner points...\n");
_nodeCount=0;
tree->recurseTreeWithOperation(countVoxelsOperation);
printf("Nodes after adding scene %d nodes\n", _nodeCount);
printf("DONE adding scene of spheres...\n");
printf("DONE adding scene of spheres...\n");
}
@ -167,8 +180,14 @@ void eraseVoxelTreeAndCleanupAgentVisitData() {
void voxelDistributor(AgentList* agentList, AgentList::iterator& agent, VoxelAgentData* agentData, ViewFrustum& viewFrustum) {
// If the bag is empty, fill it...
if (agentData->nodeBag.isEmpty()) {
bool searchReset = false;
int searchLoops = 0;
int searchLevelWas = agentData->getMaxSearchLevel();
double start = usecTimestampNow();
while (!searchReset && agentData->nodeBag.isEmpty()) {
searchLoops++;
searchLevelWas = agentData->getMaxSearchLevel();
int maxLevelReached = randomTree.searchForColoredNodes(agentData->getMaxSearchLevel(), randomTree.rootNode,
viewFrustum, agentData->nodeBag);
agentData->setMaxLevelReached(maxLevelReached);
@ -177,17 +196,38 @@ void voxelDistributor(AgentList* agentList, AgentList::iterator& agent, VoxelAge
if (agentData->nodeBag.isEmpty()) {
if (agentData->getMaxLevelReached() < agentData->getMaxSearchLevel()) {
agentData->resetMaxSearchLevel();
searchReset = true;
} else {
agentData->incrementMaxSearchLevel();
}
}
}
double end = usecTimestampNow();
double elapsedmsec = (end - start)/1000.0;
if (elapsedmsec > 100) {
if (elapsedmsec > 1000) {
double elapsedsec = (end - start)/1000000.0;
printf("WARNING! searchForColoredNodes() took %lf seconds to identify %d nodes at level %d in %d loops\n",
elapsedsec, agentData->nodeBag.count(), searchLevelWas, searchLoops);
} else {
printf("WARNING! searchForColoredNodes() took %lf milliseconds to identify %d nodes at level %d in %d loops\n",
elapsedmsec, agentData->nodeBag.count(), searchLevelWas, searchLoops);
}
} else if (::debugVoxelSending) {
printf("searchForColoredNodes() took %lf milliseconds to identify %d nodes at level %d in %d loops\n",
elapsedmsec, agentData->nodeBag.count(), searchLevelWas, searchLoops);
}
// If we have something in our nodeBag, then turn them into packets and send them out...
if (!agentData->nodeBag.isEmpty()) {
static unsigned char tempOutputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static
int bytesWritten = 0;
int packetsSentThisInterval = 0;
int truePacketsSent = 0;
int trueBytesSent = 0;
double start = usecTimestampNow();
while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL) {
if (!agentData->nodeBag.isEmpty()) {
VoxelNode* subTree = agentData->nodeBag.extract();
@ -200,6 +240,8 @@ void voxelDistributor(AgentList* agentList, AgentList::iterator& agent, VoxelAge
} else {
agentList->getAgentSocket().send(agent->getActiveSocket(),
agentData->getPacket(), agentData->getPacketLength());
trueBytesSent += agentData->getPacketLength();
truePacketsSent++;
packetsSentThisInterval++;
agentData->resetVoxelPacket();
agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten);
@ -208,12 +250,30 @@ void voxelDistributor(AgentList* agentList, AgentList::iterator& agent, VoxelAge
if (agentData->isPacketWaiting()) {
agentList->getAgentSocket().send(agent->getActiveSocket(),
agentData->getPacket(), agentData->getPacketLength());
trueBytesSent += agentData->getPacketLength();
truePacketsSent++;
agentData->resetVoxelPacket();
}
packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; // done for now, no nodes left
}
}
double end = usecTimestampNow();
double elapsedmsec = (end - start)/1000.0;
if (elapsedmsec > 100) {
if (elapsedmsec > 1000) {
double elapsedsec = (end - start)/1000000.0;
printf("WARNING! packetLoop() took %lf seconds to generate %d bytes in %d packets at level %d, %d nodes still to send\n",
elapsedsec, trueBytesSent, truePacketsSent, searchLevelWas, agentData->nodeBag.count());
} else {
printf("WARNING! packetLoop() took %lf milliseconds to generate %d bytes in %d packets at level %d, %d nodes still to send\n",
elapsedmsec, trueBytesSent, truePacketsSent, searchLevelWas, agentData->nodeBag.count());
}
} else if (::debugVoxelSending) {
printf("packetLoop() took %lf milliseconds to generate %d bytes in %d packets at level %d, %d nodes still to send\n",
elapsedmsec, trueBytesSent, truePacketsSent, searchLevelWas, agentData->nodeBag.count());
}
// if during this last pass, we emptied our bag, then we want to move to the next level.
if (agentData->nodeBag.isEmpty()) {
if (agentData->getMaxLevelReached() < agentData->getMaxSearchLevel()) {
@ -296,13 +356,9 @@ int main(int argc, const char * argv[])
srand((unsigned)time(0));
const char* DEBUG_VIEW_FRUSTUM = "--DebugViewFrustum";
::debugViewFrustum = cmdOptionExists(argc, argv, DEBUG_VIEW_FRUSTUM);
printf("debugViewFrustum=%s\n", (::debugViewFrustum ? "yes" : "no"));
const char* NO_VIEW_FRUSTUM_CULLING = "--NoViewFrustumCulling";
::viewFrustumCulling = !cmdOptionExists(argc, argv, NO_VIEW_FRUSTUM_CULLING);
printf("viewFrustumCulling=%s\n", (::viewFrustumCulling ? "yes" : "no"));
const char* DEBUG_VOXEL_SENDING = "--debugVoxelSending";
::debugVoxelSending = cmdOptionExists(argc, argv, DEBUG_VOXEL_SENDING);
printf("debugVoxelSending=%s\n", (::debugVoxelSending ? "yes" : "no"));
const char* WANT_COLOR_RANDOMIZER = "--wantColorRandomizer";
::wantColorRandomizer = cmdOptionExists(argc, argv, WANT_COLOR_RANDOMIZER);
@ -315,6 +371,17 @@ int main(int argc, const char * argv[])
if (voxelsFilename) {
randomTree.loadVoxelsFile(voxelsFilename,wantColorRandomizer);
}
// Check to see if the user passed in a command line option for setting packet send rate
const char* PACKETS_PER_SECOND = "--packetsPerSecond";
const char* packetsPerSecond = getCmdOption(argc, argv, PACKETS_PER_SECOND);
if (packetsPerSecond) {
PACKETS_PER_CLIENT_PER_INTERVAL = atoi(packetsPerSecond)/10;
if (PACKETS_PER_CLIENT_PER_INTERVAL < 1) {
PACKETS_PER_CLIENT_PER_INTERVAL = 1;
}
printf("packetsPerSecond=%s PACKETS_PER_CLIENT_PER_INTERVAL=%d\n", packetsPerSecond, PACKETS_PER_CLIENT_PER_INTERVAL);
}
const char* ADD_RANDOM_VOXELS = "--AddRandomVoxels";
if (cmdOptionExists(argc, argv, ADD_RANDOM_VOXELS)) {
@ -380,8 +447,6 @@ int main(int argc, const char * argv[])
delete []vertices;
randomTree.readCodeColorBufferToTree(pVoxelData);
//printf("readCodeColorBufferToTree() of size=%d atByte=%d receivedBytes=%ld\n",
// voxelDataSize,atByte,receivedBytes);
// skip to next
pVoxelData+=voxelDataSize;
atByte+=voxelDataSize;