diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 1c37ec9078..6471dd21b2 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -656,35 +656,45 @@ bool SetSpannerTool::appliesTo(const AttributePointer& attribute) const { return attribute == AttributeRegistry::getInstance()->getSpannersAttribute(); } -glm::vec3 DIRECTION_VECTORS[] = { glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f), - glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, 0.0f, 1.0f) }; +glm::quat DIRECTION_ROTATIONS[] = { + rotationBetween(glm::vec3(-1.0f, 0.0f, 0.0f), IDENTITY_FRONT), + rotationBetween(glm::vec3(1.0f, 0.0f, 0.0f), IDENTITY_FRONT), + rotationBetween(glm::vec3(0.0f, -1.0f, 0.0f), IDENTITY_FRONT), + rotationBetween(glm::vec3(0.0f, 1.0f, 0.0f), IDENTITY_FRONT), + rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), IDENTITY_FRONT), + rotationBetween(glm::vec3(0.0f, 0.0f, 1.0f), IDENTITY_FRONT) }; /// Represents a view from one direction of the spanner to be voxelized. class DirectionImages { public: QImage color; QVector depth; + glm::vec3 minima; + glm::vec3 maxima; + glm::vec3 scale; }; class Voxelizer : public QRunnable { public: - Voxelizer(float size, const Box& bounds, const QVector& directionImages); + Voxelizer(float size, const Box& bounds, float granularity, const QVector& directionImages); virtual void run(); private: - void voxelize(const glm::vec3& minimum); + void voxelize(const glm::vec3& center); float _size; Box _bounds; + float _granularity; QVector _directionImages; }; -Voxelizer::Voxelizer(float size, const Box& bounds, const QVector& directionImages) : +Voxelizer::Voxelizer(float size, const Box& bounds, float granularity, const QVector& directionImages) : _size(size), _bounds(bounds), + _granularity(granularity), _directionImages(directionImages) { } @@ -694,13 +704,108 @@ void Voxelizer::run() { for (float x = _bounds.minimum.x + halfSize; x < _bounds.maximum.x; x += _size) { for (float y = _bounds.minimum.y + halfSize; y < _bounds.maximum.y; y += _size) { for (float z = _bounds.minimum.z + halfSize; z < _bounds.maximum.z; z += _size) { - + voxelize(glm::vec3(x, y, z)); } } } } -void Voxelizer::voxelize(const glm::vec3& minimum) { +class VoxelizationVisitor : public MetavoxelVisitor { +public: + + VoxelizationVisitor(const QVector& directionImages, const glm::vec3& center, float granularity); + + virtual int visit(MetavoxelInfo& info); + +private: + + QVector _directionImages; + glm::vec3 _center; + float _granularity; +}; + +VoxelizationVisitor::VoxelizationVisitor(const QVector& directionImages, + const glm::vec3& center, float granularity) : + MetavoxelVisitor(QVector(), QVector() << + AttributeRegistry::getInstance()->getColorAttribute()), + _directionImages(directionImages), + _center(center), + _granularity(granularity) { +} + +bool checkDisjoint(const DirectionImages& images, const glm::vec3& minimum, const glm::vec3& maximum) { + for (int x = qMax(0, (int)minimum.x), xmax = qMin(images.color.width(), (int)maximum.x); x < xmax; x++) { + for (int y = qMax(0, (int)minimum.y), ymax = qMin(images.color.height(), (int)maximum.y); y < ymax; y++) { + float depth = 1.0f - images.depth.at(y * images.color.width() + x); + if (depth - minimum.z >= 0.0f) { + return false; + } + } + } + return true; +} + +int VoxelizationVisitor::visit(MetavoxelInfo& info) { + float halfSize = info.size * 0.5f; + glm::vec3 center = info.minimum + _center + glm::vec3(halfSize, halfSize, halfSize); + if (info.size > _granularity) { + for (unsigned int i = 0; i < sizeof(DIRECTION_ROTATIONS) / sizeof(DIRECTION_ROTATIONS[0]); i++) { + glm::vec3 rotated = DIRECTION_ROTATIONS[i] * center; + const DirectionImages& images = _directionImages.at(i); + glm::vec3 relative = (rotated - images.minima) * images.scale; + glm::vec3 extents = images.scale * halfSize; + glm::vec3 minimum = relative - extents; + glm::vec3 maximum = relative + extents; + if (checkDisjoint(images, minimum, maximum)) { + info.outputValues[0] = AttributeValue(_outputs.at(0)); + return STOP_RECURSION; + } + } + return DEFAULT_ORDER; + } + QRgb closestColor; + float closestDistance = FLT_MAX; + for (unsigned int i = 0; i < sizeof(DIRECTION_ROTATIONS) / sizeof(DIRECTION_ROTATIONS[0]); i++) { + glm::vec3 rotated = DIRECTION_ROTATIONS[i] * center; + const DirectionImages& images = _directionImages.at(i); + glm::vec3 relative = (rotated - images.minima) * images.scale; + int x = qMax(qMin((int)glm::round(relative.x), images.color.width() - 1), 0); + int y = qMax(qMin((int)glm::round(relative.y), images.color.height() - 1), 0); + float depth = 1.0f - images.depth.at(y * images.color.width() + x); + float distance = depth - relative.z; + if (distance < 0.0f) { + info.outputValues[0] = AttributeValue(_outputs.at(0)); + return STOP_RECURSION; + } + QRgb color = images.color.pixel(x, y); + if (distance < EPSILON) { + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(color)); + return STOP_RECURSION; + } + if (distance < closestDistance) { + closestColor = color; + closestDistance = distance; + } + } + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(closestColor)); + return STOP_RECURSION; +} + +void Voxelizer::voxelize(const glm::vec3& center) { + MetavoxelData data; + data.setSize(_size); + + qDebug() << "Started voxelizing " << center.x << center.y << center.z; + + VoxelizationVisitor visitor(_directionImages, center, _granularity); + data.guide(visitor); + + qDebug() << "Finished voxelizing " << center.x << center.y << center.z; + + MetavoxelEditMessage edit = { QVariant::fromValue(SetDataEdit( + center - glm::vec3(_size, _size, _size) * 0.5f, data, false)) }; + QMetaObject::invokeMethod(Application::getInstance()->getMetavoxels(), "applyEdit", + Q_ARG(const MetavoxelEditMessage&, edit), Q_ARG(bool, true)); } void SetSpannerTool::applyEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) { @@ -725,12 +830,11 @@ void SetSpannerTool::applyEdit(const AttributePointer& attribute, const SharedOb QVector directionImages; - for (unsigned int i = 0; i < sizeof(DIRECTION_VECTORS) / sizeof(DIRECTION_VECTORS[0]); i++) { - glm::quat rotation = rotationBetween(DIRECTION_VECTORS[i], IDENTITY_FRONT); + for (unsigned int i = 0; i < sizeof(DIRECTION_ROTATIONS) / sizeof(DIRECTION_ROTATIONS[0]); i++) { glm::vec3 minima(FLT_MAX, FLT_MAX, FLT_MAX); glm::vec3 maxima(-FLT_MAX, -FLT_MAX, -FLT_MAX); for (int j = 0; j < Box::VERTEX_COUNT; j++) { - glm::vec3 rotated = rotation * cellBounds.getVertex(j); + glm::vec3 rotated = DIRECTION_ROTATIONS[i] * cellBounds.getVertex(j); minima = glm::min(minima, rotated); maxima = glm::max(maxima, rotated); } @@ -742,16 +846,20 @@ void SetSpannerTool::applyEdit(const AttributePointer& attribute, const SharedOb glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); - glOrtho(minima.x, maxima.x, minima.y, maxima.y, -minima.z, -maxima.z); + glOrtho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); + glm::vec3 axis = glm::axis(DIRECTION_ROTATIONS[i]); + glRotatef(glm::degrees(glm::angle(DIRECTION_ROTATIONS[i])), axis.x, axis.y, axis.z); + + Application::getInstance()->setupWorldLight(); spannerData->getRenderer()->render(1.0f, glm::vec3(), 0.0f); - DirectionImages images = { QImage(width, height, QImage::Format_ARGB32), QVector(width * height) }; + DirectionImages images = { QImage(width, height, QImage::Format_ARGB32), + QVector(width * height), minima, maxima, glm::vec3(width / (maxima.x - minima.x), + height / (maxima.y - minima.y), 1.0f / (maxima.z - minima.z)) }; glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, images.color.bits()); glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, images.depth.data()); directionImages.append(images); @@ -771,5 +879,6 @@ void SetSpannerTool::applyEdit(const AttributePointer& attribute, const SharedOb glViewport(0, 0, Application::getInstance()->getGLWidget()->width(), Application::getInstance()->getGLWidget()->height()); // send the images off to the lab for processing - QThreadPool::globalInstance()->start(new Voxelizer(size, cellBounds, directionImages)); + QThreadPool::globalInstance()->start(new Voxelizer(size, cellBounds, + spannerData->getVoxelizationGranularity(), directionImages)); } diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index efbc0b157d..f86406a507 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -373,7 +373,12 @@ static void setNode(const AttributeValue& value, MetavoxelNode*& node, const glm setNode(value, node, other, blend); return; } - if (!node) { + if (node) { + MetavoxelNode* oldNode = node; + node = new MetavoxelNode(value.getAttribute(), oldNode); + oldNode->decrementReferenceCount(value.getAttribute()); + + } else { node = new MetavoxelNode(value); } int index = 0; @@ -403,7 +408,7 @@ static void setNode(const AttributeValue& value, MetavoxelNode*& node, const glm void MetavoxelData::set(const glm::vec3& minimum, const MetavoxelData& data, bool blend) { // expand to fit the entire data - Box bounds = minimum + glm::vec3(data.getSize(), data.getSize(), data.getSize()); + Box bounds(minimum, minimum + glm::vec3(data.getSize(), data.getSize(), data.getSize())); while (!getBounds().contains(bounds)) { expand(); } diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index ed8b1a224c..4254b3bbb2 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -61,6 +61,7 @@ public: MetavoxelData& operator=(const MetavoxelData& other); + void setSize(float size) { _size = size; } float getSize() const { return _size; } glm::vec3 getMinimum() const { return glm::vec3(_size, _size, _size) * -0.5f; } diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index 36257a740f..64ea48e016 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -20,18 +20,17 @@ REGISTER_META_OBJECT(SharedObject) SharedObject::SharedObject() : _id(++_lastID), - _remoteID(0), - _referenceCount(0) { + _remoteID(0) { _weakHash.insert(_id, this); } void SharedObject::incrementReferenceCount() { - _referenceCount++; + _referenceCount.ref(); } void SharedObject::decrementReferenceCount() { - if (--_referenceCount == 0) { + if (!_referenceCount.deref()) { _weakHash.remove(_id); delete this; } diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index 435127fffd..2751a66db3 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -9,6 +9,7 @@ #ifndef __interface__SharedObject__ #define __interface__SharedObject__ +#include #include #include #include @@ -42,7 +43,7 @@ public: void setRemoteID(int remoteID) { _remoteID = remoteID; } - int getReferenceCount() const { return _referenceCount; } + int getReferenceCount() const { return _referenceCount.load(); } void incrementReferenceCount(); void decrementReferenceCount(); @@ -62,7 +63,7 @@ private: int _id; int _remoteID; - int _referenceCount; + QAtomicInt _referenceCount; static int _lastID; static WeakSharedObjectHash _weakHash;