Various fixes and what-not, got the basic spanner clipping working.

This commit is contained in:
Andrzej Kapolka 2014-03-31 18:21:28 -07:00
parent 10588cff9f
commit 005ae79928
9 changed files with 363 additions and 65 deletions

View file

@ -167,14 +167,14 @@ void MetavoxelSystem::maybeAttachClient(const SharedNodePointer& node) {
MetavoxelSystem::SimulateVisitor::SimulateVisitor(QVector<Point>& points) :
SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute(),
QVector<AttributePointer>() << AttributeRegistry::getInstance()->getColorAttribute() <<
QVector<AttributePointer>(), QVector<AttributePointer>() << AttributeRegistry::getInstance()->getColorAttribute() <<
AttributeRegistry::getInstance()->getNormalAttribute() <<
AttributeRegistry::getInstance()->getSpannerColorAttribute() <<
AttributeRegistry::getInstance()->getSpannerNormalAttribute()),
_points(points) {
}
bool MetavoxelSystem::SimulateVisitor::visit(Spanner* spanner) {
bool MetavoxelSystem::SimulateVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) {
spanner->getRenderer()->simulate(_deltaTime);
return true;
}
@ -223,11 +223,12 @@ int MetavoxelSystem::SimulateVisitor::visit(MetavoxelInfo& info) {
}
MetavoxelSystem::RenderVisitor::RenderVisitor() :
SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute()) {
SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute(),
QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannerMaskAttribute()) {
}
bool MetavoxelSystem::RenderVisitor::visit(Spanner* spanner) {
spanner->getRenderer()->render(1.0f);
bool MetavoxelSystem::RenderVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) {
spanner->getRenderer()->render(1.0f, clipMinimum, clipSize);
return true;
}
@ -333,10 +334,55 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) {
}
}
static void enableClipPlane(GLenum plane, float x, float y, float z, float w) {
GLdouble coefficients[] = { x, y, z, w };
glClipPlane(plane, coefficients);
glEnable(plane);
}
void ClippedRenderer::render(float alpha, const glm::vec3& clipMinimum, float clipSize) {
if (clipSize == 0.0f) {
renderUnclipped(alpha);
return;
}
enableClipPlane(GL_CLIP_PLANE0, -1.0f, 0.0f, 0.0f, clipMinimum.x + clipSize);
enableClipPlane(GL_CLIP_PLANE1, 1.0f, 0.0f, 0.0f, -clipMinimum.x);
enableClipPlane(GL_CLIP_PLANE2, 0.0f, -1.0f, 0.0f, clipMinimum.y + clipSize);
enableClipPlane(GL_CLIP_PLANE3, 0.0f, 1.0f, 0.0f, -clipMinimum.y);
enableClipPlane(GL_CLIP_PLANE4, 0.0f, 0.0f, -1.0f, clipMinimum.z + clipSize);
enableClipPlane(GL_CLIP_PLANE5, 0.0f, 0.0f, 1.0f, -clipMinimum.z);
renderUnclipped(alpha);
glDisable(GL_CLIP_PLANE0);
glDisable(GL_CLIP_PLANE1);
glDisable(GL_CLIP_PLANE2);
glDisable(GL_CLIP_PLANE3);
glDisable(GL_CLIP_PLANE4);
glDisable(GL_CLIP_PLANE5);
}
SphereRenderer::SphereRenderer() {
}
void SphereRenderer::render(float alpha) {
void SphereRenderer::render(float alpha, const glm::vec3& clipMinimum, float clipSize) {
if (clipSize == 0.0f) {
renderUnclipped(alpha);
return;
}
// slight performance optimization: don't render if clip bounds are entirely within sphere
Sphere* sphere = static_cast<Sphere*>(parent());
Box clipBox(clipMinimum, clipMinimum + glm::vec3(clipSize, clipSize, clipSize));
for (int i = 0; i < Box::VERTEX_COUNT; i++) {
const float CLIP_PROPORTION = 0.95f;
if (glm::distance(sphere->getTranslation(), clipBox.getVertex(i)) >= sphere->getScale() * CLIP_PROPORTION) {
ClippedRenderer::render(alpha, clipMinimum, clipSize);
return;
}
}
}
void SphereRenderer::renderUnclipped(float alpha) {
Sphere* sphere = static_cast<Sphere*>(parent());
const QColor& color = sphere->getColor();
glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF() * alpha);
@ -384,11 +430,12 @@ void StaticModelRenderer::simulate(float deltaTime) {
_model->simulate(deltaTime);
}
void StaticModelRenderer::render(float alpha) {
void StaticModelRenderer::renderUnclipped(float alpha) {
_model->render(alpha);
}
bool StaticModelRenderer::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
bool StaticModelRenderer::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const {
return _model->findRayIntersection(origin, direction, distance);
}

View file

@ -61,7 +61,7 @@ private:
SimulateVisitor(QVector<Point>& points);
void setDeltaTime(float deltaTime) { _deltaTime = deltaTime; }
void setOrder(const glm::vec3& direction) { _order = encodeOrder(direction); }
virtual bool visit(Spanner* spanner);
virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize);
virtual int visit(MetavoxelInfo& info);
private:
@ -73,7 +73,7 @@ private:
class RenderVisitor : public SpannerVisitor {
public:
RenderVisitor();
virtual bool visit(Spanner* spanner);
virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize);
};
static ProgramObject _program;
@ -141,19 +141,36 @@ private:
QList<ReceiveRecord> _receiveRecords;
};
/// Base class for spanner renderers; provides clipping.
class ClippedRenderer : public SpannerRenderer {
Q_OBJECT
public:
virtual void render(float alpha, const glm::vec3& clipMinimum, float clipSize);
protected:
virtual void renderUnclipped(float alpha) = 0;
};
/// Renders spheres.
class SphereRenderer : public SpannerRenderer {
class SphereRenderer : public ClippedRenderer {
Q_OBJECT
public:
Q_INVOKABLE SphereRenderer();
virtual void render(float alpha);
virtual void render(float alpha, const glm::vec3& clipMinimum, float clipSize);
protected:
virtual void renderUnclipped(float alpha);
};
/// Renders static models.
class StaticModelRenderer : public SpannerRenderer {
class StaticModelRenderer : public ClippedRenderer {
Q_OBJECT
public:
@ -162,8 +179,12 @@ public:
virtual void init(Spanner* spanner);
virtual void simulate(float deltaTime);
virtual void render(float alpha);
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const;
protected:
virtual void renderUnclipped(float alpha);
private slots:

View file

@ -565,7 +565,7 @@ void PlaceSpannerTool::render() {
}
Spanner* spanner = static_cast<Spanner*>(_editor->getValue().value<SharedObjectPointer>().data());
const float SPANNER_ALPHA = 0.25f;
spanner->getRenderer()->render(SPANNER_ALPHA);
spanner->getRenderer()->render(SPANNER_ALPHA, glm::vec3(), 0.0f);
}
bool PlaceSpannerTool::appliesTo(const AttributePointer& attribute) const {

View file

@ -11,6 +11,7 @@
#include "AttributeRegistry.h"
#include "MetavoxelData.h"
REGISTER_META_OBJECT(FloatAttribute)
REGISTER_META_OBJECT(QRgbAttribute)
REGISTER_META_OBJECT(PackedNormalAttribute)
REGISTER_META_OBJECT(SpannerQRgbAttribute)
@ -34,7 +35,8 @@ AttributeRegistry::AttributeRegistry() :
_colorAttribute(registerAttribute(new QRgbAttribute("color"))),
_normalAttribute(registerAttribute(new PackedNormalAttribute("normal"))),
_spannerColorAttribute(registerAttribute(new SpannerQRgbAttribute("spannerColor"))),
_spannerNormalAttribute(registerAttribute(new SpannerPackedNormalAttribute("spannerNormal"))) {
_spannerNormalAttribute(registerAttribute(new SpannerPackedNormalAttribute("spannerNormal"))),
_spannerMaskAttribute(registerAttribute(new FloatAttribute("spannerMask"))) {
// our baseline LOD threshold is for voxels; spanners are a different story
const float SPANNER_LOD_THRESHOLD_MULTIPLIER = 8.0f;
@ -198,6 +200,10 @@ void Attribute::writeMetavoxelSubdivision(const MetavoxelNode& root, MetavoxelSt
root.writeSubdivision(state);
}
FloatAttribute::FloatAttribute(const QString& name, float defaultValue) :
SimpleInlineAttribute<float>(name, defaultValue) {
}
QRgbAttribute::QRgbAttribute(const QString& name, QRgb defaultValue) :
InlineAttribute<QRgb>(name, defaultValue) {
}

View file

@ -80,6 +80,9 @@ public:
/// Returns a reference to the standard packed normal "spannerNormal" attribute.
const AttributePointer& getSpannerNormalAttribute() const { return _spannerNormalAttribute; }
/// Returns a reference to the standard "spannerMask" attribute.
const AttributePointer& getSpannerMaskAttribute() const { return _spannerMaskAttribute; }
private:
static QScriptValue getAttribute(QScriptContext* context, QScriptEngine* engine);
@ -91,6 +94,7 @@ private:
AttributePointer _normalAttribute;
AttributePointer _spannerColorAttribute;
AttributePointer _spannerNormalAttribute;
AttributePointer _spannerMaskAttribute;
};
/// Converts a value to a void pointer.
@ -265,6 +269,39 @@ template<class T, int bits> inline void InlineAttribute<T, bits>::write(Bitstrea
}
}
/// Provides averaging using the +=, ==, and / operators.
template<class T, int bits = 32> class SimpleInlineAttribute : public InlineAttribute<T, bits> {
public:
SimpleInlineAttribute(const QString& name, const T& defaultValue = T()) : InlineAttribute<T, bits>(name, defaultValue) { }
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
};
template<class T, int bits> inline bool SimpleInlineAttribute<T, bits>::merge(
void*& parent, void* children[], bool postRead) const {
T firstValue = decodeInline<T>(children[0]);
T totalValue = firstValue;
bool allChildrenEqual = true;
for (int i = 1; i < Attribute::MERGE_COUNT; i++) {
T value = decodeInline<T>(children[i]);
totalValue += value;
allChildrenEqual &= (firstValue == value);
}
parent = encodeInline(totalValue / Attribute::MERGE_COUNT);
return allChildrenEqual;
}
/// Simple float attribute.
class FloatAttribute : public SimpleInlineAttribute<float> {
Q_OBJECT
Q_PROPERTY(float defaultValue MEMBER _defaultValue)
public:
Q_INVOKABLE FloatAttribute(const QString& name = QString(), float defaultValue = 0.0f);
};
/// Provides appropriate averaging for RGBA values.
class QRgbAttribute : public InlineAttribute<QRgb> {
Q_OBJECT

View file

@ -223,12 +223,12 @@ void Bitstream::persistReadMappings(const ReadMappings& mappings) {
if (!it.value()) {
continue;
}
QPointer<SharedObject>& reference = _sharedObjectReferences[it.value()->getID()];
QPointer<SharedObject>& reference = _sharedObjectReferences[it.value()->getRemoteID()];
if (reference) {
_sharedObjectStreamer.removePersistentValue(reference.data());
}
reference = it.value();
_weakSharedObjectHash.remove(it.value()->getID());
_weakSharedObjectHash.remove(it.value()->getRemoteID());
}
}
@ -863,7 +863,7 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) {
}
} else {
QObject* rawObject;
if (reference) {
if (reference) {
readRawDelta(rawObject, (QObject*)reference.data());
} else {
*this >> rawObject;

View file

@ -212,6 +212,67 @@ void MetavoxelData::toggle(const AttributePointer& attribute, const Box& bounds,
guide(visitor);
}
void MetavoxelData::replace(const AttributePointer& attribute, const SharedObjectPointer& oldObject,
const SharedObjectPointer& newObject) {
Spanner* spanner = static_cast<Spanner*>(oldObject.data());
replace(attribute, spanner->getBounds(), spanner->getPlacementGranularity(), oldObject, newObject);
}
class SpannerReplaceVisitor : public MetavoxelVisitor {
public:
SpannerReplaceVisitor(const AttributePointer& attribute, const Box& bounds,
float granularity, const SharedObjectPointer& oldObject, const SharedObjectPointer& newObject);
virtual int visit(MetavoxelInfo& info);
private:
const AttributePointer& _attribute;
const Box& _bounds;
float _longestSide;
const SharedObjectPointer& _oldObject;
const SharedObjectPointer& _newObject;
};
SpannerReplaceVisitor::SpannerReplaceVisitor(const AttributePointer& attribute, const Box& bounds, float granularity,
const SharedObjectPointer& oldObject, const SharedObjectPointer& newObject) :
MetavoxelVisitor(QVector<AttributePointer>() << attribute, QVector<AttributePointer>() << attribute),
_attribute(attribute),
_bounds(bounds),
_longestSide(qMax(bounds.getLongestSide(), granularity)),
_oldObject(oldObject),
_newObject(newObject) {
}
int SpannerReplaceVisitor::visit(MetavoxelInfo& info) {
if (!info.getBounds().intersects(_bounds)) {
return STOP_RECURSION;
}
if (info.size > _longestSide) {
return DEFAULT_ORDER;
}
SharedObjectSet set = info.inputValues.at(0).getInlineValue<SharedObjectSet>();
if (set.remove(_oldObject)) {
set.insert(_newObject);
}
info.outputValues[0] = AttributeValue(_attribute, encodeInline(set));
return STOP_RECURSION;
}
void MetavoxelData::replace(const AttributePointer& attribute, const Box& bounds, float granularity,
const SharedObjectPointer& oldObject, const SharedObjectPointer& newObject) {
Spanner* newSpanner = static_cast<Spanner*>(newObject.data());
if (bounds != newSpanner->getBounds() || granularity != newSpanner->getPlacementGranularity()) {
// if the bounds have changed, we must remove and reinsert
remove(attribute, bounds, granularity, oldObject);
insert(attribute, newSpanner->getBounds(), newSpanner->getPlacementGranularity(), newObject);
return;
}
SpannerReplaceVisitor visitor(attribute, bounds, granularity, oldObject, newObject);
guide(visitor);
}
void MetavoxelData::clear(const AttributePointer& attribute) {
MetavoxelNode* node = _roots.take(attribute);
if (node) {
@ -239,7 +300,7 @@ private:
FirstRaySpannerIntersectionVisitor::FirstRaySpannerIntersectionVisitor(
const glm::vec3& origin, const glm::vec3& direction, const AttributePointer& attribute, const MetavoxelLOD& lod) :
RaySpannerIntersectionVisitor(origin, direction, QVector<AttributePointer>() << attribute,
QVector<AttributePointer>(), QVector<AttributePointer>(), lod),
QVector<AttributePointer>(), QVector<AttributePointer>(), QVector<AttributePointer>(), lod),
_spanner(NULL) {
}
@ -878,10 +939,11 @@ void MetavoxelVisitor::prepare() {
// nothing by default
}
SpannerVisitor::SpannerVisitor(const QVector<AttributePointer>& spannerInputs, const QVector<AttributePointer>& inputs,
const QVector<AttributePointer>& outputs, const MetavoxelLOD& lod) :
MetavoxelVisitor(inputs + spannerInputs, outputs, lod),
_spannerInputCount(spannerInputs.size()) {
SpannerVisitor::SpannerVisitor(const QVector<AttributePointer>& spannerInputs, const QVector<AttributePointer>& spannerMasks,
const QVector<AttributePointer>& inputs, const QVector<AttributePointer>& outputs, const MetavoxelLOD& lod) :
MetavoxelVisitor(inputs + spannerInputs + spannerMasks, outputs, lod),
_spannerInputCount(spannerInputs.size()),
_spannerMaskCount(spannerMasks.size()) {
}
void SpannerVisitor::prepare() {
@ -889,17 +951,34 @@ void SpannerVisitor::prepare() {
}
int SpannerVisitor::visit(MetavoxelInfo& info) {
for (int i = _inputs.size() - _spannerInputCount; i < _inputs.size(); i++) {
for (int end = _inputs.size() - _spannerMaskCount, i = end - _spannerInputCount, j = end; i < end; i++, j++) {
foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue<SharedObjectSet>()) {
Spanner* spanner = static_cast<Spanner*>(object.data());
if (spanner->testAndSetVisited()) {
if (!visit(spanner)) {
return SHORT_CIRCUIT;
}
if (!(spanner->isMasked() && j < _inputs.size()) && spanner->testAndSetVisited() &&
!visit(spanner, glm::vec3(), 0.0f)) {
return SHORT_CIRCUIT;
}
}
}
return info.isLeaf ? STOP_RECURSION : DEFAULT_ORDER;
if (!info.isLeaf) {
return DEFAULT_ORDER;
}
for (int i = _inputs.size() - _spannerMaskCount; i < _inputs.size(); i++) {
float maskValue = info.inputValues.at(i).getInlineValue<float>();
if (maskValue < 0.5f) {
const MetavoxelInfo* nextInfo = &info;
do {
foreach (const SharedObjectPointer& object, nextInfo->inputValues.at(
i - _spannerInputCount).getInlineValue<SharedObjectSet>()) {
Spanner* spanner = static_cast<Spanner*>(object.data());
if (spanner->isMasked() && !visit(spanner, info.minimum, info.size)) {
return SHORT_CIRCUIT;
}
}
} while ((nextInfo = nextInfo->parentInfo));
}
}
return STOP_RECURSION;
}
RayIntersectionVisitor::RayIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction,
@ -919,10 +998,11 @@ int RayIntersectionVisitor::visit(MetavoxelInfo& info) {
}
RaySpannerIntersectionVisitor::RaySpannerIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction,
const QVector<AttributePointer>& spannerInputs, const QVector<AttributePointer>& inputs,
const QVector<AttributePointer>& outputs, const MetavoxelLOD& lod) :
RayIntersectionVisitor(origin, direction, inputs + spannerInputs, outputs, lod),
_spannerInputCount(spannerInputs.size()) {
const QVector<AttributePointer>& spannerInputs, const QVector<AttributePointer>& spannerMasks,
const QVector<AttributePointer>& inputs, const QVector<AttributePointer>& outputs, const MetavoxelLOD& lod) :
RayIntersectionVisitor(origin, direction, inputs + spannerInputs + spannerMasks, outputs, lod),
_spannerInputCount(spannerInputs.size()),
_spannerMaskCount(spannerMasks.size()) {
}
void RaySpannerIntersectionVisitor::prepare() {
@ -941,12 +1021,12 @@ bool operator<(const SpannerDistance& first, const SpannerDistance& second) {
int RaySpannerIntersectionVisitor::visit(MetavoxelInfo& info, float distance) {
QVarLengthArray<SpannerDistance, 4> spannerDistances;
for (int i = _inputs.size() - _spannerInputCount; i < _inputs.size(); i++) {
for (int end = _inputs.size() - _spannerMaskCount, i = end - _spannerInputCount, j = end; i < end; i++, j++) {
foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue<SharedObjectSet>()) {
Spanner* spanner = static_cast<Spanner*>(object.data());
if (spanner->testAndSetVisited()) {
if (!(spanner->isMasked() && j < _inputs.size()) && spanner->testAndSetVisited()) {
SpannerDistance spannerDistance = { spanner };
if (spanner->findRayIntersection(_origin, _direction, spannerDistance.distance)) {
if (spanner->findRayIntersection(_origin, _direction, glm::vec3(), 0.0f, spannerDistance.distance)) {
spannerDistances.append(spannerDistance);
}
}
@ -958,7 +1038,36 @@ int RaySpannerIntersectionVisitor::visit(MetavoxelInfo& info, float distance) {
}
}
}
return info.isLeaf ? STOP_RECURSION : _order;
if (!info.isLeaf) {
return _order;
}
for (int i = _inputs.size() - _spannerMaskCount; i < _inputs.size(); i++) {
float maskValue = info.inputValues.at(i).getInlineValue<float>();
if (maskValue < 0.5f) {
const MetavoxelInfo* nextInfo = &info;
do {
foreach (const SharedObjectPointer& object, nextInfo->inputValues.at(
i - _spannerInputCount).getInlineValue<SharedObjectSet>()) {
Spanner* spanner = static_cast<Spanner*>(object.data());
if (spanner->isMasked()) {
SpannerDistance spannerDistance = { spanner };
if (spanner->findRayIntersection(_origin, _direction,
info.minimum, info.size, spannerDistance.distance)) {
spannerDistances.append(spannerDistance);
}
}
}
} while ((nextInfo = nextInfo->parentInfo));
qStableSort(spannerDistances);
foreach (const SpannerDistance& spannerDistance, spannerDistances) {
if (!visitSpanner(spannerDistance.spanner, spannerDistance.distance)) {
return SHORT_CIRCUIT;
}
}
}
}
return STOP_RECURSION;
}
DefaultMetavoxelGuide::DefaultMetavoxelGuide() {
@ -1224,6 +1333,7 @@ Spanner::Spanner() :
_renderer(NULL),
_placementGranularity(DEFAULT_PLACEMENT_GRANULARITY),
_voxelizationGranularity(DEFAULT_VOXELIZATION_GRANULARITY),
_masked(false),
_lastVisit(0) {
}
@ -1276,7 +1386,8 @@ SpannerRenderer* Spanner::getRenderer() {
return _renderer;
}
bool Spanner::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
bool Spanner::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const {
return _bounds.findRayIntersection(origin, direction, distance);
}
@ -1297,11 +1408,12 @@ void SpannerRenderer::simulate(float deltaTime) {
// nothing by default
}
void SpannerRenderer::render(float alpha) {
void SpannerRenderer::render(float alpha, const glm::vec3& clipMinimum, float clipSize) {
// nothing by default
}
bool SpannerRenderer::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
bool SpannerRenderer::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const {
return false;
}
@ -1424,7 +1536,8 @@ bool Sphere::blendAttributeValues(MetavoxelInfo& info, bool force) const {
return true;
}
bool Sphere::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
bool Sphere::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const {
return findRaySphereIntersection(origin, direction, getTranslation(), getScale(), distance);
}
@ -1463,10 +1576,11 @@ void StaticModel::setURL(const QUrl& url) {
}
}
bool StaticModel::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
bool StaticModel::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const {
// delegate to renderer, if we have one
return _renderer ? _renderer->findRayIntersection(origin, direction, distance) :
Spanner::findRayIntersection(origin, direction, distance);
return _renderer ? _renderer->findRayIntersection(origin, direction, clipMinimum, clipSize, distance) :
Spanner::findRayIntersection(origin, direction, clipMinimum, clipSize, distance);
}
QByteArray StaticModel::getRendererClassName() const {

View file

@ -79,6 +79,11 @@ public:
void toggle(const AttributePointer& attribute, const SharedObjectPointer& object);
void toggle(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& object);
void replace(const AttributePointer& attribute, const SharedObjectPointer& oldObject,
const SharedObjectPointer& newObject);
void replace(const AttributePointer& attribute, const Box& bounds, float granularity, const SharedObjectPointer& oldObject,
const SharedObjectPointer& newObject);
void clear(const AttributePointer& attribute);
/// Convenience function that finds the first spanner intersecting the provided ray.
@ -255,13 +260,15 @@ class SpannerVisitor : public MetavoxelVisitor {
public:
SpannerVisitor(const QVector<AttributePointer>& spannerInputs,
const QVector<AttributePointer>& spannerMasks = QVector<AttributePointer>(),
const QVector<AttributePointer>& inputs = QVector<AttributePointer>(),
const QVector<AttributePointer>& outputs = QVector<AttributePointer>(),
const MetavoxelLOD& lod = MetavoxelLOD());
/// Visits a spanner.
/// Visits a spanner (or part thereof).
/// \param clipSize the size of the clip volume, or zero if unclipped
/// \return true to continue, false to short-circuit the tour
virtual bool visit(Spanner* spanner) = 0;
virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) = 0;
virtual void prepare();
virtual int visit(MetavoxelInfo& info);
@ -269,6 +276,7 @@ public:
protected:
int _spannerInputCount;
int _spannerMaskCount;
};
/// Base class for ray intersection visitors.
@ -298,11 +306,12 @@ public:
RaySpannerIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction,
const QVector<AttributePointer>& spannerInputs,
const QVector<AttributePointer>& spannerMasks = QVector<AttributePointer>(),
const QVector<AttributePointer>& inputs = QVector<AttributePointer>(),
const QVector<AttributePointer>& outputs = QVector<AttributePointer>(),
const MetavoxelLOD& lod = MetavoxelLOD());
/// Visits a spanner that the ray intersects.
/// Visits a spannerthat the ray intersects.
/// \return true to continue, false to short-circuit the tour
virtual bool visitSpanner(Spanner* spanner, float distance) = 0;
@ -312,6 +321,7 @@ public:
protected:
int _spannerInputCount;
int _spannerMaskCount;
};
/// Interface for objects that guide metavoxel visitors.
@ -412,6 +422,7 @@ class Spanner : public SharedObject {
Q_PROPERTY(Box bounds MEMBER _bounds WRITE setBounds NOTIFY boundsChanged DESIGNABLE false)
Q_PROPERTY(float placementGranularity MEMBER _placementGranularity DESIGNABLE false)
Q_PROPERTY(float voxelizationGranularity MEMBER _voxelizationGranularity DESIGNABLE false)
Q_PROPERTY(float masked MEMBER _masked DESIGNABLE false)
public:
@ -429,6 +440,9 @@ public:
void setVoxelizationGranularity(float granularity) { _voxelizationGranularity = granularity; }
float getVoxelizationGranularity() const { return _voxelizationGranularity; }
void setMasked(bool masked) { _masked = masked; }
bool isMasked() const { return _masked; }
/// Returns a reference to the list of attributes associated with this spanner.
virtual const QVector<AttributePointer>& getAttributes() const;
@ -452,7 +466,9 @@ public:
SpannerRenderer* getRenderer();
/// Finds the intersection between the described ray and this spanner.
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
/// \param clipSize the size of the clip region, or zero if unclipped
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const;
signals:
@ -471,6 +487,7 @@ private:
Box _bounds;
float _placementGranularity;
float _voxelizationGranularity;
bool _masked;
int _lastVisit; ///< the identifier of the last visit
static int _visit; ///< the global visit counter
@ -486,8 +503,9 @@ public:
virtual void init(Spanner* spanner);
virtual void simulate(float deltaTime);
virtual void render(float alpha);
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
virtual void render(float alpha, const glm::vec3& clipMinimum, float clipSize);
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const;
};
/// An object with a 3D transform.
@ -539,7 +557,8 @@ public:
virtual const QVector<AttributePointer>& getVoxelizedAttributes() const;
virtual bool getAttributeValues(MetavoxelInfo& info, bool force = false) const;
virtual bool blendAttributeValues(MetavoxelInfo& info, bool force = false) const;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize, float& distance) const;
signals:
@ -572,7 +591,8 @@ public:
void setURL(const QUrl& url);
const QUrl& getURL() const { return _url; }
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
const glm::vec3& clipMinimum, float clipSize,float& distance) const;
signals:

View file

@ -32,7 +32,8 @@ private:
};
BoxSetEditVisitor::BoxSetEditVisitor(const BoxSetEdit& edit) :
MetavoxelVisitor(QVector<AttributePointer>(), QVector<AttributePointer>() << edit.value.getAttribute()),
MetavoxelVisitor(QVector<AttributePointer>(), QVector<AttributePointer>() << edit.value.getAttribute() <<
AttributeRegistry::getInstance()->getSpannerMaskAttribute()),
_edit(edit) {
}
@ -47,25 +48,68 @@ int BoxSetEditVisitor::visit(MetavoxelInfo& info) {
float volume = (size.x * size.y * size.z) / (info.size * info.size * info.size);
if (volume >= 1.0f) {
info.outputValues[0] = _edit.value;
info.outputValues[1] = AttributeValue(_outputs.at(1), encodeInline<float>(1.0f));
return STOP_RECURSION; // entirely contained
}
if (info.size <= _edit.granularity) {
if (volume >= 0.5f) {
info.outputValues[0] = _edit.value;
info.outputValues[1] = AttributeValue(_outputs.at(1), encodeInline<float>(1.0f));
}
return STOP_RECURSION; // reached granularity limit; take best guess
}
return DEFAULT_ORDER; // subdivide
}
class GatherUnmaskedSpannersVisitor : public SpannerVisitor {
public:
GatherUnmaskedSpannersVisitor(const Box& bounds);
const QList<SharedObjectPointer>& getUnmaskedSpanners() const { return _unmaskedSpanners; }
virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize);
private:
Box _bounds;
QList<SharedObjectPointer> _unmaskedSpanners;
};
GatherUnmaskedSpannersVisitor::GatherUnmaskedSpannersVisitor(const Box& bounds) :
SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute()),
_bounds(bounds) {
}
bool GatherUnmaskedSpannersVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) {
if (!spanner->isMasked() && spanner->getBounds().intersects(_bounds)) {
_unmaskedSpanners.append(spanner);
}
return true;
}
static void setIntersectingMasked(const Box& bounds, MetavoxelData& data) {
GatherUnmaskedSpannersVisitor visitor(bounds);
data.guide(visitor);
foreach (const SharedObjectPointer& object, visitor.getUnmaskedSpanners()) {
Spanner* newSpanner = static_cast<Spanner*>(object->clone(true));
newSpanner->setMasked(true);
data.replace(AttributeRegistry::getInstance()->getSpannersAttribute(), object, newSpanner);
}
}
void BoxSetEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
// expand to fit the entire edit
while (!data.getBounds().contains(region)) {
data.expand();
}
BoxSetEditVisitor visitor(*this);
data.guide(visitor);
BoxSetEditVisitor setVisitor(*this);
data.guide(setVisitor);
// flip the mask flag of all intersecting spanners
setIntersectingMasked(region, data);
}
GlobalSetEdit::GlobalSetEdit(const OwnedAttributeValue& value) :
@ -180,25 +224,25 @@ ClearSpannersEdit::ClearSpannersEdit(const AttributePointer& attribute) :
attribute(attribute) {
}
class GetSpannerAttributesVisitor : public SpannerVisitor {
class GatherSpannerAttributesVisitor : public SpannerVisitor {
public:
GetSpannerAttributesVisitor(const AttributePointer& attribute);
GatherSpannerAttributesVisitor(const AttributePointer& attribute);
const QSet<AttributePointer>& getAttributes() const { return _attributes; }
virtual bool visit(Spanner* spanner);
virtual bool visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize);
protected:
QSet<AttributePointer> _attributes;
};
GetSpannerAttributesVisitor::GetSpannerAttributesVisitor(const AttributePointer& attribute) :
GatherSpannerAttributesVisitor::GatherSpannerAttributesVisitor(const AttributePointer& attribute) :
SpannerVisitor(QVector<AttributePointer>() << attribute) {
}
bool GetSpannerAttributesVisitor::visit(Spanner* spanner) {
bool GatherSpannerAttributesVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, float clipSize) {
foreach (const AttributePointer& attribute, spanner->getVoxelizedAttributes()) {
_attributes.insert(attribute);
}
@ -207,7 +251,7 @@ bool GetSpannerAttributesVisitor::visit(Spanner* spanner) {
void ClearSpannersEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
// find all the spanner attributes
GetSpannerAttributesVisitor visitor(attribute);
GatherSpannerAttributesVisitor visitor(attribute);
data.guide(visitor);
data.clear(attribute);
@ -233,12 +277,19 @@ private:
};
SetSpannerEditVisitor::SetSpannerEditVisitor(const QVector<AttributePointer>& attributes, Spanner* spanner) :
MetavoxelVisitor(attributes, attributes),
MetavoxelVisitor(attributes, QVector<AttributePointer>() << attributes <<
AttributeRegistry::getInstance()->getSpannerMaskAttribute()),
_spanner(spanner) {
}
int SetSpannerEditVisitor::visit(MetavoxelInfo& info) {
return _spanner->blendAttributeValues(info) ? DEFAULT_ORDER : STOP_RECURSION;
if (_spanner->blendAttributeValues(info)) {
return DEFAULT_ORDER;
}
if (info.outputValues.at(0).getAttribute()) {
info.outputValues.last() = AttributeValue(_outputs.last(), encodeInline<float>(1.0f));
}
return STOP_RECURSION;
}
void SetSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const {
@ -251,4 +302,6 @@ void SetSpannerEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& obje
SetSpannerEditVisitor visitor(spanner->getAttributes(), spanner);
data.guide(visitor);
setIntersectingMasked(spanner->getBounds(), data);
}