From 2497b2fe39debd321d97fa3eed03d0db107ee3f3 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 16 Jan 2015 15:41:08 -0800 Subject: [PATCH] If there's no directly intersecting spanner, find the closest heightfield that we can project onto. --- interface/src/MetavoxelSystem.cpp | 21 +++++--- .../metavoxels/src/MetavoxelMessages.cpp | 52 +++++++++++++++++++ 2 files changed, 65 insertions(+), 8 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index b0c3dafbb9..f3c3c94255 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1957,15 +1957,14 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g } } // determine whether we should ignore this vertex because it will be stitched - bool ignore = false; + int validCrossings = 0; for (int i = 0; i < crossingCount; i++) { - if (qAlpha(crossings[i].color) == 0) { - ignore = true; - break; + if (qAlpha(crossings[i].color) != 0) { + validCrossings++; } } NormalIndex index = { { -1, -1, -1, -1 } }; - if (!ignore) { + if (validCrossings != 0) { index.indices[0] = index.indices[1] = index.indices[2] = index.indices[3] = vertices.size(); glm::vec3 center; glm::vec3 normals[MAX_NORMALS_PER_VERTEX]; @@ -1978,6 +1977,9 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g int red = 0, green = 0, blue = 0; for (int i = 0; i < crossingCount; i++) { const EdgeCrossing& crossing = crossings[i]; + if (qAlpha(crossing.color) == 0) { + continue; + } center += crossing.point; int j = 0; @@ -2013,7 +2015,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g } } } - center /= crossingCount; + center /= validCrossings; // use a sequence of Givens rotations to perform a QR decomposition // see http://www.cs.rice.edu/~jwarren/papers/techreport02408.pdf @@ -2021,6 +2023,9 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g glm::vec4 bottom; for (int i = 0; i < crossingCount; i++) { const EdgeCrossing& crossing = crossings[i]; + if (qAlpha(crossing.color) == 0) { + continue; + } bottom = glm::vec4(crossing.normal, glm::dot(crossing.normal, crossing.point - center)); for (int j = 0; j < 4; j++) { @@ -2085,8 +2090,8 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g materialWeights *= (numeric_limits::max() / totalWeight); } VoxelPoint point = { (glm::vec3(clampedX, y, clampedZ) + center) * step, - { (quint8)(red / crossingCount), (quint8)(green / crossingCount), - (quint8)(blue / crossingCount) }, + { (quint8)(red / validCrossings), (quint8)(green / validCrossings), + (quint8)(blue / validCrossings) }, { (char)(normals[0].x * 127.0f), (char)(normals[0].y * 127.0f), (char)(normals[0].z * 127.0f) }, { materials[0], materials[1], materials[2], materials[3] }, diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index 5ba16ee754..cfe97a73af 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "MetavoxelMessages.h" #include "Spanner.h" @@ -180,6 +182,50 @@ HeightfieldMaterialSpannerEdit::HeightfieldMaterialSpannerEdit(const SharedObjec paint(paint) { } +class SpannerProjectionFetchVisitor : public SpannerVisitor { +public: + + SpannerProjectionFetchVisitor(const Box& bounds, QVector& results); + + virtual bool visit(Spanner* spanner); + +private: + + const Box& _bounds; + QVector& _results; + float _closestDistance; +}; + +SpannerProjectionFetchVisitor::SpannerProjectionFetchVisitor(const Box& bounds, QVector& results) : + SpannerVisitor(QVector() << AttributeRegistry::getInstance()->getSpannersAttribute()), + _bounds(bounds), + _results(results), + _closestDistance(FLT_MAX) { +} + +bool SpannerProjectionFetchVisitor::visit(Spanner* spanner) { + Heightfield* heightfield = qobject_cast(spanner); + if (!heightfield) { + return true; + } + glm::mat4 transform = glm::scale(1.0f / glm::vec3(heightfield->getScale(), + heightfield->getScale() * heightfield->getAspectY(), + heightfield->getScale() * heightfield->getAspectZ())) * + glm::mat4_cast(glm::inverse(heightfield->getRotation())) * glm::translate(-heightfield->getTranslation()); + Box transformedBounds = transform * _bounds; + if (transformedBounds.maximum.x < 0.0f && transformedBounds.maximum.z < 0.0f && + transformedBounds.minimum.x > 1.0f && transformedBounds.minimum.z > 1.0f) { + return true; + } + float distance = qMin(glm::abs(transformedBounds.minimum.y), glm::abs(transformedBounds.maximum.y)); + if (distance < _closestDistance) { + _results.clear(); + _results.append(spanner); + _closestDistance = distance; + } + return true; +} + void HeightfieldMaterialSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { // make sure the color meets our transparency requirements QColor color = averageColor; @@ -193,6 +239,12 @@ void HeightfieldMaterialSpannerEdit::apply(MetavoxelData& data, const WeakShared data.getIntersecting(AttributeRegistry::getInstance()->getSpannersAttribute(), static_cast(spanner.data())->getBounds(), results); + // if there's nothing intersecting directly, find the closest heightfield that intersects the projection + if (results.isEmpty()) { + SpannerProjectionFetchVisitor visitor(static_cast(spanner.data())->getBounds(), results); + data.guide(visitor); + } + foreach (const SharedObjectPointer& result, results) { Spanner* newResult = static_cast(result.data())->setMaterial(spanner, material, color, paint); if (newResult != result) {