Various fixes and what-not, got the basic spanner clipping working.

This commit is contained in:
Andrzej Kapolka 2014-03-31 18:21:28 -07:00
parent 10588cff9f
commit 005ae79928
9 changed files with 363 additions and 65 deletions

View file

@ -167,14 +167,14 @@ void MetavoxelSystem::maybeAttachClient(const SharedNodePointer& node) {
MetavoxelSystem::SimulateVisitor::SimulateVisitor(QVector<Point>& points) : MetavoxelSystem::SimulateVisitor::SimulateVisitor(QVector<Point>& points) :
SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute(), SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute(),
QVector<AttributePointer>() << AttributeRegistry::getInstance()->getColorAttribute() << QVector<AttributePointer>(), QVector<AttributePointer>() << AttributeRegistry::getInstance()->getColorAttribute() <<
AttributeRegistry::getInstance()->getNormalAttribute() << AttributeRegistry::getInstance()->getNormalAttribute() <<
AttributeRegistry::getInstance()->getSpannerColorAttribute() << AttributeRegistry::getInstance()->getSpannerColorAttribute() <<
AttributeRegistry::getInstance()->getSpannerNormalAttribute()), AttributeRegistry::getInstance()->getSpannerNormalAttribute()),
_points(points) { _points(points) {
} }
bool MetavoxelSystem::SimulateVisitor::visit(Spanner* spanner) { bool MetavoxelSystem::SimulateVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) {
spanner->getRenderer()->simulate(_deltaTime); spanner->getRenderer()->simulate(_deltaTime);
return true; return true;
} }
@ -223,11 +223,12 @@ int MetavoxelSystem::SimulateVisitor::visit(MetavoxelInfo& info) {
} }
MetavoxelSystem::RenderVisitor::RenderVisitor() : MetavoxelSystem::RenderVisitor::RenderVisitor() :
SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute()) { SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute(),
QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannerMaskAttribute()) {
} }
bool MetavoxelSystem::RenderVisitor::visit(Spanner* spanner) { bool MetavoxelSystem::RenderVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) {
spanner->getRenderer()->render(1.0f); spanner->getRenderer()->render(1.0f, clipMinimum, clipSize);
return true; return true;
} }
@ -333,10 +334,55 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) {
} }
} }
static void enableClipPlane(GLenum plane, float x, float y, float z, float w) {
GLdouble coefficients[] = { x, y, z, w };
glClipPlane(plane, coefficients);
glEnable(plane);
}
void ClippedRenderer::render(float alpha, const glm::vec3& clipMinimum, float clipSize) {
if (clipSize == 0.0f) {
renderUnclipped(alpha);
return;
}
enableClipPlane(GL_CLIP_PLANE0, -1.0f, 0.0f, 0.0f, clipMinimum.x + clipSize);
enableClipPlane(GL_CLIP_PLANE1, 1.0f, 0.0f, 0.0f, -clipMinimum.x);
enableClipPlane(GL_CLIP_PLANE2, 0.0f, -1.0f, 0.0f, clipMinimum.y + clipSize);
enableClipPlane(GL_CLIP_PLANE3, 0.0f, 1.0f, 0.0f, -clipMinimum.y);
enableClipPlane(GL_CLIP_PLANE4, 0.0f, 0.0f, -1.0f, clipMinimum.z + clipSize);
enableClipPlane(GL_CLIP_PLANE5, 0.0f, 0.0f, 1.0f, -clipMinimum.z);
renderUnclipped(alpha);
glDisable(GL_CLIP_PLANE0);
glDisable(GL_CLIP_PLANE1);
glDisable(GL_CLIP_PLANE2);
glDisable(GL_CLIP_PLANE3);
glDisable(GL_CLIP_PLANE4);
glDisable(GL_CLIP_PLANE5);
}
SphereRenderer::SphereRenderer() { SphereRenderer::SphereRenderer() {
} }
void SphereRenderer::render(float alpha) { void SphereRenderer::render(float alpha, const glm::vec3& clipMinimum, float clipSize) {
if (clipSize == 0.0f) {
renderUnclipped(alpha);
return;
}
// slight performance optimization: don't render if clip bounds are entirely within sphere
Sphere* sphere = static_cast<Sphere*>(parent());
Box clipBox(clipMinimum, clipMinimum + glm::vec3(clipSize, clipSize, clipSize));
for (int i = 0; i < Box::VERTEX_COUNT; i++) {
const float CLIP_PROPORTION = 0.95f;
if (glm::distance(sphere->getTranslation(), clipBox.getVertex(i)) >= sphere->getScale() * CLIP_PROPORTION) {
ClippedRenderer::render(alpha, clipMinimum, clipSize);
return;
}
}
}
void SphereRenderer::renderUnclipped(float alpha) {
Sphere* sphere = static_cast<Sphere*>(parent()); Sphere* sphere = static_cast<Sphere*>(parent());
const QColor& color = sphere->getColor(); const QColor& color = sphere->getColor();
glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF() * alpha); glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF() * alpha);
@ -384,11 +430,12 @@ void StaticModelRenderer::simulate(float deltaTime) {
_model->simulate(deltaTime); _model->simulate(deltaTime);
} }
void StaticModelRenderer::render(float alpha) { void StaticModelRenderer::renderUnclipped(float alpha) {
_model->render(alpha); _model->render(alpha);
} }
bool StaticModelRenderer::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const { bool StaticModelRenderer::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const {
return _model->findRayIntersection(origin, direction, distance); return _model->findRayIntersection(origin, direction, distance);
} }

View file

@ -61,7 +61,7 @@ private:
SimulateVisitor(QVector<Point>& points); SimulateVisitor(QVector<Point>& points);
void setDeltaTime(float deltaTime) { _deltaTime = deltaTime; } void setDeltaTime(float deltaTime) { _deltaTime = deltaTime; }
void setOrder(const glm::vec3& direction) { _order = encodeOrder(direction); } void setOrder(const glm::vec3& direction) { _order = encodeOrder(direction); }
virtual bool visit(Spanner* spanner); virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize);
virtual int visit(MetavoxelInfo& info); virtual int visit(MetavoxelInfo& info);
private: private:
@ -73,7 +73,7 @@ private:
class RenderVisitor : public SpannerVisitor { class RenderVisitor : public SpannerVisitor {
public: public:
RenderVisitor(); RenderVisitor();
virtual bool visit(Spanner* spanner); virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize);
}; };
static ProgramObject _program; static ProgramObject _program;
@ -141,19 +141,36 @@ private:
QList<ReceiveRecord> _receiveRecords; QList<ReceiveRecord> _receiveRecords;
}; };
/// Base class for spanner renderers; provides clipping.
class ClippedRenderer : public SpannerRenderer {
Q_OBJECT
public:
virtual void render(float alpha, const glm::vec3& clipMinimum, float clipSize);
protected:
virtual void renderUnclipped(float alpha) = 0;
};
/// Renders spheres. /// Renders spheres.
class SphereRenderer : public SpannerRenderer { class SphereRenderer : public ClippedRenderer {
Q_OBJECT Q_OBJECT
public: public:
Q_INVOKABLE SphereRenderer(); Q_INVOKABLE SphereRenderer();
virtual void render(float alpha); virtual void render(float alpha, const glm::vec3& clipMinimum, float clipSize);
protected:
virtual void renderUnclipped(float alpha);
}; };
/// Renders static models. /// Renders static models.
class StaticModelRenderer : public SpannerRenderer { class StaticModelRenderer : public ClippedRenderer {
Q_OBJECT Q_OBJECT
public: public:
@ -162,8 +179,12 @@ public:
virtual void init(Spanner* spanner); virtual void init(Spanner* spanner);
virtual void simulate(float deltaTime); virtual void simulate(float deltaTime);
virtual void render(float alpha); virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const; const glm::vec3& clipMinimum, float clipSize, float& distance) const;
protected:
virtual void renderUnclipped(float alpha);
private slots: private slots:

View file

@ -565,7 +565,7 @@ void PlaceSpannerTool::render() {
} }
Spanner* spanner = static_cast<Spanner*>(_editor->getValue().value<SharedObjectPointer>().data()); Spanner* spanner = static_cast<Spanner*>(_editor->getValue().value<SharedObjectPointer>().data());
const float SPANNER_ALPHA = 0.25f; const float SPANNER_ALPHA = 0.25f;
spanner->getRenderer()->render(SPANNER_ALPHA); spanner->getRenderer()->render(SPANNER_ALPHA, glm::vec3(), 0.0f);
} }
bool PlaceSpannerTool::appliesTo(const AttributePointer& attribute) const { bool PlaceSpannerTool::appliesTo(const AttributePointer& attribute) const {

View file

@ -11,6 +11,7 @@
#include "AttributeRegistry.h" #include "AttributeRegistry.h"
#include "MetavoxelData.h" #include "MetavoxelData.h"
REGISTER_META_OBJECT(FloatAttribute)
REGISTER_META_OBJECT(QRgbAttribute) REGISTER_META_OBJECT(QRgbAttribute)
REGISTER_META_OBJECT(PackedNormalAttribute) REGISTER_META_OBJECT(PackedNormalAttribute)
REGISTER_META_OBJECT(SpannerQRgbAttribute) REGISTER_META_OBJECT(SpannerQRgbAttribute)
@ -34,7 +35,8 @@ AttributeRegistry::AttributeRegistry() :
_colorAttribute(registerAttribute(new QRgbAttribute("color"))), _colorAttribute(registerAttribute(new QRgbAttribute("color"))),
_normalAttribute(registerAttribute(new PackedNormalAttribute("normal"))), _normalAttribute(registerAttribute(new PackedNormalAttribute("normal"))),
_spannerColorAttribute(registerAttribute(new SpannerQRgbAttribute("spannerColor"))), _spannerColorAttribute(registerAttribute(new SpannerQRgbAttribute("spannerColor"))),
_spannerNormalAttribute(registerAttribute(new SpannerPackedNormalAttribute("spannerNormal"))) { _spannerNormalAttribute(registerAttribute(new SpannerPackedNormalAttribute("spannerNormal"))),
_spannerMaskAttribute(registerAttribute(new FloatAttribute("spannerMask"))) {
// our baseline LOD threshold is for voxels; spanners are a different story // our baseline LOD threshold is for voxels; spanners are a different story
const float SPANNER_LOD_THRESHOLD_MULTIPLIER = 8.0f; const float SPANNER_LOD_THRESHOLD_MULTIPLIER = 8.0f;
@ -198,6 +200,10 @@ void Attribute::writeMetavoxelSubdivision(const MetavoxelNode& root, MetavoxelSt
root.writeSubdivision(state); root.writeSubdivision(state);
} }
FloatAttribute::FloatAttribute(const QString& name, float defaultValue) :
SimpleInlineAttribute<float>(name, defaultValue) {
}
QRgbAttribute::QRgbAttribute(const QString& name, QRgb defaultValue) : QRgbAttribute::QRgbAttribute(const QString& name, QRgb defaultValue) :
InlineAttribute<QRgb>(name, defaultValue) { InlineAttribute<QRgb>(name, defaultValue) {
} }

View file

@ -80,6 +80,9 @@ public:
/// Returns a reference to the standard packed normal "spannerNormal" attribute. /// Returns a reference to the standard packed normal "spannerNormal" attribute.
const AttributePointer& getSpannerNormalAttribute() const { return _spannerNormalAttribute; } const AttributePointer& getSpannerNormalAttribute() const { return _spannerNormalAttribute; }
/// Returns a reference to the standard "spannerMask" attribute.
const AttributePointer& getSpannerMaskAttribute() const { return _spannerMaskAttribute; }
private: private:
static QScriptValue getAttribute(QScriptContext* context, QScriptEngine* engine); static QScriptValue getAttribute(QScriptContext* context, QScriptEngine* engine);
@ -91,6 +94,7 @@ private:
AttributePointer _normalAttribute; AttributePointer _normalAttribute;
AttributePointer _spannerColorAttribute; AttributePointer _spannerColorAttribute;
AttributePointer _spannerNormalAttribute; AttributePointer _spannerNormalAttribute;
AttributePointer _spannerMaskAttribute;
}; };
/// Converts a value to a void pointer. /// Converts a value to a void pointer.
@ -265,6 +269,39 @@ template<class T, int bits> inline void InlineAttribute<T, bits>::write(Bitstrea
} }
} }
/// Provides averaging using the +=, ==, and / operators.
template<class T, int bits = 32> class SimpleInlineAttribute : public InlineAttribute<T, bits> {
public:
SimpleInlineAttribute(const QString& name, const T& defaultValue = T()) : InlineAttribute<T, bits>(name, defaultValue) { }
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
};
template<class T, int bits> inline bool SimpleInlineAttribute<T, bits>::merge(
void*& parent, void* children[], bool postRead) const {
T firstValue = decodeInline<T>(children[0]);
T totalValue = firstValue;
bool allChildrenEqual = true;
for (int i = 1; i < Attribute::MERGE_COUNT; i++) {
T value = decodeInline<T>(children[i]);
totalValue += value;
allChildrenEqual &= (firstValue == value);
}
parent = encodeInline(totalValue / Attribute::MERGE_COUNT);
return allChildrenEqual;
}
/// Simple float attribute.
class FloatAttribute : public SimpleInlineAttribute<float> {
Q_OBJECT
Q_PROPERTY(float defaultValue MEMBER _defaultValue)
public:
Q_INVOKABLE FloatAttribute(const QString& name = QString(), float defaultValue = 0.0f);
};
/// Provides appropriate averaging for RGBA values. /// Provides appropriate averaging for RGBA values.
class QRgbAttribute : public InlineAttribute<QRgb> { class QRgbAttribute : public InlineAttribute<QRgb> {
Q_OBJECT Q_OBJECT

View file

@ -223,12 +223,12 @@ void Bitstream::persistReadMappings(const ReadMappings& mappings) {
if (!it.value()) { if (!it.value()) {
continue; continue;
} }
QPointer<SharedObject>& reference = _sharedObjectReferences[it.value()->getID()]; QPointer<SharedObject>& reference = _sharedObjectReferences[it.value()->getRemoteID()];
if (reference) { if (reference) {
_sharedObjectStreamer.removePersistentValue(reference.data()); _sharedObjectStreamer.removePersistentValue(reference.data());
} }
reference = it.value(); reference = it.value();
_weakSharedObjectHash.remove(it.value()->getID()); _weakSharedObjectHash.remove(it.value()->getRemoteID());
} }
} }

