From 8cffa8d872d5292d9dbd9a4971673b71d6830dbf Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 27 Sep 2013 15:04:44 -0700 Subject: [PATCH] add support for global normals for voxels --- interface/src/Menu.cpp | 3 + interface/src/Menu.h | 1 + interface/src/VoxelSystem.cpp | 355 ++++++++++++++++++-------- interface/src/VoxelSystem.h | 12 + libraries/voxels/src/VoxelConstants.h | 6 + 5 files changed, 266 insertions(+), 111 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index fa42e4c274..784614043a 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -256,6 +256,9 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::UseByteNormals, 0, false, Application::getInstance()->getVoxels(), SLOT(setUseByteNormals(bool))); + + addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::UseGlobalNormals, 0, + false, Application::getInstance()->getVoxels(), SLOT(setUseGlobalNormals(bool))); QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 7cbbdbdc11..a2d0267d58 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -207,6 +207,7 @@ namespace MenuOption { const QString Quit = "Quit"; const QString UseVoxelShader = "Use Voxel Shader"; const QString UseByteNormals = "Use Byte Normals"; + const QString UseGlobalNormals = "Use Global Normals"; const QString Voxels = "Voxels"; const QString VoxelAddMode = "Add Voxel Mode"; const QString VoxelColorMode = "Color Voxel Mode"; diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 88661dd2bd..faeec9352b 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -33,9 +33,11 @@ #include "VoxelConstants.h" #include "VoxelSystem.h" -float identityVertices[] = { 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1, - 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1, - 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1 }; +float identityVerticesGlobalNormals[] = { 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1 }; + +float identityVertices[] = { 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1, //0-7 + 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1, //8-15 + 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1 }; // 16-23 GLfloat identityNormals[] = { 0,0,-1, 0,0,-1, 0,0,-1, 0,0,-1, 0,0,+1, 0,0,+1, 0,0,+1, 0,0,+1, @@ -51,6 +53,13 @@ GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z- 10,11,15, 10,15,14, // Y+ 4,5,6, 4,6,7 }; // Z+ +GLubyte identityIndicesTop[] = { 2, 3, 7, 2, 7, 6 }; +GLubyte identityIndicesBottom[] = { 0, 1, 5, 0, 5, 4 }; +GLubyte identityIndicesLeft[] = { 0, 7, 3, 0, 4, 7 }; +GLubyte identityIndicesRight[] = { 1, 2, 6, 1, 6, 5 }; +GLubyte identityIndicesFront[] = { 0, 2, 1, 0, 3, 2 }; +GLubyte identityIndicesBack[] = { 4, 5, 6, 4, 6, 7 }; + VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) : NodeData(NULL), _treeScale(treeScale), @@ -77,6 +86,7 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) _useVoxelShader = false; _useByteNormals = false; + _useGlobalNormals = false; _writeVoxelShaderData = NULL; _readVoxelShaderData = NULL; @@ -145,6 +155,7 @@ void VoxelSystem::setUseByteNormals(bool useByteNormals) { pthread_mutex_lock(&_bufferWriteLock); bool wasInitialized = _initialized; if (wasInitialized) { + clearAllNodesBufferIndex(); cleanupVoxelMemory(); } _useByteNormals = useByteNormals; @@ -158,11 +169,29 @@ void VoxelSystem::setUseByteNormals(bool useByteNormals) { } } +void VoxelSystem::setUseGlobalNormals(bool useGlobalNormals) { + pthread_mutex_lock(&_bufferWriteLock); + bool wasInitialized = _initialized; + if (wasInitialized) { + clearAllNodesBufferIndex(); + cleanupVoxelMemory(); + } + _useGlobalNormals = useGlobalNormals; + if (wasInitialized) { + init(); + } + pthread_mutex_unlock(&_bufferWriteLock); + + if (wasInitialized) { + forceRedrawEntireTree(); + } +} void VoxelSystem::setMaxVoxels(int maxVoxels) { pthread_mutex_lock(&_bufferWriteLock); bool wasInitialized = _initialized; if (wasInitialized) { + clearAllNodesBufferIndex(); cleanupVoxelMemory(); } _maxVoxels = maxVoxels; @@ -206,9 +235,19 @@ void VoxelSystem::cleanupVoxelMemory() { } else { // Destroy glBuffers glDeleteBuffers(1, &_vboVerticesID); - glDeleteBuffers(1, &_vboNormalsID); glDeleteBuffers(1, &_vboColorsID); - glDeleteBuffers(1, &_vboIndicesID); + + if (!_useGlobalNormals) { + glDeleteBuffers(1, &_vboNormalsID); + glDeleteBuffers(1, &_vboIndicesID); + } else { + glDeleteBuffers(1, &_vboIndicesTop); + glDeleteBuffers(1, &_vboIndicesBottom); + glDeleteBuffers(1, &_vboIndicesLeft); + glDeleteBuffers(1, &_vboIndicesRight); + glDeleteBuffers(1, &_vboIndicesFront); + glDeleteBuffers(1, &_vboIndicesBack); + } delete[] _readVerticesArray; delete[] _writeVerticesArray; @@ -221,6 +260,34 @@ void VoxelSystem::cleanupVoxelMemory() { _initialized = false; // no longer initialized } +void VoxelSystem::setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndices[]) { + GLuint* indicesArray = new GLuint[INDICES_PER_FACE * _maxVoxels]; + + // populate the indicesArray + // this will not change given new voxels, so we can set it all up now + for (int n = 0; n < _maxVoxels; n++) { + // fill the indices array + int voxelIndexOffset = n * INDICES_PER_FACE; + GLuint* currentIndicesPos = indicesArray + voxelIndexOffset; + int startIndex = (n * GLOBAL_NORMALS_VERTICES_PER_VOXEL); + + for (int i = 0; i < INDICES_PER_FACE; i++) { + // add indices for this side of the cube + currentIndicesPos[i] = startIndex + faceIdentityIndices[i]; + } + } + + glGenBuffers(1, &faceVBOID); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, faceVBOID); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + INDICES_PER_FACE * sizeof(GLuint) * _maxVoxels, + indicesArray, GL_STATIC_DRAW); + _memoryUsageVBO += INDICES_PER_FACE * sizeof(GLuint) * _maxVoxels; + + // delete the indices and normals arrays that are no longer needed + delete[] indicesArray; +} + void VoxelSystem::initVoxelMemory() { _initialMemoryUsageGPU = getFreeMemoryGPU(); _memoryUsageRAM = 0; @@ -265,91 +332,104 @@ void VoxelSystem::initVoxelMemory() { _readVoxelShaderData = new VoxelShaderVBOData[_maxVoxels]; _memoryUsageRAM += (sizeof(VoxelShaderVBOData) * _maxVoxels); } else { - GLuint* indicesArray = new GLuint[INDICES_PER_VOXEL * _maxVoxels]; - - // populate the indicesArray - // this will not change given new voxels, so we can set it all up now - for (int n = 0; n < _maxVoxels; n++) { - // fill the indices array - int voxelIndexOffset = n * INDICES_PER_VOXEL; - GLuint* currentIndicesPos = indicesArray + voxelIndexOffset; - int startIndex = (n * VERTICES_PER_VOXEL); - - for (int i = 0; i < INDICES_PER_VOXEL; i++) { - // add indices for this side of the cube - currentIndicesPos[i] = startIndex + identityIndices[i]; - } - } - - if (_useByteNormals) { - qDebug("Using Byte Normals...\n"); - GLbyte* normalsArray = new GLbyte[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; - GLbyte* normalsArrayEndPointer = normalsArray; - - // populate the normalsArray - for (int n = 0; n < _maxVoxels; n++) { - for (int i = 0; i < VERTEX_POINTS_PER_VOXEL; i++) { - *(normalsArrayEndPointer++) = (identityNormals[i] * CHAR_MAX); - } - } - - // VBO for the normalsArray - glGenBuffers(1, &_vboNormalsID); - glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID); - glBufferData(GL_ARRAY_BUFFER, - VERTEX_POINTS_PER_VOXEL * sizeof(GLbyte) * _maxVoxels, - normalsArray, GL_STATIC_DRAW); - _memoryUsageVBO += VERTEX_POINTS_PER_VOXEL * sizeof(GLbyte) * _maxVoxels; - - // delete the indices and normals arrays that are no longer needed - delete[] normalsArray; + if (_useGlobalNormals) { + // Global Normals mode uses a technique of not including normals on any voxel vertices, and instead + // rendering the voxel faces in 6 passes that use a global call to glNormal3f() + qDebug("Using Global Normals...\n"); + setupFaceIndices(_vboIndicesTop, identityIndicesTop); + setupFaceIndices(_vboIndicesBottom, identityIndicesBottom); + setupFaceIndices(_vboIndicesLeft, identityIndicesLeft); + setupFaceIndices(_vboIndicesRight, identityIndicesRight); + setupFaceIndices(_vboIndicesFront, identityIndicesFront); + setupFaceIndices(_vboIndicesBack, identityIndicesBack); } else { - qDebug("Using Float Normals...\n"); - GLfloat* normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; - GLfloat* normalsArrayEndPointer = normalsArray; + if (_useByteNormals) { + qDebug("Using Byte Normals...\n"); + GLbyte* normalsArray = new GLbyte[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; + GLbyte* normalsArrayEndPointer = normalsArray; - // populate the normalsArray + // populate the normalsArray + for (int n = 0; n < _maxVoxels; n++) { + for (int i = 0; i < VERTEX_POINTS_PER_VOXEL; i++) { + *(normalsArrayEndPointer++) = (identityNormals[i] * CHAR_MAX); + } + } + + // VBO for the normalsArray + glGenBuffers(1, &_vboNormalsID); + glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID); + glBufferData(GL_ARRAY_BUFFER, + VERTEX_POINTS_PER_VOXEL * sizeof(GLbyte) * _maxVoxels, + normalsArray, GL_STATIC_DRAW); + _memoryUsageVBO += VERTEX_POINTS_PER_VOXEL * sizeof(GLbyte) * _maxVoxels; + + // delete the indices and normals arrays that are no longer needed + delete[] normalsArray; + } else { + qDebug("Using Float Normals...\n"); + GLfloat* normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; + GLfloat* normalsArrayEndPointer = normalsArray; + + // populate the normalsArray + for (int n = 0; n < _maxVoxels; n++) { + for (int i = 0; i < VERTEX_POINTS_PER_VOXEL; i++) { + *(normalsArrayEndPointer++) = identityNormals[i]; + } + } + + // VBO for the normalsArray + glGenBuffers(1, &_vboNormalsID); + glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID); + glBufferData(GL_ARRAY_BUFFER, + VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, + normalsArray, GL_STATIC_DRAW); + _memoryUsageVBO += VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels; + + // delete the indices and normals arrays that are no longer needed + delete[] normalsArray; + } + + GLuint* indicesArray = new GLuint[INDICES_PER_VOXEL * _maxVoxels]; + + // populate the indicesArray + // this will not change given new voxels, so we can set it all up now for (int n = 0; n < _maxVoxels; n++) { - for (int i = 0; i < VERTEX_POINTS_PER_VOXEL; i++) { - *(normalsArrayEndPointer++) = identityNormals[i]; + // fill the indices array + int voxelIndexOffset = n * INDICES_PER_VOXEL; + GLuint* currentIndicesPos = indicesArray + voxelIndexOffset; + int startIndex = (n * VERTICES_PER_VOXEL); + + for (int i = 0; i < INDICES_PER_VOXEL; i++) { + // add indices for this side of the cube + currentIndicesPos[i] = startIndex + identityIndices[i]; } } - - // VBO for the normalsArray - glGenBuffers(1, &_vboNormalsID); - glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID); - glBufferData(GL_ARRAY_BUFFER, - VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, - normalsArray, GL_STATIC_DRAW); - _memoryUsageVBO += VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels; + + // VBO for the indicesArray + glGenBuffers(1, &_vboIndicesID); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + INDICES_PER_VOXEL * sizeof(GLuint) * _maxVoxels, + indicesArray, GL_STATIC_DRAW); + _memoryUsageVBO += INDICES_PER_VOXEL * sizeof(GLuint) * _maxVoxels; // delete the indices and normals arrays that are no longer needed - delete[] normalsArray; + delete[] indicesArray; + } - - + + // Depending on if we're using per vertex normals, we will need more or less vertex points per voxel + int vertexPointsPerVoxel = _useGlobalNormals ? GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL : VERTEX_POINTS_PER_VOXEL; glGenBuffers(1, &_vboVerticesID); glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); - glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); - _memoryUsageVBO += VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels; + glBufferData(GL_ARRAY_BUFFER, vertexPointsPerVoxel * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); + _memoryUsageVBO += vertexPointsPerVoxel * sizeof(GLfloat) * _maxVoxels; // VBO for colorsArray glGenBuffers(1, &_vboColorsID); glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); - glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); - _memoryUsageVBO += VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte) * _maxVoxels; - - // VBO for the indicesArray - glGenBuffers(1, &_vboIndicesID); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, - INDICES_PER_VOXEL * sizeof(GLuint) * _maxVoxels, - indicesArray, GL_STATIC_DRAW); - _memoryUsageVBO += INDICES_PER_VOXEL * sizeof(GLuint) * _maxVoxels; - - // delete the indices and normals arrays that are no longer needed - delete[] indicesArray; - + glBufferData(GL_ARRAY_BUFFER, vertexPointsPerVoxel * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); + _memoryUsageVBO += vertexPointsPerVoxel * sizeof(GLubyte) * _maxVoxels; // we will track individual dirty sections with these arrays of bools _writeVoxelDirtyArray = new bool[_maxVoxels]; @@ -361,15 +441,15 @@ void VoxelSystem::initVoxelMemory() { _memoryUsageRAM += (sizeof(bool) * _maxVoxels); // prep the data structures for incoming voxel data - _writeVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; - _memoryUsageRAM += (sizeof(GLfloat) * VERTEX_POINTS_PER_VOXEL * _maxVoxels); - _readVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; - _memoryUsageRAM += (sizeof(GLfloat) * VERTEX_POINTS_PER_VOXEL * _maxVoxels); + _writeVerticesArray = new GLfloat[vertexPointsPerVoxel * _maxVoxels]; + _memoryUsageRAM += (sizeof(GLfloat) * vertexPointsPerVoxel * _maxVoxels); + _readVerticesArray = new GLfloat[vertexPointsPerVoxel * _maxVoxels]; + _memoryUsageRAM += (sizeof(GLfloat) * vertexPointsPerVoxel * _maxVoxels); - _writeColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; - _memoryUsageRAM += (sizeof(GLubyte) * VERTEX_POINTS_PER_VOXEL * _maxVoxels); - _readColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; - _memoryUsageRAM += (sizeof(GLubyte) * VERTEX_POINTS_PER_VOXEL * _maxVoxels); + _writeColorsArray = new GLubyte[vertexPointsPerVoxel * _maxVoxels]; + _memoryUsageRAM += (sizeof(GLubyte) * vertexPointsPerVoxel * _maxVoxels); + _readColorsArray = new GLubyte[vertexPointsPerVoxel * _maxVoxels]; + _memoryUsageRAM += (sizeof(GLubyte) * vertexPointsPerVoxel * _maxVoxels); // create our simple fragment shader if we're the first system to init @@ -649,16 +729,19 @@ void VoxelSystem::copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, void* writeDataAt = &_writeVoxelShaderData[segmentStart]; memcpy(readDataAt, writeDataAt, segmentSizeBytes); } else { - GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + // Depending on if we're using per vertex normals, we will need more or less vertex points per voxel + int vertexPointsPerVoxel = _useGlobalNormals ? GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL : VERTEX_POINTS_PER_VOXEL; + + GLintptr segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLfloat); + GLsizeiptr segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLfloat); + GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * vertexPointsPerVoxel); + GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * vertexPointsPerVoxel); memcpy(readVerticesAt, writeVerticesAt, segmentSizeBytes); - segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readColorsAt = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLubyte); + segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLubyte); + GLubyte* readColorsAt = _readColorsArray + (segmentStart * vertexPointsPerVoxel); + GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * vertexPointsPerVoxel); memcpy(readColorsAt, writeColorsAt, segmentSizeBytes); } } @@ -797,10 +880,17 @@ void VoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& s } } else { if (_writeVerticesArray && _writeColorsArray) { - for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) { - GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); - GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); - *(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale); + int vertexPointsPerVoxel = _useGlobalNormals ? GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL : VERTEX_POINTS_PER_VOXEL; + for (int j = 0; j < vertexPointsPerVoxel; j++ ) { + GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * vertexPointsPerVoxel); + GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * vertexPointsPerVoxel); + + if (_useGlobalNormals) { + *(writeVerticesAt+j) = startVertex[j % 3] + (identityVerticesGlobalNormals[j] * voxelScale); + } else { + *(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale); + } + *(writeColorsAt +j) = color[j % 3]; } } @@ -912,15 +1002,16 @@ void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex seg glBindBuffer(GL_ARRAY_BUFFER, _vboVoxelsID); glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); } else { + int vertexPointsPerVoxel = _useGlobalNormals ? GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL : VERTEX_POINTS_PER_VOXEL; int segmentLength = (segmentEnd - segmentStart) + 1; - GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + GLintptr segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLfloat); + GLsizeiptr segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLfloat); + GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * vertexPointsPerVoxel); glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); - segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLubyte); + segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLubyte); + GLubyte* readColorsFrom = _readColorsArray + (segmentStart * vertexPointsPerVoxel); glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); } @@ -966,27 +1057,66 @@ void VoxelSystem::render(bool texture) { } else { // tell OpenGL where to find vertex and color information glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); glVertexPointer(3, GL_FLOAT, 0, 0); - glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID); - glNormalPointer((_useByteNormals ? GL_BYTE : GL_FLOAT), 0, 0); - glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); + if (!_useGlobalNormals) { + glEnableClientState(GL_NORMAL_ARRAY); + glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID); + glNormalPointer((_useByteNormals ? GL_BYTE : GL_FLOAT), 0, 0); + } else { + glNormal3f(0,1.0f,0); // hack for now + } + applyScaleAndBindProgram(texture); // for performance, enable backface culling glEnable(GL_CULL_FACE); - // draw the number of voxels we have - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); - glDrawRangeElementsEXT(GL_TRIANGLES, 0, VERTICES_PER_VOXEL * _voxelsInReadArrays - 1, - 36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + if (!_useGlobalNormals) { + // draw the number of voxels we have + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, VERTICES_PER_VOXEL * _voxelsInReadArrays - 1, + 36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + } else { + // draw voxels in 6 passes + + glNormal3f(0,1.0f,0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesTop); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, + INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + + glNormal3f(0,-1.0f,0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBottom); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, + INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + + glNormal3f(-1.0f,0,0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesLeft); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, + INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + + glNormal3f(1.0f,0,0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesRight); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, + INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + + glNormal3f(0,0,-1.0f); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesFront); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, + INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + + glNormal3f(0,0,1.0f); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBack); + glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1, + INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + } + glDisable(GL_CULL_FACE); @@ -994,9 +1124,12 @@ void VoxelSystem::render(bool texture) { // deactivate vertex and color arrays after drawing glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); + if (!_useGlobalNormals) { + glDisableClientState(GL_NORMAL_ARRAY); + } + // bind with 0 to switch back to normal operation glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 5e56cfe8a6..bf5beb6263 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -135,6 +135,7 @@ public slots: void cancelImport(); void setUseByteNormals(bool useByteNormals); + void setUseGlobalNormals(bool useGlobalNormals); protected: float _treeScale; @@ -218,6 +219,7 @@ private: void cleanupVoxelMemory(); bool _useByteNormals; + bool _useGlobalNormals; bool _useVoxelShader; GLuint _vboVoxelsID; /// when using voxel shader, we'll use this VBO @@ -229,6 +231,14 @@ private: GLuint _vboNormalsID; GLuint _vboColorsID; GLuint _vboIndicesID; + + GLuint _vboIndicesTop; + GLuint _vboIndicesBottom; + GLuint _vboIndicesLeft; + GLuint _vboIndicesRight; + GLuint _vboIndicesFront; + GLuint _vboIndicesBack; + pthread_mutex_t _bufferWriteLock; pthread_mutex_t _treeLock; @@ -236,6 +246,8 @@ private: ViewFrustum _lastStableViewFrustum; ViewFrustum* _viewFrustum; + void setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndices[]); + int newTreeToArrays(VoxelNode *currentNode); void cleanupRemovedVoxels(); diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index 391be29282..1871aa8e31 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -38,6 +38,12 @@ const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL; // xyz for each VERT const int INDICES_PER_VOXEL = 3 * 12; // 6 sides * 2 triangles per size * 3 vertices per triangle const int COLOR_VALUES_PER_VOXEL = NUMBER_OF_COLORS * VERTICES_PER_VOXEL; +const int VERTICES_PER_FACE = 4; // 6 sides * 4 corners per side +const int INDICES_PER_FACE = 3 * 2; // 1 side * 2 triangles per size * 3 vertices per triangle +const int GLOBAL_NORMALS_VERTICES_PER_VOXEL = 8; // no need for 3 copies because they don't include normal +const int GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL = 3 * GLOBAL_NORMALS_VERTICES_PER_VOXEL; +const int GLOBAL_NORMALS_COLOR_VALUES_PER_VOXEL = NUMBER_OF_COLORS * GLOBAL_NORMALS_VERTICES_PER_VOXEL; + typedef unsigned long int glBufferIndex; const glBufferIndex GLBUFFER_INDEX_UNKNOWN = ULONG_MAX;