Added per-attribute LOD threshold multiplier; things like spanners need

different LOD thresholds than, say, voxels.
This commit is contained in:
Andrzej Kapolka 2014-03-11 12:21:58 -07:00
parent 35be8cd941
commit 66e322ec55
4 changed files with 61 additions and 17 deletions

View file

@ -28,6 +28,10 @@ AttributeRegistry::AttributeRegistry() :
_spannersAttribute(registerAttribute(new SpannerSetAttribute("spanners", &Spanner::staticMetaObject))),
_colorAttribute(registerAttribute(new QRgbAttribute("color"))),
_normalAttribute(registerAttribute(new PackedNormalAttribute("normal", qRgb(0, 127, 0)))) {
// our baseline LOD threshold is for voxels; spanners are a different story
const float SPANNER_LOD_THRESHOLD_MULTIPLIER = 4.0f;
_spannersAttribute->setLODThresholdMultiplier(SPANNER_LOD_THRESHOLD_MULTIPLIER);
}
static QScriptValue qDebugFunction(QScriptContext* context, QScriptEngine* engine) {
@ -143,7 +147,8 @@ OwnedAttributeValue& OwnedAttributeValue::operator=(const OwnedAttributeValue& o
return *this;
}
Attribute::Attribute(const QString& name) {
Attribute::Attribute(const QString& name) :
_lodThresholdMultiplier(1.0f) {
setObjectName(name);
}

View file

@ -153,6 +153,7 @@ public:
/// Represents a registered attribute.
class Attribute : public SharedObject {
Q_OBJECT
Q_PROPERTY(float lodThresholdMultiplier MEMBER _lodThresholdMultiplier)
public:
@ -163,6 +164,9 @@ public:
Q_INVOKABLE QString getName() const { return objectName(); }
float getLODThresholdMultiplier() const { return _lodThresholdMultiplier; }
void setLODThresholdMultiplier(float multiplier) { _lodThresholdMultiplier = multiplier; }
void* create() const { return create(getDefaultValue()); }
virtual void* create(void* copy) const = 0;
virtual void destroy(void* value) const = 0;
@ -197,6 +201,10 @@ public:
/// Creates a widget to use to edit values of this attribute, or returns NULL if the attribute isn't editable.
/// The widget should have a single "user" property that will be used to get/set the value.
virtual QWidget* createEditor(QWidget* parent = NULL) const { return NULL; }
private:
float _lodThresholdMultiplier;
};
/// A simple attribute class that stores its values inline.

View file

@ -29,15 +29,16 @@ MetavoxelLOD::MetavoxelLOD(const glm::vec3& position, float threshold) :
threshold(threshold) {
}
bool MetavoxelLOD::shouldSubdivide(const glm::vec3& minimum, float size) const {
return size >= glm::distance(position, minimum + glm::vec3(size, size, size) * 0.5f) * threshold;
bool MetavoxelLOD::shouldSubdivide(const glm::vec3& minimum, float size, float multiplier) const {
return size >= glm::distance(position, minimum + glm::vec3(size, size, size) * 0.5f) * threshold * multiplier;
}
bool MetavoxelLOD::becameSubdivided(const glm::vec3& minimum, float size, const MetavoxelLOD& reference) const {
bool MetavoxelLOD::becameSubdivided(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 if it doesn't change
}
if (!shouldSubdivide(minimum, size)) {
if (!shouldSubdivide(minimum, size, multiplier)) {
return false; // this one must be subdivided
}
// the general check is whether we've gotten closer (as multiplied by the threshold) to any point in the volume,
@ -468,6 +469,18 @@ static glm::vec3 getNextMinimum(const glm::vec3& minimum, float nextSize, int in
(index & Z_MAXIMUM_FLAG) ? nextSize : 0.0f);
}
bool MetavoxelStreamState::shouldSubdivide() const {
return lod.shouldSubdivide(minimum, size, attribute->getLODThresholdMultiplier());
}
bool MetavoxelStreamState::shouldSubdivideReference() const {
return referenceLOD.shouldSubdivide(minimum, size, attribute->getLODThresholdMultiplier());
}
bool MetavoxelStreamState::becameSubdivided() const {
return lod.becameSubdivided(minimum, size, referenceLOD, attribute->getLODThresholdMultiplier());
}
void MetavoxelStreamState::setMinimum(const glm::vec3& lastMinimum, int index) {
minimum = getNextMinimum(lastMinimum, size, index);
}
@ -831,7 +844,16 @@ MetavoxelVisitor::MetavoxelVisitor(const QVector<AttributePointer>& inputs,
const QVector<AttributePointer>& outputs, const MetavoxelLOD& lod) :
_inputs(inputs),
_outputs(outputs),
_lod(lod) {
_lod(lod),
_minimumLODThresholdMultiplier(FLT_MAX) {
// find the minimum LOD threshold multiplier over all attributes
foreach (const AttributePointer& attribute, _inputs) {
_minimumLODThresholdMultiplier = qMin(attribute->getLODThresholdMultiplier(), _minimumLODThresholdMultiplier);
}
foreach (const AttributePointer& attribute, _outputs) {
_minimumLODThresholdMultiplier = qMin(attribute->getLODThresholdMultiplier(), _minimumLODThresholdMultiplier);
}
}
MetavoxelVisitor::~MetavoxelVisitor() {
@ -928,8 +950,11 @@ DefaultMetavoxelGuide::DefaultMetavoxelGuide() {
}
bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
bool shouldSubdivide = visitation.visitor.getLOD().shouldSubdivide(visitation.info.minimum, visitation.info.size);
visitation.info.isLeaf = !shouldSubdivide || visitation.allInputNodesLeaves();
// 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.isLeaf = (visitation.info.size < lodBase * visitation.visitor.getMinimumLODThresholdMultiplier()) ||
visitation.allInputNodesLeaves();
int encodedOrder = visitation.visitor.visit(visitation.info);
if (encodedOrder == MetavoxelVisitor::SHORT_CIRCUIT) {
return false;
@ -955,20 +980,23 @@ bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
{ glm::vec3(), visitation.info.size * 0.5f, QVector<AttributeValue>(visitation.inputNodes.size()),
QVector<OwnedAttributeValue>(visitation.outputNodes.size()) } };
for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) {
// the encoded order tells us the child indices for each iteration
const int ORDER_ELEMENT_BITS = 3;
const int ORDER_ELEMENT_MASK = (1 << ORDER_ELEMENT_BITS) - 1;
int index = encodedOrder & ORDER_ELEMENT_MASK;
encodedOrder >>= ORDER_ELEMENT_BITS;
for (int j = 0; j < visitation.inputNodes.size(); j++) {
MetavoxelNode* node = visitation.inputNodes.at(j);
MetavoxelNode* child = (node && shouldSubdivide) ? node->getChild(index) : NULL;
const AttributeValue& parentValue = visitation.info.inputValues.at(j);
MetavoxelNode* child = (node && (visitation.info.size >= lodBase *
parentValue.getAttribute()->getLODThresholdMultiplier())) ? node->getChild(index) : NULL;
nextVisitation.info.inputValues[j] = ((nextVisitation.inputNodes[j] = child)) ?
child->getAttributeValue(visitation.info.inputValues[j].getAttribute()) :
visitation.info.inputValues[j];
child->getAttributeValue(parentValue.getAttribute()) : parentValue;
}
for (int j = 0; j < visitation.outputNodes.size(); j++) {
MetavoxelNode* node = visitation.outputNodes.at(j);
MetavoxelNode* child = (node && shouldSubdivide) ? node->getChild(index) : NULL;
MetavoxelNode* child = (node && (visitation.info.size >= lodBase *
visitation.visitor.getOutputs().at(j)->getLODThresholdMultiplier())) ? node->getChild(index) : NULL;
nextVisitation.outputNodes[j] = child;
}
nextVisitation.info.minimum = getNextMinimum(visitation.info.minimum, nextVisitation.info.size, index);

View file

@ -43,10 +43,10 @@ public:
bool isValid() const { return threshold > 0.0f; }
bool shouldSubdivide(const glm::vec3& minimum, float size) const;
bool shouldSubdivide(const glm::vec3& minimum, float size, float multiplier = 1.0f) const;
/// 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) const;
bool becameSubdivided(const glm::vec3& minimum, float size, const MetavoxelLOD& reference, float multiplier = 1.0f) const;
};
DECLARE_STREAMABLE_METATYPE(MetavoxelLOD)
@ -119,9 +119,9 @@ public:
const MetavoxelLOD& lod;
const MetavoxelLOD& referenceLOD;
bool shouldSubdivide() const { return lod.shouldSubdivide(minimum, size); }
bool shouldSubdivideReference() const { return referenceLOD.shouldSubdivide(minimum, size); }
bool becameSubdivided() const { return lod.becameSubdivided(minimum, size, referenceLOD); }
bool shouldSubdivide() const;
bool shouldSubdivideReference() const;
bool becameSubdivided() const;
void setMinimum(const glm::vec3& lastMinimum, int index);
};
@ -230,6 +230,8 @@ public:
void setLOD(const MetavoxelLOD& lod) { _lod = lod; }
float getMinimumLODThresholdMultiplier() const { return _minimumLODThresholdMultiplier; }
/// Prepares for a new tour of the metavoxel data.
virtual void prepare();
@ -243,6 +245,7 @@ protected:
QVector<AttributePointer> _inputs;
QVector<AttributePointer> _outputs;
MetavoxelLOD _lod;
float _minimumLODThresholdMultiplier;
};
/// Base class for visitors to spanners.