View file

@ -212,6 +212,67 @@ void MetavoxelData::toggle(const AttributePointer& attribute, const Box& bounds,
guide(visitor); guide(visitor);
} }
void MetavoxelData::replace(const AttributePointer& attribute, const SharedObjectPointer& oldObject,
const SharedObjectPointer& newObject) {
Spanner* spanner = static_cast<Spanner*>(oldObject.data());
replace(attribute, spanner->getBounds(), spanner->getPlacementGranularity(), oldObject, newObject);
}
class SpannerReplaceVisitor : public MetavoxelVisitor {
public:
SpannerReplaceVisitor(const AttributePointer& attribute, const Box& bounds,
float granularity, const SharedObjectPointer& oldObject, const SharedObjectPointer& newObject);
virtual int visit(MetavoxelInfo& info);
private:
const AttributePointer& _attribute;
const Box& _bounds;
float _longestSide;
const SharedObjectPointer& _oldObject;
const SharedObjectPointer& _newObject;
};
SpannerReplaceVisitor::SpannerReplaceVisitor(const AttributePointer& attribute, const Box& bounds, float granularity,
const SharedObjectPointer& oldObject, const SharedObjectPointer& newObject) :
MetavoxelVisitor(QVector<AttributePointer>() << attribute, QVector<AttributePointer>() << attribute),
_attribute(attribute),
_bounds(bounds),
_longestSide(qMax(bounds.getLongestSide(), granularity)),
_oldObject(oldObject),
_newObject(newObject) {
}
int SpannerReplaceVisitor::visit(MetavoxelInfo& info) {
if (!info.getBounds().intersects(_bounds)) {
return STOP_RECURSION;
}
if (info.size > _longestSide) {
return DEFAULT_ORDER;
}
SharedObjectSet set = info.inputValues.at(0).getInlineValue<SharedObjectSet>();
if (set.remove(_oldObject)) {
set.insert(_newObject);
}
info.outputValues[0] = AttributeValue(_attribute, encodeInline(set));
return STOP_RECURSION;
}
void MetavoxelData::replace(const AttributePointer& attribute, const Box& bounds, float granularity,
const SharedObjectPointer& oldObject, const SharedObjectPointer& newObject) {
Spanner* newSpanner = static_cast<Spanner*>(newObject.data());
if (bounds != newSpanner->getBounds() || granularity != newSpanner->getPlacementGranularity()) {
// if the bounds have changed, we must remove and reinsert
remove(attribute, bounds, granularity, oldObject);
insert(attribute, newSpanner->getBounds(), newSpanner->getPlacementGranularity(), newObject);
return;
}
SpannerReplaceVisitor visitor(attribute, bounds, granularity, oldObject, newObject);
guide(visitor);
}
void MetavoxelData::clear(const AttributePointer& attribute) { void MetavoxelData::clear(const AttributePointer& attribute) {
MetavoxelNode* node = _roots.take(attribute); MetavoxelNode* node = _roots.take(attribute);
if (node) { if (node) {
@ -239,7 +300,7 @@ private:
FirstRaySpannerIntersectionVisitor::FirstRaySpannerIntersectionVisitor( FirstRaySpannerIntersectionVisitor::FirstRaySpannerIntersectionVisitor(
const glm::vec3& origin, const glm::vec3& direction, const AttributePointer& attribute, const MetavoxelLOD& lod) : const glm::vec3& origin, const glm::vec3& direction, const AttributePointer& attribute, const MetavoxelLOD& lod) :
RaySpannerIntersectionVisitor(origin, direction, QVector<AttributePointer>() << attribute, RaySpannerIntersectionVisitor(origin, direction, QVector<AttributePointer>() << attribute,
QVector<AttributePointer>(), QVector<AttributePointer>(), lod), QVector<AttributePointer>(), QVector<AttributePointer>(), QVector<AttributePointer>(), lod),
_spanner(NULL) { _spanner(NULL) {
} }
@ -878,10 +939,11 @@ void MetavoxelVisitor::prepare() {
// nothing by default // nothing by default
} }
SpannerVisitor::SpannerVisitor(const QVector<AttributePointer>& spannerInputs, const QVector<AttributePointer>& inputs, SpannerVisitor::SpannerVisitor(const QVector<AttributePointer>& spannerInputs, const QVector<AttributePointer>& spannerMasks,
const QVector<AttributePointer>& outputs, const MetavoxelLOD& lod) : const QVector<AttributePointer>& inputs, const QVector<AttributePointer>& outputs, const MetavoxelLOD& lod) :
MetavoxelVisitor(inputs + spannerInputs, outputs, lod), MetavoxelVisitor(inputs + spannerInputs + spannerMasks, outputs, lod),
_spannerInputCount(spannerInputs.size()) { _spannerInputCount(spannerInputs.size()),
_spannerMaskCount(spannerMasks.size()) {
} }
void SpannerVisitor::prepare() { void SpannerVisitor::prepare() {
@ -889,17 +951,34 @@ void SpannerVisitor::prepare() {
} }
int SpannerVisitor::visit(MetavoxelInfo& info) { int SpannerVisitor::visit(MetavoxelInfo& info) {
for (int i = _inputs.size() - _spannerInputCount; i < _inputs.size(); i++) { for (int end = _inputs.size() - _spannerMaskCount, i = end - _spannerInputCount, j = end; i < end; i++, j++) {
foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue<SharedObjectSet>()) { foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue<SharedObjectSet>()) {
Spanner* spanner = static_cast<Spanner*>(object.data()); Spanner* spanner = static_cast<Spanner*>(object.data());
if (spanner->testAndSetVisited()) { if (!(spanner->isMasked() && j < _inputs.size()) && spanner->testAndSetVisited() &&
if (!visit(spanner)) { !visit(spanner, glm::vec3(), 0.0f)) {
return SHORT_CIRCUIT; return SHORT_CIRCUIT;
} }
} }
} }
if (!info.isLeaf) {
return DEFAULT_ORDER;
} }
return info.isLeaf ? STOP_RECURSION : DEFAULT_ORDER; for (int i = _inputs.size() - _spannerMaskCount; i < _inputs.size(); i++) {
float maskValue = info.inputValues.at(i).getInlineValue<float>();
if (maskValue < 0.5f) {
const MetavoxelInfo* nextInfo = &info;
do {
foreach (const SharedObjectPointer& object, nextInfo->inputValues.at(
i - _spannerInputCount).getInlineValue<SharedObjectSet>()) {
Spanner* spanner = static_cast<Spanner*>(object.data());
if (spanner->isMasked() && !visit(spanner, info.minimum, info.size)) {
return SHORT_CIRCUIT;
}
}
} while ((nextInfo = nextInfo->parentInfo));
}
}
return STOP_RECURSION;
} }
RayIntersectionVisitor::RayIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, RayIntersectionVisitor::RayIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction,
@ -919,10 +998,11 @@ int RayIntersectionVisitor::visit(MetavoxelInfo& info) {
} }
RaySpannerIntersectionVisitor::RaySpannerIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, RaySpannerIntersectionVisitor::RaySpannerIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction,
const QVector<AttributePointer>& spannerInputs, const QVector<AttributePointer>& inputs, const QVector<AttributePointer>& spannerInputs, const QVector<AttributePointer>& spannerMasks,
const QVector<AttributePointer>& outputs, const MetavoxelLOD& lod) : const QVector<AttributePointer>& inputs, const QVector<AttributePointer>& outputs, const MetavoxelLOD& lod) :
RayIntersectionVisitor(origin, direction, inputs + spannerInputs, outputs, lod), RayIntersectionVisitor(origin, direction, inputs + spannerInputs + spannerMasks, outputs, lod),
_spannerInputCount(spannerInputs.size()) { _spannerInputCount(spannerInputs.size()),
_spannerMaskCount(spannerMasks.size()) {
} }
void RaySpannerIntersectionVisitor::prepare() { void RaySpannerIntersectionVisitor::prepare() {
@ -941,12 +1021,12 @@ bool operator<(const SpannerDistance& first, const SpannerDistance& second) {
int RaySpannerIntersectionVisitor::visit(MetavoxelInfo& info, float distance) { int RaySpannerIntersectionVisitor::visit(MetavoxelInfo& info, float distance) {
QVarLengthArray<SpannerDistance, 4> spannerDistances; QVarLengthArray<SpannerDistance, 4> spannerDistances;
for (int i = _inputs.size() - _spannerInputCount; i < _inputs.size(); i++) { for (int end = _inputs.size() - _spannerMaskCount, i = end - _spannerInputCount, j = end; i < end; i++, j++) {
foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue<SharedObjectSet>()) { foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue<SharedObjectSet>()) {
Spanner* spanner = static_cast<Spanner*>(object.data()); Spanner* spanner = static_cast<Spanner*>(object.data());
if (spanner->testAndSetVisited()) { if (!(spanner->isMasked() && j < _inputs.size()) && spanner->testAndSetVisited()) {
SpannerDistance spannerDistance = { spanner }; SpannerDistance spannerDistance = { spanner };
if (spanner->findRayIntersection(_origin, _direction, spannerDistance.distance)) { if (spanner->findRayIntersection(_origin, _direction, glm::vec3(), 0.0f, spannerDistance.distance)) {
spannerDistances.append(spannerDistance); spannerDistances.append(spannerDistance);
} }
} }
@ -958,7 +1038,36 @@ int RaySpannerIntersectionVisitor::visit(MetavoxelInfo& info, float distance) {
} }
} }
} }
return info.isLeaf ? STOP_RECURSION : _order; if (!info.isLeaf) {
return _order;
}
for (int i = _inputs.size() - _spannerMaskCount; i < _inputs.size(); i++) {
float maskValue = info.inputValues.at(i).getInlineValue<float>();
if (maskValue < 0.5f) {
const MetavoxelInfo* nextInfo = &info;
do {
foreach (const SharedObjectPointer& object, nextInfo->inputValues.at(
i - _spannerInputCount).getInlineValue<SharedObjectSet>()) {
Spanner* spanner = static_cast<Spanner*>(object.data());
if (spanner->isMasked()) {
SpannerDistance spannerDistance = { spanner };
if (spanner->findRayIntersection(_origin, _direction,
info.minimum, info.size, spannerDistance.distance)) {
spannerDistances.append(spannerDistance);
}
}
}
} while ((nextInfo = nextInfo->parentInfo));
qStableSort(spannerDistances);
foreach (const SpannerDistance& spannerDistance, spannerDistances) {
if (!visitSpanner(spannerDistance.spanner, spannerDistance.distance)) {
return SHORT_CIRCUIT;
}
}
}
}
return STOP_RECURSION;
} }
DefaultMetavoxelGuide::DefaultMetavoxelGuide() { DefaultMetavoxelGuide::DefaultMetavoxelGuide() {
@ -1224,6 +1333,7 @@ Spanner::Spanner() :
_renderer(NULL), _renderer(NULL),
_placementGranularity(DEFAULT_PLACEMENT_GRANULARITY), _placementGranularity(DEFAULT_PLACEMENT_GRANULARITY),
_voxelizationGranularity(DEFAULT_VOXELIZATION_GRANULARITY), _voxelizationGranularity(DEFAULT_VOXELIZATION_GRANULARITY),
_masked(false),
_lastVisit(0) { _lastVisit(0) {
} }
@ -1276,7 +1386,8 @@ SpannerRenderer* Spanner::getRenderer() {
return _renderer; return _renderer;
} }
bool Spanner::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const { bool Spanner::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const {
return _bounds.findRayIntersection(origin, direction, distance); return _bounds.findRayIntersection(origin, direction, distance);
} }
@ -1297,11 +1408,12 @@ void SpannerRenderer::simulate(float deltaTime) {
// nothing by default // nothing by default
} }
void SpannerRenderer::render(float alpha) { void SpannerRenderer::render(float alpha, const glm::vec3& clipMinimum, float clipSize) {
// nothing by default // nothing by default
} }
bool SpannerRenderer::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const { bool SpannerRenderer::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const {
return false; return false;
} }
@ -1424,7 +1536,8 @@ bool Sphere::blendAttributeValues(MetavoxelInfo& info, bool force) const {
return true; return true;
} }
bool Sphere::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const { bool Sphere::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const {
return findRaySphereIntersection(origin, direction, getTranslation(), getScale(), distance); return findRaySphereIntersection(origin, direction, getTranslation(), getScale(), distance);
} }
@ -1463,10 +1576,11 @@ void StaticModel::setURL(const QUrl& url) {
} }
} }
bool StaticModel::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const { bool StaticModel::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const {
// delegate to renderer, if we have one // delegate to renderer, if we have one
return _renderer ? _renderer->findRayIntersection(origin, direction, distance) : return _renderer ? _renderer->findRayIntersection(origin, direction, clipMinimum, clipSize, distance) :
Spanner::findRayIntersection(origin, direction, distance); Spanner::findRayIntersection(origin, direction, clipMinimum, clipSize, distance);
} }
QByteArray StaticModel::getRendererClassName() const { QByteArray StaticModel::getRendererClassName() const {

View file

@ -79,6 +79,11 @@ public:
void toggle(const AttributePointer& attribute, const SharedObjectPointer& object); void toggle(const AttributePointer& attribute, const SharedObjectPointer& object);
void toggle(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object); void toggle(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object);
void replace(const AttributePointer& attribute, const SharedObjectPointer& oldObject,
const SharedObjectPointer& newObject);
void replace(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& oldObject,
const SharedObjectPointer& newObject);
void clear(const AttributePointer& attribute); void clear(const AttributePointer& attribute);
/// Convenience function that finds the first spanner intersecting the provided ray. /// Convenience function that finds the first spanner intersecting the provided ray.
@ -255,13 +260,15 @@ class SpannerVisitor : public MetavoxelVisitor {
public: public:
SpannerVisitor(const QVector<AttributePointer>& spannerInputs, SpannerVisitor(const QVector<AttributePointer>& spannerInputs,
const QVector<AttributePointer>& spannerMasks = QVector<AttributePointer>(),
const QVector<AttributePointer>& inputs = QVector<AttributePointer>(), const QVector<AttributePointer>& inputs = QVector<AttributePointer>(),
const QVector<AttributePointer>& outputs = QVector<AttributePointer>(), const QVector<AttributePointer>& outputs = QVector<AttributePointer>(),
const MetavoxelLOD& lod = MetavoxelLOD()); const MetavoxelLOD& lod = MetavoxelLOD());
/// Visits a spanner. /// Visits a spanner (or part thereof).
/// \param clipSize the size of the clip volume, or zero if unclipped
/// \return true to continue, false to short-circuit the tour /// \return true to continue, false to short-circuit the tour
virtual bool visit(Spanner* spanner) = 0; virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) = 0;
virtual void prepare(); virtual void prepare();
virtual int visit(MetavoxelInfo& info); virtual int visit(MetavoxelInfo& info);
@ -269,6 +276,7 @@ public:
protected: protected:
int _spannerInputCount; int _spannerInputCount;
int _spannerMaskCount;
}; };
/// Base class for ray intersection visitors. /// Base class for ray intersection visitors.
@ -298,11 +306,12 @@ public:
RaySpannerIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, RaySpannerIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction,
const QVector<AttributePointer>& spannerInputs, const QVector<AttributePointer>& spannerInputs,
const QVector<AttributePointer>& spannerMasks = QVector<AttributePointer>(),
const QVector<AttributePointer>& inputs = QVector<AttributePointer>(), const QVector<AttributePointer>& inputs = QVector<AttributePointer>(),
const QVector<AttributePointer>& outputs = QVector<AttributePointer>(), const QVector<AttributePointer>& outputs = QVector<AttributePointer>(),
const MetavoxelLOD& lod = MetavoxelLOD()); const MetavoxelLOD& lod = MetavoxelLOD());
/// Visits a spanner that the ray intersects. /// Visits a spannerthat the ray intersects.
/// \return true to continue, false to short-circuit the tour /// \return true to continue, false to short-circuit the tour
virtual bool visitSpanner(Spanner* spanner, float distance) = 0; virtual bool visitSpanner(Spanner* spanner, float distance) = 0;
@ -312,6 +321,7 @@ public:
protected: protected:
int _spannerInputCount; int _spannerInputCount;
int _spannerMaskCount;
}; };
/// Interface for objects that guide metavoxel visitors. /// Interface for objects that guide metavoxel visitors.
@ -412,6 +422,7 @@ class Spanner : public SharedObject {
Q_PROPERTY(Box bounds MEMBER _bounds WRITE setBounds NOTIFY boundsChanged DESIGNABLE false) Q_PROPERTY(Box bounds MEMBER _bounds WRITE setBounds NOTIFY boundsChanged DESIGNABLE false)
Q_PROPERTY(float placementGranularity MEMBER _placementGranularity DESIGNABLE false) Q_PROPERTY(float placementGranularity MEMBER _placementGranularity DESIGNABLE false)
Q_PROPERTY(float voxelizationGranularity MEMBER _voxelizationGranularity DESIGNABLE false) Q_PROPERTY(float voxelizationGranularity MEMBER _voxelizationGranularity DESIGNABLE false)
Q_PROPERTY(float masked MEMBER _masked DESIGNABLE false)
public: public:
@ -429,6 +440,9 @@ public:
void setVoxelizationGranularity(float granularity) { _voxelizationGranularity = granularity; } void setVoxelizationGranularity(float granularity) { _voxelizationGranularity = granularity; }
float getVoxelizationGranularity() const { return _voxelizationGranularity; } float getVoxelizationGranularity() const { return _voxelizationGranularity; }
void setMasked(bool masked) { _masked = masked; }
bool isMasked() const { return _masked; }
/// Returns a reference to the list of attributes associated with this spanner. /// Returns a reference to the list of attributes associated with this spanner.
virtual const QVector<AttributePointer>& getAttributes() const; virtual const QVector<AttributePointer>& getAttributes() const;
@ -452,7 +466,9 @@ public:
SpannerRenderer* getRenderer(); SpannerRenderer* getRenderer();
/// Finds the intersection between the described ray and this spanner. /// Finds the intersection between the described ray and this spanner.
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const; /// \param clipSize the size of the clip region, or zero if unclipped
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const;
signals: signals:
@ -471,6 +487,7 @@ private:
Box _bounds; Box _bounds;
float _placementGranularity; float _placementGranularity;
float _voxelizationGranularity; float _voxelizationGranularity;
bool _masked;
int _lastVisit; ///< the identifier of the last visit int _lastVisit; ///< the identifier of the last visit
static int _visit; ///< the global visit counter static int _visit; ///< the global visit counter
@ -486,8 +503,9 @@ public:
virtual void init(Spanner* spanner); virtual void init(Spanner* spanner);
virtual void simulate(float deltaTime); virtual void simulate(float deltaTime);
virtual void render(float alpha); virtual void render(float alpha, const glm::vec3& clipMinimum, float clipSize);
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const; virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const;
}; };
/// An object with a 3D transform. /// An object with a 3D transform.
@ -539,7 +557,8 @@ public:
virtual const QVector<AttributePointer>& getVoxelizedAttributes() const; virtual const QVector<AttributePointer>& getVoxelizedAttributes() const;
virtual bool getAttributeValues(MetavoxelInfo& info, bool force = false) const; virtual bool getAttributeValues(MetavoxelInfo& info, bool force = false) const;
virtual bool blendAttributeValues(MetavoxelInfo& info, bool force = false) const; virtual bool blendAttributeValues(MetavoxelInfo& info, bool force = false) const;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const; virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const;
signals: signals:
@ -572,7 +591,8 @@ public:
void setURL(const QUrl& url); void setURL(const QUrl& url);
const QUrl& getURL() const { return _url; } const QUrl& getURL() const { return _url; }
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const; virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize,float& distance) const;
signals: signals:

