Merge pull request #96 from ZappoMan/view_frustum_work

Working on False Color Support & LOD Bug fix
This commit is contained in:
Philip Rosedale 2013-04-22 08:53:05 -07:00
commit 6286e1b54f
16 changed files with 851 additions and 308 deletions

View file

@ -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\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.getCorner())) {
// 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();
}

View file

@ -14,6 +14,7 @@
#include <UDPSocket.h>
#include <AgentData.h>
#include <VoxelTree.h>
#include <ViewFrustum.h>
#include "Head.h"
#include "Util.h"
#include "world.h"
@ -44,7 +45,27 @@ public:
float getVoxelsColoredPerSecondAverage();
float getVoxelsBytesReadPerSecondAverage();
// 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();
};

View file

@ -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];
@ -555,34 +559,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 +578,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 +637,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 +835,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 +929,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);
@ -1090,6 +1109,46 @@ 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 doFalseColorizeByDistance(int state) {
if (state == MENU_ROW_PICKED) {
loadViewFrustum(::viewFrustum);
voxels.falseColorizeDistanceFromView(&::viewFrustum);
}
return state;
}
int doFalseColorizeInView(int state) {
if (state == MENU_ROW_PICKED) {
loadViewFrustum(::viewFrustum);
// we probably want to make sure the viewFrustum is initialized first
voxels.falseColorizeInView(&::viewFrustum);
}
return state;
}
const char* modeAll = " - All ";
const char* modeVectors = " - Vectors ";
const char* modePlanes = " - Planes ";
@ -1144,7 +1203,11 @@ void initMenu() {
// Debug
menuColumnDebug = menu.addColumn("Debug");
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("Show TRUE Colors", doTrueVoxelColors);
}
void testPointToVoxel()
@ -1308,7 +1371,7 @@ void key(unsigned char k, int x, int y)
// if (k == '\\') ViewFrustum::fovAngleAdust += 0.05;
if (k == 'R') setFrustumRenderMode(MENU_ROW_PICKED);
if (k == '&') {
::paintOn = !::paintOn; // toggle paint
::setupPaintingVoxel(); // also randomizes colors

View file

@ -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;
}

View file

@ -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__) */

View file

@ -1,76 +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);
void AABox::scale(float scale) {
_corner = _corner*scale;
_size = _size*scale;
}
AABox::AABox(void) {
corner.x = 0; corner.y = 0; corner.z = 0;
x = 1.0f;
y = 1.0f;
z = 1.0f;
}
AABox::~AABox() {}
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);
}

View file

@ -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,18 +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;
};

View file

@ -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 <stdio.h>
@ -10,78 +16,55 @@
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));
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 vec3_normalize(glm::vec3& v) {
float len;
len = vec3_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);
}
Plane::Plane(const glm::vec3 &v1, const glm::vec3 &v2, const glm::vec3 &v3) {
set3Points(v1,v2,v3);
}
Plane::Plane() {}
Plane::~Plane() {}
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 = glm::cross(linev1v2,linev1v3);
glm::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 = -(glm::dot(_normal,_point));
}
void Plane::setNormalAndPoint(const glm::vec3 &normal, const glm::vec3 &point) {
_point = point;
_normal = normal;
glm::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 = -(glm::dot(_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 = glm::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 + glm::dot(_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);
}

View file

@ -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 <glm/glm.hpp>
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;
};

View file

@ -53,102 +53,126 @@ 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);
// 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);
}
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) {
//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(const glm::vec3& point) {
int result = INSIDE;
for(int i=0; i < 6; i++) {
if (this->_planes[i].distance(p) < 0)
if (_planes[i].distance(point) < 0) {
return OUTSIDE;
}
}
return(result);
}
int ViewFrustum::sphereInFrustum(glm::vec3 &center, float radius) {
int ViewFrustum::sphereInFrustum(const glm::vec3& center, 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)
@ -158,13 +182,39 @@ int ViewFrustum::sphereInFrustum(glm::vec3 &center, float radius) {
}
int ViewFrustum::boxInFrustum(AABox &b) {
int ViewFrustum::boxInFrustum(const AABox& box) {
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++) {
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].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].getNormal();
glm::vec3 boxVertexP = box.getVertexP(normal);
float planeToBoxVertexPDistance = _planes[i].distance(boxVertexP);
glm::vec3 boxVertexN = box.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);
}

View file

@ -45,15 +45,23 @@ 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; }
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; }
@ -86,9 +94,9 @@ public:
enum {OUTSIDE, INTERSECT, INSIDE};
int pointInFrustum(glm::vec3 &p);
int sphereInFrustum(glm::vec3 &center, 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);
};

View file

@ -6,17 +6,23 @@
//
//
#include <stdio.h>
#include <cstring>
#include "SharedUtil.h"
//#include "voxels_Log.h"
#include "VoxelNode.h"
#include "OctalCode.h"
#include "AABox.h"
// using voxels_lib::printLog;
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++) {
children[i] = NULL;
@ -28,10 +34,27 @@ 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 {
glm::vec3 corner;
glm::vec3 size;
// copy corner into box
copyFirstVertexForCode(octalCode,(float*)&corner);
// this tells you the "size" of the voxel
float voxelScale = 1 / powf(2, *octalCode);
size = glm::vec3(voxelScale,voxelScale,voxelScale);
box.setBox(corner,size);
}
void VoxelNode::addChildAtIndex(int childIndex) {
children[childIndex] = new VoxelNode();
@ -43,30 +66,60 @@ 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);
}
// 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;
_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));
}
}
#endif
// will detect if children are leaves AND the same color
// and in that case will delete the children and make this node
// a leaf, returns TRUE if all the leaves are collapsed into a
@ -77,16 +130,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 +154,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);
}

View file

@ -9,7 +9,18 @@
#ifndef __hifi__VoxelNode__
#define __hifi__VoxelNode__
#include "AABox.h"
typedef unsigned char colorPart;
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();
@ -20,8 +31,27 @@ public:
bool collapseIdenticalLeaves();
unsigned char *octalCode;
unsigned char color[4];
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;
};
#endif /* defined(__hifi__VoxelNode__) */

View file

@ -66,6 +66,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) {
@ -127,8 +148,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.updateAverage(1);
@ -233,8 +256,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,
@ -273,7 +299,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];
@ -317,10 +343,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
@ -358,9 +384,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];
@ -370,6 +406,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,
@ -437,7 +474,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));
}
}
@ -446,9 +483,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]);
}
}
}

View file

@ -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:
// when a voxel is created in the tree (object new'd)
@ -53,7 +56,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);

View file

@ -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})
link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR})
# find required libraries
find_package(GLM REQUIRED)