diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 7ed31ec7cc..3920522503 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -63,11 +63,6 @@ void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) setupNewVoxelsForDrawing(); } -void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer) { - _tree->createSphere(r, xc, yc, zc, s, solid, wantColorRandomizer); - setupNewVoxelsForDrawing(); -} - long int VoxelSystem::getVoxelsCreated() { return _tree->voxelsCreated; } diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 97d5fa1518..f3968004b0 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -42,7 +42,6 @@ public: void setViewerAvatar(Avatar *newViewerAvatar) { _viewerAvatar = newViewerAvatar; }; void setCamera(Camera* newCamera) { _camera = newCamera; }; void loadVoxelsFile(const char* fileName,bool wantColorRandomizer); - void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer); long int getVoxelsCreated(); long int getVoxelsColored(); diff --git a/interface/src/main.cpp b/interface/src/main.cpp index b31438e03d..b1e06b9da6 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -1428,23 +1428,6 @@ void setupPaintingVoxel() { shiftPaintingColor(); } -void addRandomSphere(bool wantColorRandomizer) { - float r = randFloatInRange(0.05,0.1); - float xc = randFloatInRange(r,(1-r)); - float yc = randFloatInRange(r,(1-r)); - float zc = randFloatInRange(r,(1-r)); - float s = 0.001; // size of voxels to make up surface of sphere - bool solid = false; - - printLog("random sphere\n"); - printLog("radius=%f\n",r); - printLog("xc=%f\n",xc); - printLog("yc=%f\n",yc); - printLog("zc=%f\n",zc); - - voxels.createSphere(r,xc,yc,zc,s,solid,wantColorRandomizer); -} - const float KEYBOARD_YAW_RATE = 0.8; const float KEYBOARD_PITCH_RATE = 0.6; const float KEYBOARD_STRAFE_RATE = 0.03; diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 7c8f7f5e9b..1ba8e8ddef 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -170,7 +170,7 @@ bool cmdOptionExists(int argc, const char * argv[],const char* option) { // Complaints: Brad :) #define GUESS_OF_VOXELCODE_SIZE 10 #define MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE 1500 -#define SIZE_OF_COLOR_DATA 3 +#define SIZE_OF_COLOR_DATA sizeof(rgbColor) bool createVoxelEditMessage(unsigned char command, short int sequence, int voxelCount, VoxelDetail* voxelDetails, unsigned char*& bufferOut, int& sizeOut) { @@ -231,27 +231,26 @@ bool createVoxelEditMessage(unsigned char command, short int sequence, unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r, unsigned char g, unsigned char b ) { float xTest, yTest, zTest, sTest; - xTest = yTest = zTest = sTest = 0.5; + xTest = yTest = zTest = sTest = 0.5f; // First determine the voxelSize that will properly encode a // voxel of size S. - int voxelSizeInBits = 0; + unsigned int voxelSizeInOctets = 1; while (sTest > s) { sTest /= 2.0; - voxelSizeInBits+=3; + voxelSizeInOctets++; } - unsigned int voxelSizeInBytes = (voxelSizeInBits/8)+1; - unsigned int voxelSizeInOctets = (voxelSizeInBits/3); - unsigned int voxelBufferSize = voxelSizeInBytes+1+3; // 1 for size, 3 for color + unsigned int voxelSizeInBytes = bytesRequiredForCodeLength(voxelSizeInOctets); // (voxelSizeInBits/8)+1; + unsigned int voxelBufferSize = voxelSizeInBytes + sizeof(rgbColor); // 3 for color // allocate our resulting buffer unsigned char* voxelOut = new unsigned char[voxelBufferSize]; - + // first byte of buffer is always our size in octets voxelOut[0]=voxelSizeInOctets; - sTest = 0.5; // reset sTest so we can do this again. + sTest = 0.5f; // reset sTest so we can do this again. unsigned char byte = 0; // we will be adding coding bits here int bitInByteNDX = 0; // keep track of where we are in byte as we go @@ -260,7 +259,7 @@ unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r, // Now we actually fill out the voxel code while (octetsDone < voxelSizeInOctets) { - if (x > xTest) { + if (x >= xTest) { // byte = (byte << 1) | true; xTest += sTest/2.0; @@ -272,14 +271,14 @@ unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r, bitInByteNDX++; // If we've reached the last bit of the byte, then we want to copy this byte // into our buffer. And get ready to start on a new byte - if (bitInByteNDX > 7) { + if (bitInByteNDX == 8) { voxelOut[byteNDX]=byte; byteNDX++; bitInByteNDX=0; byte=0; } - if (y > yTest) { + if (y >= yTest) { // byte = (byte << 1) | true; yTest += sTest/2.0; @@ -291,14 +290,14 @@ unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r, bitInByteNDX++; // If we've reached the last bit of the byte, then we want to copy this byte // into our buffer. And get ready to start on a new byte - if (bitInByteNDX > 7) { + if (bitInByteNDX == 8) { voxelOut[byteNDX]=byte; byteNDX++; bitInByteNDX=0; byte=0; } - if (z > zTest) { + if (z >= zTest) { // byte = (byte << 1) | true; zTest += sTest/2.0; @@ -310,7 +309,7 @@ unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r, bitInByteNDX++; // If we've reached the last bit of the byte, then we want to copy this byte // into our buffer. And get ready to start on a new byte - if (bitInByteNDX > 7) { + if (bitInByteNDX == 8) { voxelOut[byteNDX]=byte; byteNDX++; bitInByteNDX=0; @@ -323,13 +322,13 @@ unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r, // If we've got here, and we didn't fill the last byte, we need to zero pad this // byte before we copy it into our buffer. - if (bitInByteNDX > 0 && bitInByteNDX < 7) { + if (bitInByteNDX > 0 && bitInByteNDX < 8) { // Pad the last byte - while (bitInByteNDX <= 7) { + while (bitInByteNDX < 8) { byte = (byte << 1) | false; bitInByteNDX++; } - + // Copy it into our output buffer voxelOut[byteNDX]=byte; byteNDX++; diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 1b40de5448..9d2fcb8799 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -18,6 +18,8 @@ #include #endif +typedef unsigned char rgbColor[3]; + static const float ZERO = 0.0f; static const float ONE = 1.0f; static const float ONE_HALF = 0.5f; diff --git a/libraries/voxels/src/SceneUtils.cpp b/libraries/voxels/src/SceneUtils.cpp new file mode 100644 index 0000000000..da92734350 --- /dev/null +++ b/libraries/voxels/src/SceneUtils.cpp @@ -0,0 +1,106 @@ +// +// SceneUtils.cpp +// hifi +// +// Created by Brad Hefta-Gaub on 5/7/2013. +// +// + +#include "SceneUtils.h" +#include + +void addCornersAndAxisLines(VoxelTree* tree) { + // We want our corner voxels to be about 1/2 meter high, and our TREE_SCALE is in meters, so... + float voxelSize = 0.5f / TREE_SCALE; + + // Now some more examples... a little more complex + 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, 0 , voxelSize, 255, 255 ,0 ); + tree->createVoxel(1.0 - voxelSize, 1.0 - voxelSize, 1.0 - voxelSize, voxelSize, 255, 255 ,255); + printf("DONE creating corner points...\n"); + + // Now some more examples... creating some lines using the line primitive + printf("creating voxel lines...\n"); + // We want our line voxels to be about 1/32 meter high, and our TREE_SCALE is in meters, so... + float lineVoxelSize = 1.f / (32 * TREE_SCALE); + rgbColor red = {255, 0, 0}; + rgbColor green = {0, 255, 0}; + rgbColor blue = {0, 0, 255}; + tree->createLine(glm::vec3(0, 0, 0), glm::vec3(0, 0, 1), lineVoxelSize, blue); + tree->createLine(glm::vec3(0, 0, 0), glm::vec3(1, 0, 0), lineVoxelSize, red); + tree->createLine(glm::vec3(0, 0, 0), glm::vec3(0, 1, 0), lineVoxelSize, green); + printf("DONE creating lines...\n"); +} + +void addSphereScene(VoxelTree * tree) { + printf("adding sphere scene...\n"); + + // Now some more examples... creating some spheres using the sphere primitive + // We want the smallest unit of our spheres to be about 1/16th of a meter tall + float sphereVoxelSize = 1.f / (8 * TREE_SCALE); + printf("creating spheres... sphereVoxelSize=%f\n",sphereVoxelSize); + + tree->createSphere(0.030625, 0.5, 0.5, (0.25 - 0.06125), sphereVoxelSize, true, NATURAL); + printf("1 spheres added... sphereVoxelSize=%f\n",sphereVoxelSize); + tree->createSphere(0.030625, (0.75 - 0.030625), (0.75 - 0.030625), (0.75 - 0.06125), sphereVoxelSize, true, GRADIENT); + printf("2 spheres added... sphereVoxelSize=%f\n",sphereVoxelSize); + tree->createSphere(0.030625, (0.75 - 0.030625), (0.75 - 0.030625), 0.06125, sphereVoxelSize, true, RANDOM); + printf("3 spheres added... sphereVoxelSize=%f\n",sphereVoxelSize); + tree->createSphere(0.030625, (0.75 - 0.030625), 0.06125, (0.75 - 0.06125), sphereVoxelSize, true, GRADIENT); + printf("4 spheres added... sphereVoxelSize=%f\n",sphereVoxelSize); + tree->createSphere(0.06125, 0.125, 0.125, (0.75 - 0.125), sphereVoxelSize, true, GRADIENT); + +/** + float radius = 0.0125f; + printf("5 spheres added...\n"); + tree->createSphere(radius, 0.25, radius * 5.0f, 0.25, sphereVoxelSize, true, GRADIENT); + printf("6 spheres added...\n"); + tree->createSphere(radius, 0.125, radius * 5.0f, 0.25, sphereVoxelSize, true, RANDOM); + printf("7 spheres added...\n"); + tree->createSphere(radius, 0.075, radius * 5.0f, 0.25, sphereVoxelSize, true, GRADIENT); + printf("8 spheres added...\n"); + tree->createSphere(radius, 0.05, radius * 5.0f, 0.25, sphereVoxelSize, true, RANDOM); + printf("9 spheres added...\n"); + tree->createSphere(radius, 0.025, radius * 5.0f, 0.25, sphereVoxelSize, true, GRADIENT); + printf("10 spheres added...\n"); +*/ + float largeRadius = 0.1875f; + tree->createSphere(largeRadius, 0.5, 0.5, 0.5, sphereVoxelSize, true, NATURAL); + printf("11 - last large sphere added... largeRadius=%f sphereVoxelSize=%f\n", largeRadius, sphereVoxelSize); + + printf("DONE adding scene of spheres...\n"); +} + +void addSurfaceScene(VoxelTree * tree) { + printf("adding surface scene...\n"); + float voxelSize = 1.f / (8 * TREE_SCALE); + + // color 1= blue, color 2=green + unsigned char r1, g1, b1, r2, g2, b2, red, green, blue; + r1 = r2 = b2 = g1 = 0; + b1 = g2 = 255; + + for (float x = 0.0; x < 1.0; x += voxelSize) { + for (float z = 0.0; z < 1.0; z += voxelSize) { + + glm::vec2 position = glm::vec2(x, z); + float perlin = glm::perlin(position) + .25f * glm::perlin(position * 4.f) + .125f * glm::perlin(position * 16.f); + float gradient = (1.0f + perlin)/ 2.0f; + red = (unsigned char)std::min(255, std::max(0, (int)(r1 + ((r2 - r1) * gradient)))); + green = (unsigned char)std::min(255, std::max(0, (int)(g1 + ((g2 - g1) * gradient)))); + blue = (unsigned char)std::min(255, std::max(0, (int)(b1 + ((b2 - b1) * gradient)))); + + int height = (4 * gradient)+1; // make it at least 4 thick, so we get some averaging + for (int i = 0; i < height; i++) { + tree->createVoxel(x, ((i+1) * voxelSize) , z, voxelSize, red, green, blue); + } + } + } + printf("DONE adding surface scene...\n"); +} diff --git a/libraries/voxels/src/SceneUtils.h b/libraries/voxels/src/SceneUtils.h new file mode 100644 index 0000000000..378382f51f --- /dev/null +++ b/libraries/voxels/src/SceneUtils.h @@ -0,0 +1,20 @@ +// +// SceneUtils.h +// hifi +// +// Created by Brad Hefta-Gaub on 5/7/2013. +// +// + +#ifndef __hifi__SceneUtil__ +#define __hifi__SceneUtil__ + +#include "VoxelTree.h" +#include + +void addCornersAndAxisLines(VoxelTree* tree); +void addSphereScene(VoxelTree * tree); +void addSurfaceScene(VoxelTree * tree); + + +#endif /* defined(__hifi__SceneUtil__) */ diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index 41007a47c7..9df2cdbc5e 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -14,12 +14,12 @@ #include -const int TREE_SCALE = 100; +const int TREE_SCALE = 128; const int NUMBER_OF_CHILDREN = 8; const int MAX_VOXEL_PACKET_SIZE = 1492; const int MAX_TREE_SLICE_BYTES = 26; -const int MAX_VOXELS_PER_SYSTEM = 250000; +const int MAX_VOXELS_PER_SYSTEM = 500000; const int VERTICES_PER_VOXEL = 24; const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL; const int INDICES_PER_VOXEL = 3 * 12; diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 95e71b2b76..02f1592126 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -123,7 +123,6 @@ void VoxelNode::setColorFromAverageOfChildren() { 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 @@ -179,9 +178,7 @@ void VoxelNode::setColor(const nodeColor& color) { if (!_falseColored) { memcpy(&_currentColor,&color,sizeof(nodeColor)); } - //if (_shouldRender) { - _isDirty = true; - //} + _isDirty = true; } } #endif diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 49e1f7596c..0c605aee62 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -22,10 +22,12 @@ #include // to load voxels from file #include "VoxelConstants.h" +#include + using voxels_lib::printLog; int boundaryDistanceForRenderLevel(unsigned int renderLevel) { - float voxelSizeScale = 500.0*TREE_SCALE; + float voxelSizeScale = 50000.0f; return voxelSizeScale / powf(2, renderLevel); } @@ -113,9 +115,7 @@ VoxelNode* VoxelTree::createMissingNode(VoxelNode* lastParentNode, unsigned char } } -int VoxelTree::readNodeData(VoxelNode* destinationNode, - unsigned char* nodeData, - int bytesLeftToRead) { +int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, int bytesLeftToRead) { // instantiate variable for bytes already read int bytesRead = 1; for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { @@ -457,87 +457,136 @@ void VoxelTree::createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, r } void VoxelTree::createSphere(float radius, float xc, float yc, float zc, float voxelSize, - bool solid, bool wantColorRandomizer, bool debug) { + bool solid, creationMode mode, bool debug) { - // 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 - unsigned char dominantColor1 = randIntInRange(1, 3); //1=r, 2=g, 3=b dominant - unsigned char dominantColor2 = randIntInRange(1, 3); + bool wantColorRandomizer = (mode == RANDOM); + bool wantNaturalSurface = (mode == NATURAL); + bool wantNaturalColor = (mode == NATURAL); - if (dominantColor1 == dominantColor2) { - dominantColor2 = dominantColor1 + 1 % 3; + // About the color of the sphere... we're going to make this sphere be a mixture of two colors + // in NATURAL mode, those colors will be green dominant and blue dominant. In GRADIENT mode we + // will randomly pick which color family red, green, or blue to be dominant. In RANDOM mode we + // ignore these dominant colors and make every voxel a completely random color. + unsigned char r1, g1, b1, r2, g2, b2; + + if (wantNaturalColor) { + r1 = r2 = b2 = g1 = 0; + b1 = g2 = 255; + } else if (!wantColorRandomizer) { + unsigned char dominantColor1 = randIntInRange(1, 3); //1=r, 2=g, 3=b dominant + unsigned char dominantColor2 = randIntInRange(1, 3); + + if (dominantColor1 == dominantColor2) { + dominantColor2 = dominantColor1 + 1 % 3; + } + + r1 = (dominantColor1 == 1) ? randIntInRange(200, 255) : randIntInRange(40, 100); + g1 = (dominantColor1 == 2) ? randIntInRange(200, 255) : randIntInRange(40, 100); + b1 = (dominantColor1 == 3) ? randIntInRange(200, 255) : randIntInRange(40, 100); + r2 = (dominantColor2 == 1) ? randIntInRange(200, 255) : randIntInRange(40, 100); + g2 = (dominantColor2 == 2) ? randIntInRange(200, 255) : randIntInRange(40, 100); + b2 = (dominantColor2 == 3) ? randIntInRange(200, 255) : randIntInRange(40, 100); } - unsigned char r1 = (dominantColor1 == 1) ? randIntInRange(200, 255) : randIntInRange(40, 100); - unsigned char g1 = (dominantColor1 == 2) ? randIntInRange(200, 255) : randIntInRange(40, 100); - unsigned char b1 = (dominantColor1 == 3) ? randIntInRange(200, 255) : randIntInRange(40, 100); - unsigned char r2 = (dominantColor2 == 1) ? randIntInRange(200, 255) : randIntInRange(40, 100); - unsigned char g2 = (dominantColor2 == 2) ? randIntInRange(200, 255) : randIntInRange(40, 100); - unsigned char b2 = (dominantColor2 == 3) ? randIntInRange(200, 255) : randIntInRange(40, 100); - - // We initialize our rgb to be either "grey" in case of randomized surface, or - // the average of the gradient, in the case of the gradient sphere. + // We initialize our rgb to be either "grey" in case of randomized surface, or + // the average of the gradient, in the case of the gradient sphere. unsigned char red = wantColorRandomizer ? 128 : (r1 + r2) / 2; // average of the colors unsigned char green = wantColorRandomizer ? 128 : (g1 + g2) / 2; unsigned char blue = wantColorRandomizer ? 128 : (b1 + b2) / 2; - - // Psuedocode for creating a sphere: - // - // for (theta from 0 to 2pi): - // for (phi from 0 to pi): - // x = xc+r*cos(theta)*sin(phi) - // y = yc+r*sin(theta)*sin(phi) - // z = zc+r*cos(phi) - // assume solid for now - float thisRadius = 0.0; - float thisVoxelSize = radius / 4.0f; - - if (!solid) { - thisRadius = radius; // just the outer surface - thisVoxelSize = voxelSize; - } - - // If you also iterate form the interior of the sphere to the radius, makeing - // larger and larger sphere'voxelSize you'd end up with a solid sphere. And lots of voxels! - while (thisRadius <= (radius + (voxelSize / 2.0))) { - if (debug) { - printLog("radius: thisRadius=%f thisVoxelSize=%f thisRadius+thisVoxelSize=%f (radius+(voxelSize/2.0))=%f\n", - thisRadius, thisVoxelSize, thisRadius+thisVoxelSize, (radius + (voxelSize / 2.0))); - } + // I want to do something smart like make these inside circles with bigger voxels, but this doesn't seem to work. + float thisVoxelSize = voxelSize; // radius / 2.0f; + float thisRadius = 0.0; + if (!solid) { + thisRadius = radius; // just the outer surface + thisVoxelSize = voxelSize; + } + + // If you also iterate form the interior of the sphere to the radius, making + // larger and larger spheres you'd end up with a solid sphere. And lots of voxels! + bool lastLayer = false; + while (!lastLayer) { + lastLayer = (thisRadius + (voxelSize * 2.0) >= radius); + // We want to make sure that as we "sweep" through our angles we use a delta angle that voxelSize // small enough to not skip any voxels we can calculate theta from our desired arc length // lenArc = ndeg/360deg * 2pi*R ---> lenArc = theta/2pi * 2pi*R // lenArc = theta*R ---> theta = lenArc/R ---> theta = g/r float angleDelta = (thisVoxelSize / thisRadius); - for (float theta=0.0; theta <= 2 * M_PI; theta += angleDelta) { - for (float phi=0.0; phi <= M_PI; phi += angleDelta) { - float x = xc + thisRadius * cos(theta) * sin(phi); - float y = yc + thisRadius * sin(theta) * sin(phi); - float z = zc + thisRadius * cos(phi); - - // gradient color data - float gradient = (phi / M_PI); - - // only use our actual desired color on the outer edge, otherwise - // use our "average" color - if (thisRadius + (voxelSize * 2.0) >= radius) { - //printLog("painting candy shell radius: thisRadius=%f radius=%f\n",thisRadius,radius); - red = wantColorRandomizer ? randomColorValue(165) : r1 + ((r2 - r1) * gradient); - green = wantColorRandomizer ? randomColorValue(165) : g1 + ((g2 - g1) * gradient); - blue = wantColorRandomizer ? randomColorValue(165) : b1 + ((b2 - b1) * gradient); - } - - unsigned char* voxelData = pointToVoxel(x, y, z, thisVoxelSize, red, green, blue); - this->readCodeColorBufferToTree(voxelData); - delete voxelData; - } - } + if (debug) { + int percentComplete = 100 * (thisRadius/radius); + printLog("percentComplete=%d\n",percentComplete); + } + + for (float theta=0.0; theta <= 2 * M_PI; theta += angleDelta) { + for (float phi=0.0; phi <= M_PI; phi += angleDelta) { + bool naturalSurfaceRendered = false; + float x = xc + thisRadius * cos(theta) * sin(phi); + float y = yc + thisRadius * sin(theta) * sin(phi); + float z = zc + thisRadius * cos(phi); + + // if we're on the outer radius, then we do a couple of things differently. + // 1) If we're in NATURAL mode we will actually draw voxels from our surface outward (from the surface) up + // some random height. This will give our sphere some contours. + // 2) In all modes, we will use our "outer" color to draw the voxels. Otherwise we will use the average color + if (lastLayer) { + if (false && debug) { + printLog("adding candy shell: theta=%f phi=%f thisRadius=%f radius=%f\n", + theta, phi, thisRadius,radius); + } + switch (mode) { + case RANDOM: { + red = randomColorValue(165); + green = randomColorValue(165); + blue = randomColorValue(165); + } break; + case GRADIENT: { + float gradient = (phi / M_PI); + red = r1 + ((r2 - r1) * gradient); + green = g1 + ((g2 - g1) * gradient); + blue = b1 + ((b2 - b1) * gradient); + } break; + case NATURAL: { + glm::vec3 position = glm::vec3(theta,phi,radius); + float perlin = glm::perlin(position) + .25f * glm::perlin(position * 4.f) + + .125f * glm::perlin(position * 16.f); + float gradient = (1.0f + perlin)/ 2.0f; + red = (unsigned char)std::min(255, std::max(0, (int)(r1 + ((r2 - r1) * gradient)))); + green = (unsigned char)std::min(255, std::max(0, (int)(g1 + ((g2 - g1) * gradient)))); + blue = (unsigned char)std::min(255, std::max(0, (int)(b1 + ((b2 - b1) * gradient)))); + if (debug) { + printLog("perlin=%f gradient=%f color=(%d,%d,%d)\n",perlin, gradient, red, green, blue); + } + } break; + } + if (wantNaturalSurface) { + // for natural surfaces, we will render up to 16 voxel's above the surface of the sphere + glm::vec3 position = glm::vec3(theta,phi,radius); + float perlin = glm::perlin(position) + .25f * glm::perlin(position * 4.f) + + .125f * glm::perlin(position * 16.f); + float gradient = (1.0f + perlin)/ 2.0f; + + int height = (4 * gradient)+1; // make it at least 4 thick, so we get some averaging + float subVoxelScale = thisVoxelSize; + for (int i = 0; i < height; i++) { + x = xc + (thisRadius + i * subVoxelScale) * cos(theta) * sin(phi); + y = yc + (thisRadius + i * subVoxelScale) * sin(theta) * sin(phi); + z = zc + (thisRadius + i * subVoxelScale) * cos(phi); + this->createVoxel(x, y, z, subVoxelScale, red, green, blue); + } + naturalSurfaceRendered = true; + } + } + if (!naturalSurfaceRendered) { + this->createVoxel(x, y, z, thisVoxelSize, red, green, blue); + } + } + } thisRadius += thisVoxelSize; - thisVoxelSize = std::max(voxelSize, thisVoxelSize / 2.0f); - } - this->reaverageVoxelColors(this->rootNode); + thisVoxelSize = std::max(voxelSize, thisVoxelSize / 2.0f); + } + this->reaverageVoxelColors(this->rootNode); } int VoxelTree::searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag) { @@ -923,3 +972,13 @@ void VoxelTree::writeToFileV2(const char* fileName) const { file.close(); } +unsigned long VoxelTree::getVoxelCount() { + unsigned long nodeCount = 0; + recurseTreeWithOperation(countVoxelsOperation, &nodeCount); + return nodeCount; +} + +bool VoxelTree::countVoxelsOperation(VoxelNode* node, void* extraData) { + (*(unsigned long*)extraData)++; + return true; // keep going +} diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 421e14ace7..319b4aed95 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -17,6 +17,7 @@ // Callback function, for recuseTreeWithOperation typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, void* extraData); +typedef enum {GRADIENT, RANDOM, NATURAL} creationMode; class VoxelTree { public: @@ -49,7 +50,7 @@ public: VoxelNode* getVoxelAt(float x, float y, float z, float s) const; void createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue); void createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color); - void createSphere(float r,float xc, float yc, float zc, float s, bool solid, bool wantColorRandomizer, bool debug = false); + void createSphere(float r,float xc, float yc, float zc, float s, bool solid, creationMode mode, bool debug = false); void recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData=NULL); @@ -70,6 +71,8 @@ public: // these will read/write files that match the wireformat, excluding the 'V' leading void writeToFileV2(const char* filename) const; bool readFromFileV2(const char* filename); + + unsigned long getVoxelCount(); private: int encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, @@ -79,6 +82,8 @@ private: int searchForColoredNodesRecursion(int maxSearchLevel, int& currentSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag); + static bool countVoxelsOperation(VoxelNode* node, void* extraData); + void recurseNodeWithOperation(VoxelNode* node, RecurseVoxelTreeOperation operation, void* extraData); VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode) const; VoxelNode* createMissingNode(VoxelNode* lastParentNode, unsigned char* deepestCodeToCreate); diff --git a/voxel-edit/src/main.cpp b/voxel-edit/src/main.cpp index d93effc7fd..6e193315e1 100644 --- a/voxel-edit/src/main.cpp +++ b/voxel-edit/src/main.cpp @@ -8,6 +8,7 @@ #include #include +#include VoxelTree myTree; @@ -28,7 +29,7 @@ void addScene(VoxelTree * tree) { // We want our corner voxels to be about 1/2 meter high, and our TREE_SCALE is in meters, so... float voxelSize = 0.5f / TREE_SCALE; - + // Here's an example of how to create a voxel. printf("creating corner points...\n"); tree->createVoxel(0, 0, 0, voxelSize, 255, 255 ,255); @@ -51,72 +52,8 @@ void addScene(VoxelTree * tree) { } else { printf("corner point 0,0,0 does not exists...\n"); } - - // Now some more examples... a little more complex - 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, 0 , voxelSize, 255, 255 ,0 ); - tree->createVoxel(1.0 - voxelSize, 1.0 - voxelSize, 1.0 - voxelSize, voxelSize, 255, 255 ,255); - printf("DONE creating corner points...\n"); - - // Now some more examples... creating some lines using the line primitive - printf("creating voxel lines...\n"); - // We want our line voxels to be about 1/32 meter high, and our TREE_SCALE is in meters, so... - float lineVoxelSize = 1.f / (32 * TREE_SCALE); - rgbColor red = {255, 0, 0}; - rgbColor green = {0, 255, 0}; - rgbColor blue = {0, 0, 255}; - tree->createLine(glm::vec3(0, 0, 0), glm::vec3(0, 0, 1), lineVoxelSize, blue); - tree->createLine(glm::vec3(0, 0, 0), glm::vec3(1, 0, 0), lineVoxelSize, red); - tree->createLine(glm::vec3(0, 0, 0), glm::vec3(0, 1, 0), lineVoxelSize, green); - printf("DONE creating lines...\n"); - - // Now some more examples... creating some spheres using the sphere primitive - // We want the smallest unit of our spheres to be about 1/16th of a meter tall - float sphereVoxelSize = 1.f / (16 * TREE_SCALE); - printf("creating spheres... sphereVoxelSize=%f\n",sphereVoxelSize); - tree->createSphere(0.25, 0.5, 0.5, 0.5, sphereVoxelSize, true, false, true); - printf("one sphere added... sphereVoxelSize=%f\n",sphereVoxelSize); - - tree->createSphere(0.030625, 0.5, 0.5, (0.25 - 0.06125), sphereVoxelSize, true, true); - printf("two spheres added... sphereVoxelSize=%f\n",sphereVoxelSize); - tree->createSphere(0.030625, (0.75 - 0.030625), (0.75 - 0.030625), (0.75 - 0.06125), sphereVoxelSize, true, true); - printf("three spheres added... sphereVoxelSize=%f\n",sphereVoxelSize); - tree->createSphere(0.030625, (0.75 - 0.030625), (0.75 - 0.030625), 0.06125, sphereVoxelSize, true, true); - printf("four spheres added... sphereVoxelSize=%f\n",sphereVoxelSize); - tree->createSphere(0.030625, (0.75 - 0.030625), 0.06125, (0.75 - 0.06125), sphereVoxelSize, true, true); - printf("five spheres added... sphereVoxelSize=%f\n",sphereVoxelSize); - tree->createSphere(0.06125, 0.125, 0.125, (0.75 - 0.125), sphereVoxelSize, 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("DONE creating spheres...\n"); - // Here's an example of how to recurse the tree and do some operation on the nodes as you recurse them. - // This one is really simple, it just couts them... - // Look at the function countVoxelsOperation() for an example of how you could use this function - _nodeCount=0; - tree->recurseTreeWithOperation(countVoxelsOperation); - printf("Nodes after adding scene %d nodes\n", _nodeCount); - - printf("DONE adding scene of spheres...\n"); } - int main(int argc, const char * argv[]) { const char* SAY_HELLO = "--sayHello"; @@ -131,8 +68,32 @@ int main(int argc, const char * argv[]) printf("You asked us not to create a scene file, so we will not.\n"); } else { printf("Creating Scene File...\n"); - addScene(&myTree); + + const char* RUN_TUTORIAL = "--runTutorial"; + if (cmdOptionExists(argc, argv, RUN_TUTORIAL)) { + voxelTutorial(&myTree); + } + + const char* ADD_CORNERS_AND_AXIS_LINES = "--addCornersAndAxisLines"; + if (cmdOptionExists(argc, argv, ADD_CORNERS_AND_AXIS_LINES)) { + addCornersAndAxisLines(&myTree); + } + + const char* ADD_SPHERE_SCENE = "--addSphereScene"; + if (cmdOptionExists(argc, argv, ADD_SPHERE_SCENE)) { + addSphereScene(&myTree); + } + + const char* ADD_SURFACE_SCENE = "--addSurfaceScene"; + if (cmdOptionExists(argc, argv, ADD_SURFACE_SCENE)) { + addSurfaceScene(&myTree); + } + + unsigned long nodeCount = myTree.getVoxelCount(); + printf("Nodes after adding scenes: %ld nodes\n", nodeCount); + myTree.writeToFileV2("voxels.hio2"); + } return 0; } \ No newline at end of file diff --git a/voxel-server/resources/voxels.hio2 b/voxel-server/resources/voxels.hio2 new file mode 100644 index 0000000000..77d51228ce Binary files /dev/null and b/voxel-server/resources/voxels.hio2 differ diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 380f2cc794..f7d4567711 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -17,6 +17,7 @@ #include "VoxelAgentData.h" #include #include +#include #ifdef _WIN32 #include "Syssocket.h" @@ -27,6 +28,8 @@ #include #endif +const char* VOXELS_PERSIST_FILE = "resources/voxels.hio2"; + const int VOXEL_LISTEN_PORT = 40106; @@ -48,100 +51,6 @@ bool wantVoxelPersist = true; bool wantColorRandomizer = false; bool debugVoxelSending = false; -void addSphere(VoxelTree * tree,bool random, bool wantColorRandomizer) { - float r = random ? randFloatInRange(0.05,0.1) : 0.25; - float xc = random ? randFloatInRange(r,(1-r)) : 0.5; - float yc = random ? randFloatInRange(r,(1-r)) : 0.5; - float zc = random ? randFloatInRange(r,(1-r)) : 0.5; - float s = (1.0/256); // size of voxels to make up surface of sphere - bool solid = true; - - printf("adding sphere:"); - if (random) - printf(" random"); - printf("\nradius=%f\n",r); - printf("xc=%f\n",xc); - printf("yc=%f\n",yc); - printf("zc=%f\n",zc); - - tree->createSphere(r,xc,yc,zc,s,solid,wantColorRandomizer); -} - -int _nodeCount=0; -bool countVoxelsOperation(VoxelNode* node, void* extraData) { - if (node->isColored()){ - _nodeCount++; - } - return true; // keep going -} - -void addSphereScene(VoxelTree * tree, bool wantColorRandomizer) { - printf("adding scene...\n"); - - float voxelSize = 1.f/32; - 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, 0 , voxelSize, 255, 255 ,0 ); - tree->createVoxel(1.0 - voxelSize, 1.0 - voxelSize, 1.0 - voxelSize, voxelSize, 255, 255 ,255); - printf("DONE creating corner points...\n"); - - printf("creating voxel lines...\n"); - float lineVoxelSize = 0.99f/256; - rgbColor red = {255,0,0}; - rgbColor green = {0,255,0}; - rgbColor blue = {0,0,255}; - - tree->createLine(glm::vec3(0, 0, 0), glm::vec3(0, 0, 1), lineVoxelSize, blue); - tree->createLine(glm::vec3(0, 0, 0), glm::vec3(1, 0, 0), lineVoxelSize, red); - tree->createLine(glm::vec3(0, 0, 0), glm::vec3(0, 1, 0), lineVoxelSize, green); - - printf("DONE creating lines...\n"); - - int sphereBaseSize = 512; - printf("creating spheres...\n"); - 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, (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("DONE creating spheres...\n"); - - _nodeCount=0; - tree->recurseTreeWithOperation(countVoxelsOperation); - printf("Nodes after adding scene %d nodes\n", _nodeCount); - - - printf("DONE adding scene of spheres...\n"); -} - - void randomlyFillVoxelTree(int levelsToGo, VoxelNode *currentRootNode) { // randomly generate children for this node // the first level of the tree (where levelsToGo = MAX_VOXEL_TREE_DEPTH_LEVELS) has all 8 @@ -298,7 +207,7 @@ void persistVoxelsWhenDirty() { // check the dirty bit and persist here... if (::wantVoxelPersist && ::randomTree.isDirty()) { printf("saving voxels to file...\n"); - randomTree.writeToFileV2("voxels.hio2"); + randomTree.writeToFileV2(VOXELS_PERSIST_FILE); randomTree.clearDirtyBit(); // tree is clean after saving printf("DONE saving voxels to file...\n"); } @@ -393,12 +302,11 @@ int main(int argc, const char * argv[]) bool persistantFileRead = false; if (::wantVoxelPersist) { printf("loading voxels from file...\n"); - persistantFileRead = ::randomTree.readFromFileV2("voxels.hio2"); + persistantFileRead = ::randomTree.readFromFileV2(VOXELS_PERSIST_FILE); ::randomTree.clearDirtyBit(); // the tree is clean since we just loaded it printf("DONE loading voxels from file...\n"); - _nodeCount=0; - ::randomTree.recurseTreeWithOperation(countVoxelsOperation); - printf("Nodes after loading scene %d nodes\n", _nodeCount); + unsigned long nodeCount = ::randomTree.getVoxelCount(); + printf("Nodes after loading scene %ld nodes\n", nodeCount); } // Check to see if the user passed in a command line option for loading an old style local @@ -427,14 +335,6 @@ int main(int argc, const char * argv[]) randomlyFillVoxelTree(MAX_VOXEL_TREE_DEPTH_LEVELS, randomTree.rootNode); } - const char* ADD_SPHERE = "--AddSphere"; - const char* ADD_RANDOM_SPHERE = "--AddRandomSphere"; - if (cmdOptionExists(argc, argv, ADD_SPHERE)) { - addSphere(&randomTree,false,wantColorRandomizer); - } else if (cmdOptionExists(argc, argv, ADD_RANDOM_SPHERE)) { - addSphere(&randomTree,true,wantColorRandomizer); - } - const char* ADD_SCENE = "--AddScene"; bool addScene = cmdOptionExists(argc, argv, ADD_SCENE); const char* NO_ADD_SCENE = "--NoAddScene"; @@ -449,7 +349,7 @@ int main(int argc, const char * argv[]) // HOWEVER -- we will NEVER add a scene if you explicitly tell us not to! bool actuallyAddScene = !noAddScene && (addScene || (::wantVoxelPersist && !persistantFileRead)); if (actuallyAddScene) { - addSphereScene(&randomTree,wantColorRandomizer); + addSphereScene(&randomTree); } pthread_t sendVoxelThread; @@ -535,7 +435,7 @@ int main(int argc, const char * argv[]) } if (0==strcmp(command,(char*)"add scene")) { printf("got Z message == add scene\n"); - addSphereScene(&randomTree,false); + addSphereScene(&randomTree); } totalLength += commandLength+1; }