View file

@ -32,7 +32,8 @@ private:
}; };
BoxSetEditVisitor::BoxSetEditVisitor(const BoxSetEdit& edit) : BoxSetEditVisitor::BoxSetEditVisitor(const BoxSetEdit& edit) :
MetavoxelVisitor(QVector<AttributePointer>(), QVector<AttributePointer>() << edit.value.getAttribute()), MetavoxelVisitor(QVector<AttributePointer>(), QVector<AttributePointer>() << edit.value.getAttribute() <<
AttributeRegistry::getInstance()->getSpannerMaskAttribute()),
_edit(edit) { _edit(edit) {
} }
@ -47,25 +48,68 @@ int BoxSetEditVisitor::visit(MetavoxelInfo& info) {
float volume = (size.x * size.y * size.z) / (info.size * info.size * info.size); float volume = (size.x * size.y * size.z) / (info.size * info.size * info.size);
if (volume >= 1.0f) { if (volume >= 1.0f) {
info.outputValues[0] = _edit.value; info.outputValues[0] = _edit.value;
info.outputValues[1] = AttributeValue(_outputs.at(1), encodeInline<float>(1.0f));
return STOP_RECURSION; // entirely contained return STOP_RECURSION; // entirely contained
} }
if (info.size <= _edit.granularity) { if (info.size <= _edit.granularity) {
if (volume >= 0.5f) { if (volume >= 0.5f) {
info.outputValues[0] = _edit.value; info.outputValues[0] = _edit.value;
info.outputValues[1] = AttributeValue(_outputs.at(1), encodeInline<float>(1.0f));
} }
return STOP_RECURSION; // reached granularity limit; take best guess return STOP_RECURSION; // reached granularity limit; take best guess
} }
return DEFAULT_ORDER; // subdivide return DEFAULT_ORDER; // subdivide
} }
class GatherUnmaskedSpannersVisitor : public SpannerVisitor {
public:
GatherUnmaskedSpannersVisitor(const Box& bounds);
const QList<SharedObjectPointer>& getUnmaskedSpanners() const { return _unmaskedSpanners; }
virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize);
private:
Box _bounds;
QList<SharedObjectPointer> _unmaskedSpanners;
};
GatherUnmaskedSpannersVisitor::GatherUnmaskedSpannersVisitor(const Box& bounds) :
SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute()),
_bounds(bounds) {
}
bool GatherUnmaskedSpannersVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) {
if (!spanner->isMasked() && spanner->getBounds().intersects(_bounds)) {
_unmaskedSpanners.append(spanner);
}
return true;
}
static void setIntersectingMasked(const Box& bounds, MetavoxelData& data) {
GatherUnmaskedSpannersVisitor visitor(bounds);
data.guide(visitor);
foreach (const SharedObjectPointer& object, visitor.getUnmaskedSpanners()) {
Spanner* newSpanner = static_cast<Spanner*>(object->clone(true));
newSpanner->setMasked(true);
data.replace(AttributeRegistry::getInstance()->getSpannersAttribute(), object, newSpanner);
}
}
void BoxSetEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { void BoxSetEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
// expand to fit the entire edit // expand to fit the entire edit
while (!data.getBounds().contains(region)) { while (!data.getBounds().contains(region)) {
data.expand(); data.expand();
} }
BoxSetEditVisitor visitor(*this); BoxSetEditVisitor setVisitor(*this);
data.guide(visitor); data.guide(setVisitor);
// flip the mask flag of all intersecting spanners
setIntersectingMasked(region, data);
} }
GlobalSetEdit::GlobalSetEdit(const OwnedAttributeValue& value) : GlobalSetEdit::GlobalSetEdit(const OwnedAttributeValue& value) :
@ -180,25 +224,25 @@ ClearSpannersEdit::ClearSpannersEdit(const AttributePointer& attribute) :
attribute(attribute) { attribute(attribute) {
} }
class GetSpannerAttributesVisitor : public SpannerVisitor { class GatherSpannerAttributesVisitor : public SpannerVisitor {
public: public:
GetSpannerAttributesVisitor(const AttributePointer& attribute); GatherSpannerAttributesVisitor(const AttributePointer& attribute);
const QSet<AttributePointer>& getAttributes() const { return _attributes; } const QSet<AttributePointer>& getAttributes() const { return _attributes; }
virtual bool visit(Spanner* spanner); virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize);
protected: protected:
QSet<AttributePointer> _attributes; QSet<AttributePointer> _attributes;
}; };
GetSpannerAttributesVisitor::GetSpannerAttributesVisitor(const AttributePointer& attribute) : GatherSpannerAttributesVisitor::GatherSpannerAttributesVisitor(const AttributePointer& attribute) :
SpannerVisitor(QVector<AttributePointer>() << attribute) { SpannerVisitor(QVector<AttributePointer>() << attribute) {
} }
bool GetSpannerAttributesVisitor::visit(Spanner* spanner) { bool GatherSpannerAttributesVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) {
foreach (const AttributePointer& attribute, spanner->getVoxelizedAttributes()) { foreach (const AttributePointer& attribute, spanner->getVoxelizedAttributes()) {
_attributes.insert(attribute); _attributes.insert(attribute);
} }
@ -207,7 +251,7 @@ bool GetSpannerAttributesVisitor::visit(Spanner* spanner) {
void ClearSpannersEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { void ClearSpannersEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
// find all the spanner attributes // find all the spanner attributes
GetSpannerAttributesVisitor visitor(attribute); GatherSpannerAttributesVisitor visitor(attribute);
data.guide(visitor); data.guide(visitor);
data.clear(attribute); data.clear(attribute);
@ -233,12 +277,19 @@ private:
}; };
SetSpannerEditVisitor::SetSpannerEditVisitor(const QVector<AttributePointer>& attributes, Spanner* spanner) : SetSpannerEditVisitor::SetSpannerEditVisitor(const QVector<AttributePointer>& attributes, Spanner* spanner) :
MetavoxelVisitor(attributes, attributes), MetavoxelVisitor(attributes, QVector<AttributePointer>() << attributes <<
AttributeRegistry::getInstance()->getSpannerMaskAttribute()),
_spanner(spanner) { _spanner(spanner) {
} }
int SetSpannerEditVisitor::visit(MetavoxelInfo& info) { int SetSpannerEditVisitor::visit(MetavoxelInfo& info) {
return _spanner->blendAttributeValues(info) ? DEFAULT_ORDER : STOP_RECURSION; if (_spanner->blendAttributeValues(info)) {
return DEFAULT_ORDER;
}
if (info.outputValues.at(0).getAttribute()) {
info.outputValues.last() = AttributeValue(_outputs.last(), encodeInline<float>(1.0f));
}
return STOP_RECURSION;
} }
void SetSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { void SetSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
@ -251,4 +302,6 @@ void SetSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& obje
SetSpannerEditVisitor visitor(spanner->getAttributes(), spanner); SetSpannerEditVisitor visitor(spanner->getAttributes(), spanner);
data.guide(visitor); data.guide(visitor);
setIntersectingMasked(spanner->getBounds(), data);
} }