Collapse nodes when they fall out of LOD.

This commit is contained in:
Andrzej Kapolka 2014-07-30 16:36:40 -07:00
parent a722c4ba0a
commit f356f0652b
2 changed files with 111 additions and 71 deletions

View file

@ -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<AttributePointer, MetavoxelNode*> 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<AttributePointer, MetavoxelNode*>::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;
}

View file

@ -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);
};