From f356f0652b72eb4cb6ef88e44aa1666c3bc9aaca Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 30 Jul 2014 16:36:40 -0700 Subject: [PATCH] Collapse nodes when they fall out of LOD. --- libraries/metavoxels/src/MetavoxelData.cpp | 176 ++++++++++++--------- libraries/metavoxels/src/MetavoxelData.h | 6 + 2 files changed, 111 insertions(+), 71 deletions(-) diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 29f18f5cc1..8860d30c93 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -54,6 +54,18 @@ bool MetavoxelLOD::becameSubdivided(const glm::vec3& minimum, float size, return true; } +bool MetavoxelLOD::becameSubdividedOrCollapsed(const glm::vec3& minimum, float size, + const MetavoxelLOD& reference, float multiplier) const { + if (position == reference.position && threshold == reference.threshold) { + return false; // first off, nothing becomes subdivided or collapsed if it doesn't change + } + if (!(shouldSubdivide(minimum, size, multiplier) || reference.shouldSubdivide(minimum, size, multiplier))) { + return false; // this one or the reference must be subdivided + } + // TODO: find some way of culling subtrees that can't possibly contain subdivided or collapsed nodes + return true; +} + MetavoxelData::MetavoxelData() : _size(1.0f) { } @@ -567,53 +579,67 @@ void MetavoxelData::readDelta(const MetavoxelData& reference, const MetavoxelLOD // shallow copy the reference *this = reference; + QHash remainingRoots = _roots; + glm::vec3 minimum = getMinimum(); + bool changed; in >> changed; - if (!changed) { - return; - } - - bool sizeChanged; - in >> sizeChanged; - if (sizeChanged) { - float size; - in >> size; - while (_size < size) { - expand(); - } - } - - forever { - AttributePointer attribute; - in >> attribute; - if (!attribute) { - break; - } - MetavoxelStreamBase base = { attribute, in, lod, referenceLOD }; - MetavoxelStreamState state = { base, getMinimum(), _size }; - MetavoxelNode* oldRoot = _roots.value(attribute); - if (oldRoot) { - bool changed; - in >> changed; - if (changed) { - oldRoot->incrementReferenceCount(); - attribute->readMetavoxelDelta(*this, *oldRoot, state); - oldRoot->decrementReferenceCount(attribute); - } else { - attribute->readMetavoxelSubdivision(*this, state); + if (changed) { + bool sizeChanged; + in >> sizeChanged; + if (sizeChanged) { + float size; + in >> size; + while (_size < size) { + expand(); } - } else { - attribute->readMetavoxelRoot(*this, state); - } + } + + forever { + AttributePointer attribute; + in >> attribute; + if (!attribute) { + break; + } + MetavoxelStreamBase base = { attribute, in, lod, referenceLOD }; + MetavoxelStreamState state = { base, minimum, _size }; + MetavoxelNode* oldRoot = _roots.value(attribute); + if (oldRoot) { + bool changed; + in >> changed; + if (changed) { + oldRoot->incrementReferenceCount(); + attribute->readMetavoxelDelta(*this, *oldRoot, state); + oldRoot->decrementReferenceCount(attribute); + } else { + attribute->readMetavoxelSubdivision(*this, state); + } + remainingRoots.remove(attribute); + + } else { + attribute->readMetavoxelRoot(*this, state); + } + } + + forever { + AttributePointer attribute; + in >> attribute; + if (!attribute) { + break; + } + _roots.take(attribute)->decrementReferenceCount(attribute); + remainingRoots.remove(attribute); + } } - forever { - AttributePointer attribute; - in >> attribute; - if (!attribute) { - break; + // read subdivisions for the remaining roots if there's any chance of a collapse + if (!(lod.position == referenceLOD.position && lod.threshold <= referenceLOD.threshold)) { + for (QHash::const_iterator it = remainingRoots.constBegin(); + it != remainingRoots.constEnd(); it++) { + MetavoxelStreamBase base = { it.key(), in, lod, referenceLOD }; + MetavoxelStreamState state = { base, minimum, _size }; + it.key()->readMetavoxelSubdivision(*this, state); } - _roots.take(attribute)->decrementReferenceCount(attribute); } } @@ -788,6 +814,10 @@ bool MetavoxelStreamState::becameSubdivided() const { return base.lod.becameSubdivided(minimum, size, base.referenceLOD, base.attribute->getLODThresholdMultiplier()); } +bool MetavoxelStreamState::becameSubdividedOrCollapsed() const { + return base.lod.becameSubdividedOrCollapsed(minimum, size, base.referenceLOD, base.attribute->getLODThresholdMultiplier()); +} + void MetavoxelStreamState::setMinimum(const glm::vec3& lastMinimum, int index) { minimum = getNextMinimum(lastMinimum, size, index); } @@ -923,7 +953,7 @@ void MetavoxelNode::readDelta(const MetavoxelNode& reference, MetavoxelStreamSta _children[i] = new MetavoxelNode(state.base.attribute); _children[i]->readDelta(*reference._children[i], nextState); } else { - if (nextState.becameSubdivided()) { + if (nextState.becameSubdividedOrCollapsed()) { _children[i] = reference._children[i]->readSubdivision(nextState); if (_children[i] == reference._children[i]) { _children[i]->incrementReferenceCount(); @@ -972,42 +1002,46 @@ void MetavoxelNode::writeDelta(const MetavoxelNode& reference, MetavoxelStreamSt } MetavoxelNode* MetavoxelNode::readSubdivision(MetavoxelStreamState& state) { - if (!state.shouldSubdivideReference()) { - bool leaf; - state.base.stream >> leaf; - if (leaf) { - return isLeaf() ? this : new MetavoxelNode(getAttributeValue(state.base.attribute)); - - } else { - MetavoxelNode* newNode = new MetavoxelNode(getAttributeValue(state.base.attribute)); + if (state.shouldSubdivide()) { + if (!state.shouldSubdivideReference()) { + bool leaf; + state.base.stream >> leaf; + if (leaf) { + return isLeaf() ? this : new MetavoxelNode(getAttributeValue(state.base.attribute)); + + } else { + MetavoxelNode* newNode = new MetavoxelNode(getAttributeValue(state.base.attribute)); + MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f }; + for (int i = 0; i < CHILD_COUNT; i++) { + nextState.setMinimum(state.minimum, i); + newNode->_children[i] = new MetavoxelNode(state.base.attribute); + newNode->_children[i]->read(nextState); + } + return newNode; + } + } else if (!isLeaf()) { + MetavoxelNode* node = this; MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f }; for (int i = 0; i < CHILD_COUNT; i++) { nextState.setMinimum(state.minimum, i); - newNode->_children[i] = new MetavoxelNode(state.base.attribute); - newNode->_children[i]->read(nextState); - } - return newNode; - } - } else if (!isLeaf()) { - MetavoxelNode* node = this; - MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f }; - for (int i = 0; i < CHILD_COUNT; i++) { - nextState.setMinimum(state.minimum, i); - if (nextState.becameSubdivided()) { - MetavoxelNode* child = _children[i]->readSubdivision(nextState); - if (child != _children[i]) { - if (node == this) { - node = new MetavoxelNode(state.base.attribute, this); + if (nextState.becameSubdividedOrCollapsed()) { + MetavoxelNode* child = _children[i]->readSubdivision(nextState); + if (child != _children[i]) { + if (node == this) { + node = new MetavoxelNode(state.base.attribute, this); + } + node->_children[i] = child; + _children[i]->decrementReferenceCount(state.base.attribute); } - node->_children[i] = child; - _children[i]->decrementReferenceCount(state.base.attribute); } } + if (node != this) { + node->mergeChildren(state.base.attribute, true); + } + return node; } - if (node != this) { - node->mergeChildren(state.base.attribute, true); - } - return node; + } else if (!isLeaf()) { + return new MetavoxelNode(getAttributeValue(state.base.attribute)); } return this; } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 46376601c1..24eb09763c 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -55,6 +55,11 @@ public: /// Checks whether the node or any of the nodes underneath it have had subdivision enabled as compared to the reference. bool becameSubdivided(const glm::vec3& minimum, float size, const MetavoxelLOD& reference, float multiplier = 1.0f) const; + + /// Checks whether the node or any of the nodes underneath it have had subdivision + /// enabled or disabled as compared to the reference. + bool becameSubdividedOrCollapsed(const glm::vec3& minimum, float size, + const MetavoxelLOD& reference, float multiplier = 1.0f) const; }; DECLARE_STREAMABLE_METATYPE(MetavoxelLOD) @@ -181,6 +186,7 @@ public: bool shouldSubdivide() const; bool shouldSubdivideReference() const; bool becameSubdivided() const; + bool becameSubdividedOrCollapsed() const; void setMinimum(const glm::vec3& lastMinimum, int index); };