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; 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) { MetavoxelData::MetavoxelData() : _size(1.0f) {
} }
@ -567,53 +579,67 @@ void MetavoxelData::readDelta(const MetavoxelData& reference, const MetavoxelLOD
// shallow copy the reference // shallow copy the reference
*this = reference; *this = reference;
QHash<AttributePointer, MetavoxelNode*> remainingRoots = _roots;
glm::vec3 minimum = getMinimum();
bool changed; bool changed;
in >> changed; in >> changed;
if (!changed) { if (changed) {
return; bool sizeChanged;
} in >> sizeChanged;
if (sizeChanged) {
bool sizeChanged; float size;
in >> sizeChanged; in >> size;
if (sizeChanged) { while (_size < size) {
float size; expand();
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);
} }
} 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 { // read subdivisions for the remaining roots if there's any chance of a collapse
AttributePointer attribute; if (!(lod.position == referenceLOD.position && lod.threshold <= referenceLOD.threshold)) {
in >> attribute; for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = remainingRoots.constBegin();
if (!attribute) { it != remainingRoots.constEnd(); it++) {
break; 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()); 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) { void MetavoxelStreamState::setMinimum(const glm::vec3& lastMinimum, int index) {
minimum = getNextMinimum(lastMinimum, size, 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] = new MetavoxelNode(state.base.attribute);
_children[i]->readDelta(*reference._children[i], nextState); _children[i]->readDelta(*reference._children[i], nextState);
} else { } else {
if (nextState.becameSubdivided()) { if (nextState.becameSubdividedOrCollapsed()) {
_children[i] = reference._children[i]->readSubdivision(nextState); _children[i] = reference._children[i]->readSubdivision(nextState);
if (_children[i] == reference._children[i]) { if (_children[i] == reference._children[i]) {
_children[i]->incrementReferenceCount(); _children[i]->incrementReferenceCount();
@ -972,42 +1002,46 @@ void MetavoxelNode::writeDelta(const MetavoxelNode& reference, MetavoxelStreamSt
} }
MetavoxelNode* MetavoxelNode::readSubdivision(MetavoxelStreamState& state) { MetavoxelNode* MetavoxelNode::readSubdivision(MetavoxelStreamState& state) {
if (!state.shouldSubdivideReference()) { if (state.shouldSubdivide()) {
bool leaf; if (!state.shouldSubdivideReference()) {
state.base.stream >> leaf; bool leaf;
if (leaf) { state.base.stream >> leaf;
return isLeaf() ? this : new MetavoxelNode(getAttributeValue(state.base.attribute)); if (leaf) {
return isLeaf() ? this : new MetavoxelNode(getAttributeValue(state.base.attribute));
} else {
MetavoxelNode* newNode = 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 }; MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f };
for (int i = 0; i < CHILD_COUNT; i++) { for (int i = 0; i < CHILD_COUNT; i++) {
nextState.setMinimum(state.minimum, i); nextState.setMinimum(state.minimum, i);
newNode->_children[i] = new MetavoxelNode(state.base.attribute); if (nextState.becameSubdividedOrCollapsed()) {
newNode->_children[i]->read(nextState); MetavoxelNode* child = _children[i]->readSubdivision(nextState);
} if (child != _children[i]) {
return newNode; if (node == this) {
} node = new MetavoxelNode(state.base.attribute, this);
} else if (!isLeaf()) { }
MetavoxelNode* node = this; node->_children[i] = child;
MetavoxelStreamState nextState = { state.base, glm::vec3(), state.size * 0.5f }; _children[i]->decrementReferenceCount(state.base.attribute);
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);
} }
node->_children[i] = child;
_children[i]->decrementReferenceCount(state.base.attribute);
} }
} }
if (node != this) {
node->mergeChildren(state.base.attribute, true);
}
return node;
} }
if (node != this) { } else if (!isLeaf()) {
node->mergeChildren(state.base.attribute, true); return new MetavoxelNode(getAttributeValue(state.base.attribute));
}
return node;
} }
return this; 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. /// 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; 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) DECLARE_STREAMABLE_METATYPE(MetavoxelLOD)
@ -181,6 +186,7 @@ public:
bool shouldSubdivide() const; bool shouldSubdivide() const;
bool shouldSubdivideReference() const; bool shouldSubdivideReference() const;
bool becameSubdivided() const; bool becameSubdivided() const;
bool becameSubdividedOrCollapsed() const;
void setMinimum(const glm::vec3& lastMinimum, int index); void setMinimum(const glm::vec3& lastMinimum, int index);
}; };