From 631419d23c62739f7927593fe7e67b32e1de0723 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 22 Oct 2014 18:22:21 -0700 Subject: [PATCH 1/4] Tweaks to heightfield conversion. --- .../shaders/metavoxel_heightfield_base.vert | 13 +++--- .../metavoxels/src/MetavoxelMessages.cpp | 43 ++++++++++++------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/interface/resources/shaders/metavoxel_heightfield_base.vert b/interface/resources/shaders/metavoxel_heightfield_base.vert index f097426e13..5486f5fa67 100644 --- a/interface/resources/shaders/metavoxel_heightfield_base.vert +++ b/interface/resources/shaders/metavoxel_heightfield_base.vert @@ -26,11 +26,14 @@ varying vec4 normal; void main(void) { // transform and store the normal for interpolation vec2 heightCoord = gl_MultiTexCoord0.st; - float deltaX = texture2D(heightMap, heightCoord - vec2(heightScale, 0.0)).r - - texture2D(heightMap, heightCoord + vec2(heightScale, 0.0)).r; - float deltaZ = texture2D(heightMap, heightCoord - vec2(0.0, heightScale)).r - - texture2D(heightMap, heightCoord + vec2(0.0, heightScale)).r; - normal = normalize(gl_ModelViewMatrix * vec4(deltaX, heightScale, deltaZ, 0.0)); + vec4 neighborHeights = vec4(texture2D(heightMap, heightCoord - vec2(heightScale, 0.0)).r, + texture2D(heightMap, heightCoord + vec2(heightScale, 0.0)).r, + texture2D(heightMap, heightCoord - vec2(0.0, heightScale)).r, + texture2D(heightMap, heightCoord + vec2(0.0, heightScale)).r); + vec4 neighborsZero = step(1.0 / 255.0, neighborHeights); + normal = normalize(gl_ModelViewMatrix * vec4( + (neighborHeights.x - neighborHeights.y) * neighborsZero.x * neighborsZero.y, heightScale, + (neighborHeights.z - neighborHeights.w) * neighborsZero.z * neighborsZero.w, 0.0)); // add the height to the position float height = texture2D(heightMap, heightCoord).r; diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index d9c60f3f12..2d1e03fc69 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -1062,6 +1062,13 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) { HeightfieldHeightDataPointer newHeightPointer(new HeightfieldHeightData(contents)); info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(newHeightPointer)); + // allow a border for what we clear in terms of color/material + innerBounds.minimum.x += increment; + innerBounds.minimum.z += increment; + innerBounds.maximum.x -= increment; + innerBounds.maximum.z -= increment; + innerOverlap = bounds.getIntersection(innerBounds); + HeightfieldColorDataPointer colorPointer = info.inputValues.at(1).getInlineValue(); if (colorPointer) { contents = colorPointer->getContents(); @@ -1087,14 +1094,16 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) { destY = (innerOverlap.minimum.z - info.minimum.z) * heightScale; destWidth = glm::ceil((innerOverlap.maximum.x - innerOverlap.minimum.x) * heightScale); destHeight = glm::ceil((innerOverlap.maximum.z - innerOverlap.minimum.z) * heightScale); - dest = contents.data() + (destY * size + destX) * DataBlock::COLOR_BYTES; - - for (int y = 0; y < destHeight; y++, dest += size * DataBlock::COLOR_BYTES) { - memset(dest, 0, destWidth * DataBlock::COLOR_BYTES); + if (destWidth > 0 && destHeight > 0) { + dest = contents.data() + (destY * size + destX) * DataBlock::COLOR_BYTES; + + for (int y = 0; y < destHeight; y++, dest += size * DataBlock::COLOR_BYTES) { + memset(dest, 0, destWidth * DataBlock::COLOR_BYTES); + } + + HeightfieldColorDataPointer newColorPointer(new HeightfieldColorData(contents)); + info.outputValues[1] = AttributeValue(_outputs.at(1), encodeInline(newColorPointer)); } - - HeightfieldColorDataPointer newColorPointer(new HeightfieldColorData(contents)); - info.outputValues[1] = AttributeValue(_outputs.at(1), encodeInline(newColorPointer)); } HeightfieldMaterialDataPointer materialPointer = info.inputValues.at(2).getInlineValue(); @@ -1134,16 +1143,18 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) { destY = (innerOverlap.minimum.z - info.minimum.z) * heightScale; destWidth = glm::ceil((innerOverlap.maximum.x - innerOverlap.minimum.x) * heightScale); destHeight = glm::ceil((innerOverlap.maximum.z - innerOverlap.minimum.z) * heightScale); - dest = (uchar*)contents.data() + destY * size + destX; - - for (int y = 0; y < destHeight; y++, dest += size) { - memset(dest, 0, destWidth); + if (destWidth > 0 && destHeight > 0) { + dest = (uchar*)contents.data() + destY * size + destX; + + for (int y = 0; y < destHeight; y++, dest += size) { + memset(dest, 0, destWidth); + } + + clearUnusedMaterials(materials, contents); + HeightfieldMaterialDataPointer newMaterialPointer(new HeightfieldMaterialData(contents, materials)); + info.outputValues[2] = AttributeValue(_outputs.at(2), + encodeInline(newMaterialPointer)); } - - clearUnusedMaterials(materials, contents); - HeightfieldMaterialDataPointer newMaterialPointer(new HeightfieldMaterialData(contents, materials)); - info.outputValues[2] = AttributeValue(_outputs.at(2), - encodeInline(newMaterialPointer)); } return STOP_RECURSION; From 34cba5c031b404b2812f186080ca02d95994aaab Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 23 Oct 2014 13:16:43 -0700 Subject: [PATCH 2/4] Added options to selectively toggle heightfield/dual contour surface rendering. --- interface/src/Menu.cpp | 2 ++ interface/src/Menu.h | 2 ++ interface/src/MetavoxelSystem.cpp | 53 +++++++++++++++---------------- 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 11ab5769cb..d7b47a549d 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -432,6 +432,8 @@ Menu::Menu() : QMenu* metavoxelOptionsMenu = developerMenu->addMenu("Metavoxels"); addCheckableActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::DisplayHermiteData, 0, false, Application::getInstance()->getMetavoxels(), SLOT(refreshVoxelData())); + addCheckableActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::RenderHeightfields, 0, true); + addCheckableActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::RenderDualContourSurfaces, 0, true); addActionToQMenuAndActionHash(metavoxelOptionsMenu, MenuOption::NetworkSimulator, 0, this, SLOT(showMetavoxelNetworkSimulator())); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 80f7f1e006..66755f0e5b 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -446,8 +446,10 @@ namespace MenuOption { const QString Quit = "Quit"; const QString ReloadAllScripts = "Reload All Scripts"; const QString RenderBoundingCollisionShapes = "Show Bounding Collision Shapes"; + const QString RenderDualContourSurfaces = "Render Dual Contour Surfaces"; const QString RenderFocusIndicator = "Show Eye Focus"; const QString RenderHeadCollisionShapes = "Show Head Collision Shapes"; + const QString RenderHeightfields = "Render Heightfields"; const QString RenderLookAtVectors = "Show Look-at Vectors"; const QString RenderSkeletonCollisionShapes = "Show Skeleton Collision Shapes"; const QString RenderResolution = "Scale Resolution"; diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 8166c3938c..2071ea8c3d 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -2772,40 +2772,39 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - _baseHeightfieldProgram.bind(); - - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - BufferRenderVisitor heightfieldRenderVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute()); - data.guide(heightfieldRenderVisitor); - - _baseHeightfieldProgram.release(); - - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE0); + if (Menu::getInstance()->isOptionChecked(MenuOption::RenderHeightfields)) { + _baseHeightfieldProgram.bind(); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + BufferRenderVisitor heightfieldRenderVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute()); + data.guide(heightfieldRenderVisitor); + + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + _baseHeightfieldProgram.release(); + } - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - - _baseVoxelProgram.bind(); - - BufferRenderVisitor voxelRenderVisitor(Application::getInstance()->getMetavoxels()->getVoxelBufferAttribute()); - data.guide(voxelRenderVisitor); - - _baseVoxelProgram.release(); + if (Menu::getInstance()->isOptionChecked(MenuOption::RenderDualContourSurfaces)) { + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + + _baseVoxelProgram.bind(); + + BufferRenderVisitor voxelRenderVisitor(Application::getInstance()->getMetavoxels()->getVoxelBufferAttribute()); + data.guide(voxelRenderVisitor); + + _baseVoxelProgram.release(); + + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + } glDisable(GL_ALPHA_TEST); glDisable(GL_CULL_FACE); glEnable(GL_BLEND); - + glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false); } From ef0a400dcbd18d9b45eb8b4086f29154dae7e53a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 23 Oct 2014 13:37:11 -0700 Subject: [PATCH 3/4] Fix for clearing empty nodes. --- .../metavoxels/src/MetavoxelMessages.cpp | 78 ++++++++++--------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index 2d1e03fc69..d92dc4bd5a 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -1049,19 +1049,14 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) { } // if all is gone, clear the node - if (!foundNonZero) { - info.outputValues[0] = AttributeValue(_outputs.at(0), - encodeInline(HeightfieldHeightDataPointer())); - info.outputValues[1] = AttributeValue(_outputs.at(1), - encodeInline(HeightfieldColorDataPointer())); - info.outputValues[2] = AttributeValue(_outputs.at(2), - encodeInline(HeightfieldMaterialDataPointer())); - return STOP_RECURSION; + if (foundNonZero) { + HeightfieldHeightDataPointer newHeightPointer(new HeightfieldHeightData(contents)); + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(newHeightPointer)); + + } else { + info.outputValues[0] = AttributeValue(_outputs.at(0)); } - HeightfieldHeightDataPointer newHeightPointer(new HeightfieldHeightData(contents)); - info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(newHeightPointer)); - // allow a border for what we clear in terms of color/material innerBounds.minimum.x += increment; innerBounds.minimum.z += increment; @@ -1090,19 +1085,24 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) { memcpy(dest, src, destWidth * DataBlock::COLOR_BYTES); } - destX = (innerOverlap.minimum.x - info.minimum.x) * heightScale; - destY = (innerOverlap.minimum.z - info.minimum.z) * heightScale; - destWidth = glm::ceil((innerOverlap.maximum.x - innerOverlap.minimum.x) * heightScale); - destHeight = glm::ceil((innerOverlap.maximum.z - innerOverlap.minimum.z) * heightScale); - if (destWidth > 0 && destHeight > 0) { - dest = contents.data() + (destY * size + destX) * DataBlock::COLOR_BYTES; - - for (int y = 0; y < destHeight; y++, dest += size * DataBlock::COLOR_BYTES) { - memset(dest, 0, destWidth * DataBlock::COLOR_BYTES); + if (foundNonZero) { + destX = (innerOverlap.minimum.x - info.minimum.x) * heightScale; + destY = (innerOverlap.minimum.z - info.minimum.z) * heightScale; + destWidth = glm::ceil((innerOverlap.maximum.x - innerOverlap.minimum.x) * heightScale); + destHeight = glm::ceil((innerOverlap.maximum.z - innerOverlap.minimum.z) * heightScale); + if (destWidth > 0 && destHeight > 0) { + dest = contents.data() + (destY * size + destX) * DataBlock::COLOR_BYTES; + + for (int y = 0; y < destHeight; y++, dest += size * DataBlock::COLOR_BYTES) { + memset(dest, 0, destWidth * DataBlock::COLOR_BYTES); + } + + HeightfieldColorDataPointer newColorPointer(new HeightfieldColorData(contents)); + info.outputValues[1] = AttributeValue(_outputs.at(1), + encodeInline(newColorPointer)); } - - HeightfieldColorDataPointer newColorPointer(new HeightfieldColorData(contents)); - info.outputValues[1] = AttributeValue(_outputs.at(1), encodeInline(newColorPointer)); + } else { + info.outputValues[1] = AttributeValue(_outputs.at(1)); } } @@ -1139,21 +1139,25 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) { } } - destX = (innerOverlap.minimum.x - info.minimum.x) * heightScale; - destY = (innerOverlap.minimum.z - info.minimum.z) * heightScale; - destWidth = glm::ceil((innerOverlap.maximum.x - innerOverlap.minimum.x) * heightScale); - destHeight = glm::ceil((innerOverlap.maximum.z - innerOverlap.minimum.z) * heightScale); - if (destWidth > 0 && destHeight > 0) { - dest = (uchar*)contents.data() + destY * size + destX; - - for (int y = 0; y < destHeight; y++, dest += size) { - memset(dest, 0, destWidth); + if (foundNonZero) { + destX = (innerOverlap.minimum.x - info.minimum.x) * heightScale; + destY = (innerOverlap.minimum.z - info.minimum.z) * heightScale; + destWidth = glm::ceil((innerOverlap.maximum.x - innerOverlap.minimum.x) * heightScale); + destHeight = glm::ceil((innerOverlap.maximum.z - innerOverlap.minimum.z) * heightScale); + if (destWidth > 0 && destHeight > 0) { + dest = (uchar*)contents.data() + destY * size + destX; + + for (int y = 0; y < destHeight; y++, dest += size) { + memset(dest, 0, destWidth); + } + + clearUnusedMaterials(materials, contents); + HeightfieldMaterialDataPointer newMaterialPointer(new HeightfieldMaterialData(contents, materials)); + info.outputValues[2] = AttributeValue(_outputs.at(2), + encodeInline(newMaterialPointer)); } - - clearUnusedMaterials(materials, contents); - HeightfieldMaterialDataPointer newMaterialPointer(new HeightfieldMaterialData(contents, materials)); - info.outputValues[2] = AttributeValue(_outputs.at(2), - encodeInline(newMaterialPointer)); + } else { + info.outputValues[2] = AttributeValue(_outputs.at(2)); } } From 27d9de0cba6fbdc862a165161a09e56fc89a3246 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 23 Oct 2014 16:01:51 -0700 Subject: [PATCH 4/4] More gradual improvements to heightfield voxelization. --- libraries/metavoxels/src/MetavoxelData.cpp | 35 +++++++++++++++++-- .../metavoxels/src/MetavoxelMessages.cpp | 9 +++-- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 5b00c6531f..2bd28de784 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -2486,8 +2486,39 @@ bool Heightfield::intersects(const glm::vec3& start, const glm::vec3& end, float if (!getBounds().findRayIntersection(start, direction, rayDistance) || rayDistance > 1.0f) { return false; } - glm::vec3 entry = (start + direction * rayDistance - getBounds().minimum) / _increment; - direction /= _increment; + glm::vec3 entry = start + direction * rayDistance; + const float DISTANCE_THRESHOLD = 0.001f; + if (glm::abs(entry.x - getBounds().minimum.x) < DISTANCE_THRESHOLD) { + normal = glm::vec3(-1.0f, 0.0f, 0.0f); + distance = rayDistance; + return true; + + } else if (glm::abs(entry.x - getBounds().maximum.x) < DISTANCE_THRESHOLD) { + normal = glm::vec3(1.0f, 0.0f, 0.0f); + distance = rayDistance; + return true; + + } else if (glm::abs(entry.y - getBounds().minimum.y) < DISTANCE_THRESHOLD) { + normal = glm::vec3(0.0f, -1.0f, 0.0f); + distance = rayDistance; + return true; + + } else if (glm::abs(entry.y - getBounds().maximum.y) < DISTANCE_THRESHOLD) { + normal = glm::vec3(0.0f, 1.0f, 0.0f); + distance = rayDistance; + return true; + + } else if (glm::abs(entry.z - getBounds().minimum.z) < DISTANCE_THRESHOLD) { + normal = glm::vec3(0.0f, 0.0f, -1.0f); + distance = rayDistance; + return true; + + } else if (glm::abs(entry.z - getBounds().maximum.z) < DISTANCE_THRESHOLD) { + normal = glm::vec3(0.0f, 0.0f, 1.0f); + distance = rayDistance; + return true; + } + entry = (entry - getBounds().minimum) / _increment; glm::vec3 floors = glm::floor(entry); glm::vec3 ceils = glm::ceil(entry); if (floors.x == ceils.x) { diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index d92dc4bd5a..549931e030 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -998,10 +998,13 @@ int HeightfieldClearFetchVisitor::visit(MetavoxelInfo& info) { _spannerBounds.maximum = (glm::ceil(_bounds.maximum / increment) + glm::vec3(1.0f, 0.0f, 1.0f)) * increment; _spannerBounds.minimum.y = bounds.minimum.y; _spannerBounds.maximum.y = bounds.maximum.y; - _heightfieldWidth = (int)glm::round((_spannerBounds.maximum.x - _spannerBounds.minimum.x) / increment) + 1; - _heightfieldHeight = (int)glm::round((_spannerBounds.maximum.z - _spannerBounds.minimum.z) / increment) + 1; + _heightfieldWidth = (int)glm::round((_spannerBounds.maximum.x - _spannerBounds.minimum.x) / increment); + _heightfieldHeight = (int)glm::round((_spannerBounds.maximum.z - _spannerBounds.minimum.z) / increment); int heightfieldArea = _heightfieldWidth * _heightfieldHeight; - _spanner = spanner = new Heightfield(_spannerBounds, increment, QByteArray(heightfieldArea, 0), + Box innerBounds = _spannerBounds; + innerBounds.maximum.x -= increment; + innerBounds.maximum.z -= increment; + _spanner = spanner = new Heightfield(innerBounds, increment, QByteArray(heightfieldArea, 0), QByteArray(heightfieldArea * DataBlock::COLOR_BYTES, 0), QByteArray(heightfieldArea, 0), QVector()); }