From 5934a7fbea1209efa43488a36215067b82a73d75 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 25 Mar 2014 20:41:19 -0700 Subject: [PATCH] Working on voxelizing spanners. --- interface/interface_en.ts | 16 ++-- interface/src/MetavoxelSystem.cpp | 39 ++++++++-- interface/src/ui/MetavoxelEditor.cpp | 1 - .../metavoxels/src/AttributeRegistry.cpp | 46 +++++++++-- libraries/metavoxels/src/AttributeRegistry.h | 53 +++++++------ libraries/metavoxels/src/MetavoxelData.cpp | 77 ++++++++++++++++--- libraries/metavoxels/src/MetavoxelData.h | 26 +++++-- .../metavoxels/src/MetavoxelMessages.cpp | 50 ++++++------ 8 files changed, 220 insertions(+), 88 deletions(-) diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 689b45afcf..f5c7f225df 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -4,22 +4,22 @@ Application - + Export Voxels - + Sparse Voxel Octree Files (*.svo) - + Open Script - + JavaScript Files (*.js) @@ -113,18 +113,18 @@ Menu - + Open .ini config file - - + + Text files (*.ini) - + Save .ini config file diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 23e50176eb..a003f650f5 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -168,7 +168,9 @@ void MetavoxelSystem::maybeAttachClient(const SharedNodePointer& node) { MetavoxelSystem::SimulateVisitor::SimulateVisitor(QVector& points) : SpannerVisitor(QVector() << AttributeRegistry::getInstance()->getSpannersAttribute(), QVector() << AttributeRegistry::getInstance()->getColorAttribute() << - AttributeRegistry::getInstance()->getNormalAttribute()), + AttributeRegistry::getInstance()->getNormalAttribute() << + AttributeRegistry::getInstance()->getSpannerColorAttribute() << + AttributeRegistry::getInstance()->getSpannerNormalAttribute()), _points(points) { } @@ -186,11 +188,36 @@ int MetavoxelSystem::SimulateVisitor::visit(MetavoxelInfo& info) { QRgb color = info.inputValues.at(0).getInlineValue(); QRgb normal = info.inputValues.at(1).getInlineValue(); quint8 alpha = qAlpha(color); - if (alpha > 0) { - Point point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size), - { quint8(qRed(color)), quint8(qGreen(color)), quint8(qBlue(color)), alpha }, - { quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } }; - _points.append(point); + if (info.inputValues.at(4).getAttribute()) { + if (alpha > 0) { + Point point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size), + { quint8(qRed(color)), quint8(qGreen(color)), quint8(qBlue(color)), alpha }, + { quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } }; + _points.append(point); + } + } else { + QRgb spannerColor = info.inputValues.at(2).getInlineValue(); + QRgb spannerNormal = info.inputValues.at(3).getInlineValue(); + quint8 spannerAlpha = qAlpha(spannerColor); + if (spannerAlpha > 0) { + if (alpha > 0) { + Point point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size), + { quint8(qRed(spannerColor)), quint8(qGreen(spannerColor)), quint8(qBlue(spannerColor)), spannerAlpha }, + { quint8(qRed(spannerNormal)), quint8(qGreen(spannerNormal)), quint8(qBlue(spannerNormal)) } }; + _points.append(point); + + } else { + Point point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size), + { quint8(qRed(spannerColor)), quint8(qGreen(spannerColor)), quint8(qBlue(spannerColor)), spannerAlpha }, + { quint8(qRed(spannerNormal)), quint8(qGreen(spannerNormal)), quint8(qBlue(spannerNormal)) } }; + _points.append(point); + } + } else if (alpha > 0) { + Point point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size), + { quint8(qRed(color)), quint8(qGreen(color)), quint8(qBlue(color)), alpha }, + { quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } }; + _points.append(point); + } } return STOP_RECURSION; } diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index eed8a7b6f3..7a70cb9a4c 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -655,6 +655,5 @@ bool SetSpannerTool::appliesTo(const AttributePointer& attribute) const { } QVariant SetSpannerTool::createEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) { - static_cast(spanner.data())->setGranularity(_editor->getGridSpacing()); return QVariant::fromValue(SetSpannerEdit(spanner)); } diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 634e7d3b57..c61a8e7560 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -30,7 +30,9 @@ AttributeRegistry::AttributeRegistry() : SharedObjectPointer(new DefaultMetavoxelGuide())))), _spannersAttribute(registerAttribute(new SpannerSetAttribute("spanners", &Spanner::staticMetaObject))), _colorAttribute(registerAttribute(new QRgbAttribute("color"))), - _normalAttribute(registerAttribute(new PackedNormalAttribute("normal", qRgb(0, 127, 0)))) { + _normalAttribute(registerAttribute(new PackedNormalAttribute("normal", qRgb(0, 127, 0)))), + _spannerColorAttribute(registerAttribute(new QRgbAttribute("spannerColor"))), + _spannerNormalAttribute(registerAttribute(new PackedNormalAttribute("spannerNormal", qRgb(0, 127, 0)))) { // our baseline LOD threshold is for voxels; spanners are a different story const float SPANNER_LOD_THRESHOLD_MULTIPLIER = 4.0f; @@ -92,6 +94,10 @@ bool AttributeValue::isDefault() const { return !_attribute || _attribute->equal(_value, _attribute->getDefaultValue()); } +AttributeValue AttributeValue::split() const { + return _attribute ? _attribute->split(*this) : AttributeValue(); +} + bool AttributeValue::operator==(const AttributeValue& other) const { return _attribute == other._attribute && (!_attribute || _attribute->equal(_value, other._value)); } @@ -130,6 +136,14 @@ OwnedAttributeValue::~OwnedAttributeValue() { } } +void OwnedAttributeValue::mix(const AttributeValue& first, const AttributeValue& second, float alpha) { + if (_attribute) { + _attribute->destroy(_value); + } + _attribute = first.getAttribute(); + _value = _attribute->mix(first.getValue(), second.getValue(), alpha); +} + OwnedAttributeValue& OwnedAttributeValue::operator=(const AttributeValue& other) { if (_attribute) { _attribute->destroy(_value); @@ -206,6 +220,16 @@ bool QRgbAttribute::merge(void*& parent, void* children[]) const { return allChildrenEqual; } +void* QRgbAttribute::mix(void* first, void* second, float alpha) const { + QRgb firstValue = decodeInline(first); + QRgb secondValue = decodeInline(second); + return encodeInline(qRgba( + glm::mix((float)qRed(firstValue), (float)qRed(secondValue), alpha), + glm::mix((float)qGreen(firstValue), (float)qGreen(secondValue), alpha), + glm::mix((float)qBlue(firstValue), (float)qBlue(secondValue), alpha), + glm::mix((float)qAlpha(firstValue), (float)qAlpha(secondValue), alpha))); +} + void* QRgbAttribute::createFromScript(const QScriptValue& value, QScriptEngine* engine) const { return encodeInline((QRgb)value.toUInt32()); } @@ -232,21 +256,23 @@ PackedNormalAttribute::PackedNormalAttribute(const QString& name, QRgb defaultVa bool PackedNormalAttribute::merge(void*& parent, void* children[]) const { QRgb firstValue = decodeInline(children[0]); - int totalRed = (char)qRed(firstValue); - int totalGreen = (char)qGreen(firstValue); - int totalBlue = (char)qBlue(firstValue); + glm::vec3 total = unpackNormal(firstValue); bool allChildrenEqual = true; for (int i = 1; i < Attribute::MERGE_COUNT; i++) { QRgb value = decodeInline(children[i]); - totalRed += (char)qRed(value); - totalGreen += (char)qGreen(value); - totalBlue += (char)qBlue(value); + total += unpackNormal(value); allChildrenEqual &= (firstValue == value); } - parent = encodeInline(packNormal(glm::normalize(glm::vec3(totalRed, totalGreen, totalBlue)))); + parent = encodeInline(packNormal(glm::normalize(total))); return allChildrenEqual; } +void* PackedNormalAttribute::mix(void* first, void* second, float alpha) const { + glm::vec3 firstNormal = unpackNormal(decodeInline(first)); + glm::vec3 secondNormal = unpackNormal(decodeInline(second)); + return encodeInline(packNormal(glm::normalize(glm::mix(firstNormal, secondNormal, alpha)))); +} + const float CHAR_SCALE = 127.0f; const float INVERSE_CHAR_SCALE = 1.0f / CHAR_SCALE; @@ -290,6 +316,10 @@ bool SharedObjectAttribute::merge(void*& parent, void* children[]) const { return true; } +AttributeValue SharedObjectSetAttribute::split(const AttributeValue& parent) const { + return AttributeValue(); +} + void* SharedObjectAttribute::createFromVariant(const QVariant& value) const { return create(encodeInline(value.value())); } diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index f3dd9f4632..e0a1c0b3f0 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -71,9 +71,15 @@ public: /// Returns a reference to the standard QRgb "color" attribute. const AttributePointer& getColorAttribute() const { return _colorAttribute; } - /// Returns a reference to the standard QRgb "normal" attribute. + /// Returns a reference to the standard packed normal "normal" attribute. const AttributePointer& getNormalAttribute() const { return _normalAttribute; } + /// Returns a reference to the standard QRgb "spannerColor" attribute. + const AttributePointer& getSpannerColorAttribute() const { return _spannerColorAttribute; } + + /// Returns a reference to the standard packed normal "spannerNormal" attribute. + const AttributePointer& getSpannerNormalAttribute() const { return _spannerNormalAttribute; } + private: static QScriptValue getAttribute(QScriptContext* context, QScriptEngine* engine); @@ -83,6 +89,8 @@ private: AttributePointer _spannersAttribute; AttributePointer _colorAttribute; AttributePointer _normalAttribute; + AttributePointer _spannerColorAttribute; + AttributePointer _spannerNormalAttribute; }; /// Converts a value to a void pointer. @@ -107,13 +115,14 @@ public: template void setInlineValue(T value) { _value = encodeInline(value); } template T getInlineValue() const { return decodeInline(_value); } - - template T* getPointerValue() const { return static_cast(_value); } + template T getSafeInlineValue() const { return _attribute ? decodeInline(_value) : T(); } void* copy() const; bool isDefault() const; + AttributeValue split() const; + bool operator==(const AttributeValue& other) const; bool operator==(void* other) const; @@ -145,6 +154,9 @@ public: /// Destroys the current value, if any. ~OwnedAttributeValue(); + /// Sets this attribute to a mix of the first and second provided. + void mix(const AttributeValue& first, const AttributeValue& second, float alpha); + /// Destroys the current value, if any, and copies the specified other value. OwnedAttributeValue& operator=(const AttributeValue& other); @@ -196,6 +208,12 @@ public: /// \return whether or not the children and parent values are all equal virtual bool merge(void*& parent, void* children[]) const = 0; + /// Returns the attribute value to pass to children below leaves (either the parent, or the default, or a null value). + virtual AttributeValue split(const AttributeValue& parent) const { return parent; } + + /// Mixes the first and the second, returning a new value with the result. + virtual void* mix(void* first, void* second, float alpha) const = 0; + virtual void* getDefaultValue() const = 0; virtual void* createFromScript(const QScriptValue& value, QScriptEngine* engine) const { return create(); } @@ -225,6 +243,8 @@ public: virtual bool equal(void* first, void* second) const { return decodeInline(first) == decodeInline(second); } + virtual void* mix(void* first, void* second, float alpha) const { return create(alpha < 0.5f ? first : second); } + virtual void* getDefaultValue() const { return encodeInline(_defaultValue); } protected: @@ -245,27 +265,6 @@ template inline void InlineAttribute::write(Bitstrea } } -/// Provides merging using the =, ==, += and /= operators. -template class SimpleInlineAttribute : public InlineAttribute { -public: - - SimpleInlineAttribute(const QString& name, T defaultValue = T()) : InlineAttribute(name, defaultValue) { } - - virtual bool merge(void*& parent, void* children[]) const; -}; - -template inline bool SimpleInlineAttribute::merge(void*& parent, void* children[]) const { - T& merged = *(T*)&parent; - merged = decodeInline(children[0]); - bool allChildrenEqual = true; - for (int i = 1; i < Attribute::MERGE_COUNT; i++) { - merged += decodeInline(children[i]); - allChildrenEqual &= (decodeInline(children[0]) == decodeInline(children[i])); - } - merged /= Attribute::MERGE_COUNT; - return allChildrenEqual; -} - /// Provides appropriate averaging for RGBA values. class QRgbAttribute : public InlineAttribute { Q_OBJECT @@ -277,6 +276,8 @@ public: virtual bool merge(void*& parent, void* children[]) const; + virtual void* mix(void* first, void* second, float alpha) const; + virtual void* createFromScript(const QScriptValue& value, QScriptEngine* engine) const; virtual void* createFromVariant(const QVariant& value) const; @@ -293,6 +294,8 @@ public: Q_INVOKABLE PackedNormalAttribute(const QString& name = QString(), QRgb defaultValue = QRgb()); virtual bool merge(void*& parent, void* children[]) const; + + virtual void* mix(void* first, void* second, float alpha) const; }; /// Packs a normal into an RGB value. @@ -343,6 +346,8 @@ public: virtual bool merge(void*& parent, void* children[]) const; + virtual AttributeValue split(const AttributeValue& parent) const; + virtual QWidget* createEditor(QWidget* parent = NULL) const; private: diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 397e10d45f..c561cbae09 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -169,7 +169,7 @@ template int SpannerUpdateVisitor::visit(MetavoxelIn if (info.size > _longestSide) { return DEFAULT_ORDER; } - SharedObjectSet set = info.inputValues.at(0).getInlineValue(); + SharedObjectSet set = info.inputValues.at(0).getSafeInlineValue(); F(set, _object); info.outputValues[0] = AttributeValue(_attribute, encodeInline(set)); return STOP_RECURSION; @@ -177,7 +177,7 @@ template int SpannerUpdateVisitor::visit(MetavoxelIn void MetavoxelData::insert(const AttributePointer& attribute, const SharedObjectPointer& object) { Spanner* spanner = static_cast(object.data()); - insert(attribute, spanner->getBounds(), spanner->getGranularity(), object); + insert(attribute, spanner->getBounds(), spanner->getPlacementGranularity(), object); } void MetavoxelData::insert(const AttributePointer& attribute, const Box& bounds, @@ -192,7 +192,7 @@ void MetavoxelData::insert(const AttributePointer& attribute, const Box& bounds, void MetavoxelData::remove(const AttributePointer& attribute, const SharedObjectPointer& object) { Spanner* spanner = static_cast(object.data()); - remove(attribute, spanner->getBounds(), spanner->getGranularity(), object); + remove(attribute, spanner->getBounds(), spanner->getPlacementGranularity(), object); } void MetavoxelData::remove(const AttributePointer& attribute, const Box& bounds, @@ -203,7 +203,7 @@ void MetavoxelData::remove(const AttributePointer& attribute, const Box& bounds, void MetavoxelData::toggle(const AttributePointer& attribute, const SharedObjectPointer& object) { Spanner* spanner = static_cast(object.data()); - toggle(attribute, spanner->getBounds(), spanner->getGranularity(), object); + toggle(attribute, spanner->getBounds(), spanner->getPlacementGranularity(), object); } void MetavoxelData::toggle(const AttributePointer& attribute, const Box& bounds, @@ -875,7 +875,7 @@ void SpannerVisitor::prepare() { int SpannerVisitor::visit(MetavoxelInfo& info) { for (int i = _inputs.size() - _spannerInputCount; i < _inputs.size(); i++) { - foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue()) { + foreach (const SharedObjectPointer& object, info.inputValues.at(i).getSafeInlineValue()) { Spanner* spanner = static_cast(object.data()); if (spanner->testAndSetVisited()) { if (!visit(spanner)) { @@ -927,7 +927,7 @@ bool operator<(const SpannerDistance& first, const SpannerDistance& second) { int RaySpannerIntersectionVisitor::visit(MetavoxelInfo& info, float distance) { QVarLengthArray spannerDistances; for (int i = _inputs.size() - _spannerInputCount; i < _inputs.size(); i++) { - foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue()) { + foreach (const SharedObjectPointer& object, info.inputValues.at(i).getSafeInlineValue()) { Spanner* spanner = static_cast(object.data()); if (spanner->testAndSetVisited()) { SpannerDistance spannerDistance = { spanner }; @@ -991,7 +991,7 @@ bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { MetavoxelNode* child = (node && (visitation.info.size >= lodBase * parentValue.getAttribute()->getLODThresholdMultiplier())) ? node->getChild(index) : NULL; nextVisitation.info.inputValues[j] = ((nextVisitation.inputNodes[j] = child)) ? - child->getAttributeValue(parentValue.getAttribute()) : parentValue; + child->getAttributeValue(parentValue.getAttribute()) : parentValue.split(); } for (int j = 0; j < visitation.outputNodes.size(); j++) { MetavoxelNode* node = visitation.outputNodes.at(j); @@ -1202,11 +1202,13 @@ AttributeValue MetavoxelVisitation::getInheritedOutputValue(int index) const { return AttributeValue(visitor.getOutputs().at(index)); } -const float DEFAULT_GRANULARITY = 0.01f; +const float DEFAULT_PLACEMENT_GRANULARITY = 0.01f; +const float DEFAULT_VOXELIZATION_GRANULARITY = powf(2.0f, -3.0f); Spanner::Spanner() : _renderer(NULL), - _granularity(DEFAULT_GRANULARITY), + _placementGranularity(DEFAULT_PLACEMENT_GRANULARITY), + _voxelizationGranularity(DEFAULT_VOXELIZATION_GRANULARITY), _lastVisit(0) { } @@ -1223,10 +1225,19 @@ const QVector& Spanner::getAttributes() const { return emptyVector; } +const QVector& Spanner::getVoxelizedAttributes() const { + static QVector emptyVector; + return emptyVector; +} + bool Spanner::getAttributeValues(MetavoxelInfo& info) const { return false; } +bool Spanner::blendAttributeValues(MetavoxelInfo& info) const { + return false; +} + bool Spanner::testAndSetVisited() { if (_lastVisit == _visit) { return false; @@ -1320,6 +1331,13 @@ const QVector& Sphere::getAttributes() const { return attributes; } +const QVector& Sphere::getVoxelizedAttributes() const { + static QVector attributes = QVector() << + AttributeRegistry::getInstance()->getSpannerColorAttribute() << + AttributeRegistry::getInstance()->getSpannerNormalAttribute(); + return attributes; +} + bool Sphere::getAttributeValues(MetavoxelInfo& info) const { // bounds check Box bounds = info.getBounds(); @@ -1339,7 +1357,7 @@ bool Sphere::getAttributeValues(MetavoxelInfo& info) const { getNormal(info); return false; } - if (info.size <= getGranularity()) { + if (info.size <= getVoxelizationGranularity()) { // best guess if (pointsWithin > 0) { info.outputValues[0] = AttributeValue(getAttributes().at(0), encodeInline(qRgba( @@ -1351,6 +1369,41 @@ bool Sphere::getAttributeValues(MetavoxelInfo& info) const { return true; } +bool Sphere::blendAttributeValues(MetavoxelInfo& info) const { + // bounds check + Box bounds = info.getBounds(); + if (!getBounds().intersects(bounds)) { + return false; + } + // count the points inside the sphere + int pointsWithin = 0; + for (int i = 0; i < Box::VERTEX_COUNT; i++) { + if (glm::distance(bounds.getVertex(i), getTranslation()) <= getScale()) { + pointsWithin++; + } + } + if (pointsWithin == Box::VERTEX_COUNT) { + // entirely contained + info.outputValues[0] = AttributeValue(getAttributes().at(0), encodeInline(_color.rgba())); + info.outputValues[1] = getNormal(info); + return false; + } + if (info.size <= getVoxelizationGranularity()) { + // best guess + if (pointsWithin > 0) { + int oldAlpha = qAlpha(info.inputValues.at(0).getInlineValue()); + int newAlpha = _color.alpha() * pointsWithin / Box::VERTEX_COUNT; + float combinedAlpha = (float)newAlpha / (oldAlpha + newAlpha); + info.outputValues[0].mix(info.inputValues.at(0), AttributeValue(getAttributes().at(0), + encodeInline(qRgba(_color.red(), _color.green(), _color.blue(), + _color.alpha() * pointsWithin / Box::VERTEX_COUNT))), combinedAlpha); + info.outputValues[1].mix(info.inputValues.at(1), getNormal(info), combinedAlpha); + } + return false; + } + return true; +} + bool Sphere::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const { return findRaySphereIntersection(origin, direction, getTranslation(), getScale(), distance); } @@ -1364,7 +1417,7 @@ void Sphere::updateBounds() { setBounds(Box(getTranslation() - extent, getTranslation() + extent)); } -void Sphere::getNormal(MetavoxelInfo& info) const { +AttributeValue Sphere::getNormal(MetavoxelInfo& info) const { glm::vec3 normal = info.getCenter() - getTranslation(); float length = glm::length(normal); QRgb color; @@ -1379,7 +1432,7 @@ void Sphere::getNormal(MetavoxelInfo& info) const { const QRgb DEFAULT_NORMAL = 0x007F00; color = DEFAULT_NORMAL; } - info.outputValues[1] = AttributeValue(getAttributes().at(1), encodeInline(color)); + return AttributeValue(getAttributes().at(1), encodeInline(color)); } StaticModel::StaticModel() { diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 9d642f8f34..3e7c6f1b15 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -408,8 +408,9 @@ public: class Spanner : public SharedObject { Q_OBJECT Q_PROPERTY(Box bounds MEMBER _bounds WRITE setBounds NOTIFY boundsChanged DESIGNABLE false) - Q_PROPERTY(float granularity MEMBER _granularity DESIGNABLE false) - + Q_PROPERTY(float placementGranularity MEMBER _placementGranularity DESIGNABLE false) + Q_PROPERTY(float voxelizationGranularity MEMBER _voxelizationGranularity DESIGNABLE false) + public: /// Increments the value of the global visit counter. @@ -420,16 +421,26 @@ public: void setBounds(const Box& bounds); const Box& getBounds() const { return _bounds; } - void setGranularity(float granularity) { _granularity = granularity; } - float getGranularity() const { return _granularity; } + void setPlacementGranularity(float granularity) { _placementGranularity = granularity; } + float getPlacementGranularity() const { return _placementGranularity; } + + void setVoxelizationGranularity(float granularity) { _voxelizationGranularity = granularity; } + float getVoxelizationGranularity() const { return _voxelizationGranularity; } /// Returns a reference to the list of attributes associated with this spanner. virtual const QVector& getAttributes() const; + /// Returns a reference to the list of corresponding attributes that we voxelize the spanner into. + virtual const QVector& getVoxelizedAttributes() const; + /// Sets the attribute values associated with this spanner in the supplied info. /// \return true to recurse, false to stop virtual bool getAttributeValues(MetavoxelInfo& info) const; + /// Blends the attribute values associated with this spanner into the supplied info. + /// \return true to recurse, false to stop + virtual bool blendAttributeValues(MetavoxelInfo& info) const; + /// Checks whether we've visited this object on the current traversal. If we have, returns false. /// If we haven't, sets the last visit identifier and returns true. bool testAndSetVisited(); @@ -455,7 +466,8 @@ protected: private: Box _bounds; - float _granularity; + float _placementGranularity; + float _voxelizationGranularity; int _lastVisit; ///< the identifier of the last visit static int _visit; ///< the global visit counter @@ -521,7 +533,9 @@ public: const QColor& getColor() const { return _color; } virtual const QVector& getAttributes() const; + virtual const QVector& getVoxelizedAttributes() const; virtual bool getAttributeValues(MetavoxelInfo& info) const; + virtual bool blendAttributeValues(MetavoxelInfo& info) const; virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const; signals: @@ -538,7 +552,7 @@ private slots: private: - void getNormal(MetavoxelInfo& info) const; + AttributeValue getNormal(MetavoxelInfo& info) const; QColor _color; }; diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index 7a60ae6263..b600ef87bf 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -104,8 +104,33 @@ InsertSpannerEdit::InsertSpannerEdit(const AttributePointer& attribute, const Sh spanner(spanner) { } +class SetSpannerEditVisitor : public MetavoxelVisitor { +public: + + SetSpannerEditVisitor(const QVector& attributes, Spanner* spanner); + + virtual int visit(MetavoxelInfo& info); + +private: + + Spanner* _spanner; +}; + +SetSpannerEditVisitor::SetSpannerEditVisitor(const QVector& attributes, Spanner* spanner) : + MetavoxelVisitor(attributes, attributes), + _spanner(spanner) { +} + +int SetSpannerEditVisitor::visit(MetavoxelInfo& info) { + return _spanner->blendAttributeValues(info) ? DEFAULT_ORDER : STOP_RECURSION; +} + void InsertSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { - data.insert(attribute, spanner); + data.insert(attribute, this->spanner); + + Spanner* spanner = static_cast(this->spanner.data()); + SetSpannerEditVisitor visitor(spanner->getVoxelizedAttributes(), spanner); + data.guide(visitor); } RemoveSpannerEdit::RemoveSpannerEdit(const AttributePointer& attribute, int id) : @@ -130,27 +155,6 @@ void ClearSpannersEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& o data.clear(attribute); } -class SetSpannerEditVisitor : public MetavoxelVisitor { -public: - - SetSpannerEditVisitor(Spanner* spanner); - - virtual int visit(MetavoxelInfo& info); - -private: - - Spanner* _spanner; -}; - -SetSpannerEditVisitor::SetSpannerEditVisitor(Spanner* spanner) : - MetavoxelVisitor(spanner->getAttributes(), spanner->getAttributes()), - _spanner(spanner) { -} - -int SetSpannerEditVisitor::visit(MetavoxelInfo& info) { - return _spanner->getAttributeValues(info) ? DEFAULT_ORDER : STOP_RECURSION; -} - SetSpannerEdit::SetSpannerEdit(const SharedObjectPointer& spanner) : spanner(spanner) { } @@ -163,6 +167,6 @@ void SetSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& obje data.expand(); } - SetSpannerEditVisitor visitor(spanner); + SetSpannerEditVisitor visitor(spanner->getAttributes(), spanner); data.guide(visitor); }