If there's no directly intersecting spanner, find the closest heightfield that

we can project onto.
This commit is contained in:
Andrzej Kapolka 2015-01-16 15:41:08 -08:00
parent 45b36b383c
commit 2497b2fe39
2 changed files with 65 additions and 8 deletions

View file

@ -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<quint8>::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] },

View file

@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <glm/gtx/transform.hpp>
#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<SharedObjectPointer>& results);
virtual bool visit(Spanner* spanner);
private:
const Box& _bounds;
QVector<SharedObjectPointer>& _results;
float _closestDistance;
};
SpannerProjectionFetchVisitor::SpannerProjectionFetchVisitor(const Box& bounds, QVector<SharedObjectPointer>& results) :
SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute()),
_bounds(bounds),
_results(results),
_closestDistance(FLT_MAX) {
}
bool SpannerProjectionFetchVisitor::visit(Spanner* spanner) {
Heightfield* heightfield = qobject_cast<Heightfield*>(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*>(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*>(spanner.data())->getBounds(), results);
data.guide(visitor);
}
foreach (const SharedObjectPointer& result, results) {
Spanner* newResult = static_cast<Spanner*>(result.data())->setMaterial(spanner, material, color, paint);
if (newResult != result) {