diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 90adcef38c..9b4dcff807 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -90,8 +90,8 @@ public: SpannerRenderVisitor::SpannerRenderVisitor() : SpannerVisitor(QVector() << AttributeRegistry::getInstance()->getSpannersAttribute(), - QVector() << AttributeRegistry::getInstance()->getSpannerMaskAttribute(), - QVector(), QVector(), Application::getInstance()->getMetavoxels()->getLOD(), + QVector(), QVector(), QVector(), + Application::getInstance()->getMetavoxels()->getLOD(), encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())) { } @@ -239,53 +239,22 @@ void MetavoxelSystemClient::sendDatagram(const QByteArray& data) { Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::METAVOXELS).updateValue(data.size()); } -PointBuffer::PointBuffer(const QVector& levelPoints) : - _levelPoints(levelPoints) { +PointBuffer::PointBuffer(const BufferPointVector& points) : + _points(points) { } -void PointBuffer::render(int level) { +void PointBuffer::render() { // initalize buffer, etc. on first render if (!_buffer.isCreated()) { - _offsets.append(0); - _lastLeafCount = 0; - int totalPoints = 0; - foreach (const BufferPointVectorPair& pair, _levelPoints) { - _offsets.append(totalPoints += ((_lastLeafCount += pair.first.size()) + pair.second.size())); - } _buffer.setUsagePattern(QOpenGLBuffer::StaticDraw); _buffer.create(); _buffer.bind(); - _buffer.allocate(totalPoints * sizeof(BufferPoint)); - int offset = 0; - for (int i = 0; i < _levelPoints.size(); i++) { - // write the internal nodes from the current level - const BufferPointVector& internal = _levelPoints.at(i).second; - int length = internal.size() * sizeof(BufferPoint); - _buffer.write(offset, internal.constData(), length); - offset += length; - - // and the leaves from the top down - for (int j = 0; j <= i; j++) { - const BufferPointVector& leaves = _levelPoints.at(j).first; - length = leaves.size() * sizeof(BufferPoint); - _buffer.write(offset, leaves.constData(), length); - offset += length; - } - } - _levelPoints.clear(); + _pointCount = _points.size(); + _buffer.allocate(_points.constData(), _pointCount * sizeof(BufferPoint)); + _points.clear(); _buffer.release(); } - int first, count; - int nextLevel = level + 1; - if (nextLevel >= _offsets.size()) { - first = _offsets.last() - _lastLeafCount; - count = _lastLeafCount; - - } else { - first = _offsets.at(level); - count = _offsets.at(nextLevel) - first; - } - if (count == 0) { + if (_pointCount == 0) { return; } _buffer.bind(); @@ -295,7 +264,7 @@ void PointBuffer::render(int level) { glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(BufferPoint), &point->color); glNormalPointer(GL_BYTE, sizeof(BufferPoint), &point->normal); - glDrawArrays(GL_POINTS, first, count); + glDrawArrays(GL_POINTS, 0, _pointCount); _buffer.release(); } @@ -304,23 +273,18 @@ PointBufferAttribute::PointBufferAttribute() : InlineAttribute("pointBuffer") { } -MetavoxelNode* PointBufferAttribute::createMetavoxelNode(const AttributeValue& value, const MetavoxelNode* original) const { - return new MetavoxelNode(value, original); -} - bool PointBufferAttribute::merge(void*& parent, void* children[], bool postRead) const { - for (int i = 0; i < MERGE_COUNT; i++) { - if (decodeInline(children[i])) { + PointBufferPointer firstChild = decodeInline(children[0]); + for (int i = 1; i < MERGE_COUNT; i++) { + if (firstChild != decodeInline(children[i])) { + *(PointBufferPointer*)&parent = _defaultValue; return false; } } + *(PointBufferPointer*)&parent = firstChild; return true; } -AttributeValue PointBufferAttribute::inherit(const AttributeValue& parentValue) const { - return AttributeValue(parentValue.getAttribute()); -} - void PointMetavoxelRendererImplementation::init() { if (!_program.isLinked()) { _program.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert"); @@ -340,12 +304,14 @@ public: PointAugmentVisitor(const MetavoxelLOD& lod); + virtual void prepare(MetavoxelData* data); virtual int visit(MetavoxelInfo& info); virtual bool postVisit(MetavoxelInfo& info); private: - QVector _depthPoints; + BufferPointVector _points; + float _pointLeafSize; }; PointAugmentVisitor::PointAugmentVisitor(const MetavoxelLOD& lod) : @@ -356,48 +322,61 @@ PointAugmentVisitor::PointAugmentVisitor(const MetavoxelLOD& lod) : const int ALPHA_RENDER_THRESHOLD = 0; +void PointAugmentVisitor::prepare(MetavoxelData* data) { + MetavoxelVisitor::prepare(data); + const float MAX_POINT_LEAF_SIZE = 64.0f; + _pointLeafSize = qMin(data->getSize(), MAX_POINT_LEAF_SIZE); +} + int PointAugmentVisitor::visit(MetavoxelInfo& info) { - if (_depth >= _depthPoints.size()) { - _depthPoints.resize(_depth + 1); + if (!info.isLeaf) { + return (info.size > _pointLeafSize) ? DEFAULT_ORDER : (DEFAULT_ORDER | ALL_NODES_REST); } QRgb color = info.inputValues.at(0).getInlineValue(); quint8 alpha = qAlpha(color); - if (alpha <= ALPHA_RENDER_THRESHOLD) { - return info.isLeaf ? STOP_RECURSION : (DEFAULT_ORDER | ALL_NODES); + if (alpha > ALPHA_RENDER_THRESHOLD) { + QRgb normal = info.inputValues.at(1).getInlineValue(); + BufferPoint 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)) }, + { quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } }; + _points.append(point); } - QRgb normal = info.inputValues.at(1).getInlineValue(); - BufferPoint 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)) }, - { quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } }; - if (info.isLeaf) { - _depthPoints[_depth].first.append(point); - return STOP_RECURSION; + if (info.size >= _pointLeafSize) { + BufferPointVector swapPoints; + _points.swap(swapPoints); + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(PointBufferPointer( + new PointBuffer(swapPoints)))); } - _depthPoints[_depth].second.append(point); - return DEFAULT_ORDER | ALL_NODES; + return STOP_RECURSION; } bool PointAugmentVisitor::postVisit(MetavoxelInfo& info) { - if (_depth != 0) { + if (info.size != _pointLeafSize) { return false; } - int lastDepth = _depthPoints.size(); - QVector levelPoints(lastDepth - _depth); - for (int i = 0; i < levelPoints.size(); i++) { - BufferPointVectorPair& levelPair = levelPoints[i]; - BufferPointVectorPair& depthPair = _depthPoints[_depth + i]; - levelPair.first.swap(depthPair.first); - levelPair.second.swap(depthPair.second); - } + BufferPointVector swapPoints; + _points.swap(swapPoints); info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(PointBufferPointer( - new PointBuffer(levelPoints)))); + new PointBuffer(swapPoints)))); return true; } void PointMetavoxelRendererImplementation::augment(MetavoxelData& data, const MetavoxelData& previous, MetavoxelInfo& info, const MetavoxelLOD& lod) { + // copy the previous buffers + MetavoxelData expandedPrevious = previous; + while (expandedPrevious.getSize() < data.getSize()) { + expandedPrevious.expand(); + } + const AttributePointer& pointBufferAttribute = Application::getInstance()->getMetavoxels()->getPointBufferAttribute(); + MetavoxelNode* root = expandedPrevious.getRoot(pointBufferAttribute); + if (root) { + data.setRoot(pointBufferAttribute, root); + root->incrementReferenceCount(); + } + PointAugmentVisitor visitor(lod); - data.guideToDifferent(previous, visitor, &info); + data.guideToDifferent(expandedPrevious, visitor); } class PointRenderVisitor : public MetavoxelVisitor { @@ -421,7 +400,7 @@ PointRenderVisitor::PointRenderVisitor(const MetavoxelLOD& lod) : int PointRenderVisitor::visit(MetavoxelInfo& info) { PointBufferPointer buffer = info.inputValues.at(0).getInlineValue(); if (buffer) { - buffer->render(1000); + buffer->render(); } return info.isLeaf ? STOP_RECURSION : _order; } @@ -450,7 +429,7 @@ void PointMetavoxelRendererImplementation::render(MetavoxelData& data, Metavoxel glDisable(GL_BLEND); PointRenderVisitor visitor(lod); - data.guide(visitor, &info); + data.guide(visitor); glEnable(GL_BLEND); diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index a765f9fdd9..4a5b99aa47 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -23,12 +23,8 @@ #include "renderer/ProgramObject.h" -class BufferPoint; class Model; -typedef QVector BufferPointVector; -typedef QPair BufferPointVectorPair; - /// Renders a metavoxel tree. class MetavoxelSystem : public MetavoxelClientManager { Q_OBJECT @@ -66,6 +62,8 @@ public: quint8 normal[3]; }; +typedef QVector BufferPointVector; + Q_DECLARE_METATYPE(BufferPointVector) /// A client session associated with a single server. @@ -94,20 +92,19 @@ private: QReadWriteLock _augmentedDataLock; }; -/// Contains the information necessary to render a group of points at variable detail levels. +/// Contains the information necessary to render a group of points. class PointBuffer : public QSharedData { public: - PointBuffer(const QVector& levelPoints); + PointBuffer(const BufferPointVector& points); - void render(int level); + void render(); private: - QVector _levelPoints; + BufferPointVector _points; QOpenGLBuffer _buffer; - QVector _offsets; - int _lastLeafCount; + int _pointCount; }; typedef QExplicitlySharedDataPointer PointBufferPointer; @@ -120,9 +117,7 @@ public: Q_INVOKABLE PointBufferAttribute(); - virtual MetavoxelNode* createMetavoxelNode(const AttributeValue& value, const MetavoxelNode* original) const; virtual bool merge(void*& parent, void* children[], bool postRead = false) const; - virtual AttributeValue inherit(const AttributeValue& parentValue) const; }; /// Renders metavoxels as points. diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 3a1fe81259..3bf43ef8d4 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -81,7 +81,7 @@ Box MetavoxelData::getBounds() const { return Box(glm::vec3(-halfSize, -halfSize, -halfSize), glm::vec3(halfSize, halfSize, halfSize)); } -void MetavoxelData::guide(MetavoxelVisitor& visitor, const MetavoxelInfo* start) { +void MetavoxelData::guide(MetavoxelVisitor& visitor) { // let the visitor know we're about to begin a tour visitor.prepare(this); @@ -128,7 +128,7 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor, const MetavoxelInfo* start) visitor.releaseVisitation(); } -void MetavoxelData::guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor, const MetavoxelInfo* start) { +void MetavoxelData::guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor) { // if the other data is smaller, we need to expand it to compare const MetavoxelData* expandedOther = &other; if (_size > other._size) { @@ -1249,6 +1249,7 @@ const int MetavoxelVisitor::DEFAULT_ORDER = encodeOrder(0, 1, 2, 3, 4, 5, 6, 7); const int MetavoxelVisitor::STOP_RECURSION = 0; const int MetavoxelVisitor::SHORT_CIRCUIT = -1; const int MetavoxelVisitor::ALL_NODES = 1 << 24; +const int MetavoxelVisitor::ALL_NODES_REST = 1 << 25; MetavoxelVisitor::MetavoxelVisitor(const QVector& inputs, const QVector& outputs, const MetavoxelLOD& lod) : @@ -1428,32 +1429,7 @@ bool MetavoxelGuide::guideToDifferent(MetavoxelVisitation& visitation) { DefaultMetavoxelGuide::DefaultMetavoxelGuide() { } -bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { - // save the core of the LOD calculation; we'll reuse it to determine whether to subdivide each attribute - float lodBase = glm::distance(visitation.visitor->getLOD().position, visitation.info.getCenter()) * - visitation.visitor->getLOD().threshold; - visitation.info.isLODLeaf = (visitation.info.size < lodBase * visitation.visitor->getMinimumLODThresholdMultiplier()); - visitation.info.isLeaf = visitation.info.isLODLeaf || visitation.allInputNodesLeaves(); - int encodedOrder = visitation.visitor->visit(visitation.info); - if (encodedOrder == MetavoxelVisitor::SHORT_CIRCUIT) { - return false; - } - for (int i = 0; i < visitation.outputNodes.size(); i++) { - OwnedAttributeValue& value = visitation.info.outputValues[i]; - if (!value.getAttribute()) { - continue; - } - MetavoxelNode*& node = visitation.outputNodes[i]; - if (node && node->isLeaf() && value.getAttribute()->equal(value.getValue(), node->getAttributeValue())) { - // "set" to same value; disregard - value = AttributeValue(); - } else { - node = value.getAttribute()->createMetavoxelNode(value, node); - } - } - if (encodedOrder == MetavoxelVisitor::STOP_RECURSION) { - return true; - } +static inline bool defaultGuideToChildren(MetavoxelVisitation& visitation, float lodBase, int encodedOrder) { MetavoxelVisitation& nextVisitation = visitation.visitor->acquireVisitation(); nextVisitation.info.size = visitation.info.size * 0.5f; for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { @@ -1546,6 +1522,35 @@ bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { return true; } +bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) { + // save the core of the LOD calculation; we'll reuse it to determine whether to subdivide each attribute + float lodBase = glm::distance(visitation.visitor->getLOD().position, visitation.info.getCenter()) * + visitation.visitor->getLOD().threshold; + visitation.info.isLODLeaf = (visitation.info.size < lodBase * visitation.visitor->getMinimumLODThresholdMultiplier()); + visitation.info.isLeaf = visitation.info.isLODLeaf || visitation.allInputNodesLeaves(); + int encodedOrder = visitation.visitor->visit(visitation.info); + if (encodedOrder == MetavoxelVisitor::SHORT_CIRCUIT) { + return false; + } + for (int i = 0; i < visitation.outputNodes.size(); i++) { + OwnedAttributeValue& value = visitation.info.outputValues[i]; + if (!value.getAttribute()) { + continue; + } + MetavoxelNode*& node = visitation.outputNodes[i]; + if (node && node->isLeaf() && value.getAttribute()->equal(value.getValue(), node->getAttributeValue())) { + // "set" to same value; disregard + value = AttributeValue(); + } else { + node = value.getAttribute()->createMetavoxelNode(value, node); + } + } + if (encodedOrder == MetavoxelVisitor::STOP_RECURSION) { + return true; + } + return (encodedOrder == MetavoxelVisitor::STOP_RECURSION || defaultGuideToChildren(visitation, lodBase, encodedOrder)); +} + bool DefaultMetavoxelGuide::guideToDifferent(MetavoxelVisitation& visitation) { // save the core of the LOD calculation; we'll reuse it to determine whether to subdivide each attribute float lodBase = glm::distance(visitation.visitor->getLOD().position, visitation.info.getCenter()) * @@ -1572,6 +1577,9 @@ bool DefaultMetavoxelGuide::guideToDifferent(MetavoxelVisitation& visitation) { if (encodedOrder == MetavoxelVisitor::STOP_RECURSION) { return true; } + if (encodedOrder & MetavoxelVisitor::ALL_NODES_REST) { + return defaultGuideToChildren(visitation, lodBase, encodedOrder); + } bool onlyVisitDifferent = !(encodedOrder & MetavoxelVisitor::ALL_NODES); MetavoxelVisitation& nextVisitation = visitation.visitor->acquireVisitation(); nextVisitation.compareNodes.resize(visitation.compareNodes.size()); diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 8f9ee8924e..2dc778cf71 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -81,12 +81,10 @@ public: Box getBounds() const; /// Applies the specified visitor to the contained voxels. - /// \param start the location at which to start, or NULL for the root - void guide(MetavoxelVisitor& visitor, const MetavoxelInfo* start = NULL); + void guide(MetavoxelVisitor& visitor); /// Guides the specified visitor to the voxels that differ from those of the specified other. - /// \param start the location at which to start, or NULL for the root - void guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor, const MetavoxelInfo* start = NULL); + void guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor); /// Inserts a spanner into the specified attribute layer. void insert(const AttributePointer& attribute, const SharedObjectPointer& object); @@ -296,9 +294,14 @@ public: /// A special "order" that short-circuits the tour. static const int SHORT_CIRCUIT; - /// A flag combined with an order that instructs us to return to visiting all nodes (rather than the different ones). + /// A flag combined with an order that instructs us to return to visiting all nodes (rather than the different ones) for + /// just this level. static const int ALL_NODES; + /// A flag combined with an order that instructs us to return to visiting all nodes (rather than the different ones) for + /// this level and all beneath it. + static const int ALL_NODES_REST; + MetavoxelVisitor(const QVector& inputs, const QVector& outputs = QVector(), const MetavoxelLOD& lod = MetavoxelLOD());