mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 18:23:54 +02:00
Various fixes and what-not, got the basic spanner clipping working.
This commit is contained in:
parent
10588cff9f
commit
005ae79928
9 changed files with 363 additions and 65 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue