Basic voxelization.

This commit is contained in:
Andrzej Kapolka 2014-04-03 23:47:31 -07:00
parent 061d7719d4
commit d706e23012
5 changed files with 138 additions and 23 deletions

View file

@ -656,35 +656,45 @@ bool SetSpannerTool::appliesTo(const AttributePointer& attribute) const {
return attribute == AttributeRegistry::getInstance()->getSpannersAttribute(); 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::quat DIRECTION_ROTATIONS[] = {
glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, 0.0f, 1.0f) }; 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. /// Represents a view from one direction of the spanner to be voxelized.
class DirectionImages { class DirectionImages {
public: public:
QImage color; QImage color;
QVector<float> depth; QVector<float> depth;
glm::vec3 minima;
glm::vec3 maxima;
glm::vec3 scale;
}; };
class Voxelizer : public QRunnable { class Voxelizer : public QRunnable {
public: public:
Voxelizer(float size, const Box& bounds, const QVector<DirectionImages>& directionImages); Voxelizer(float size, const Box& bounds, float granularity, const QVector<DirectionImages>& directionImages);
virtual void run(); virtual void run();
private: private:
void voxelize(const glm::vec3& minimum); void voxelize(const glm::vec3& center);
float _size; float _size;
Box _bounds; Box _bounds;
float _granularity;
QVector<DirectionImages> _directionImages; QVector<DirectionImages> _directionImages;
}; };
Voxelizer::Voxelizer(float size, const Box& bounds, const QVector<DirectionImages>& directionImages) : Voxelizer::Voxelizer(float size, const Box& bounds, float granularity, const QVector<DirectionImages>& directionImages) :
_size(size), _size(size),
_bounds(bounds), _bounds(bounds),
_granularity(granularity),
_directionImages(directionImages) { _directionImages(directionImages) {
} }
@ -694,13 +704,108 @@ void Voxelizer::run() {
for (float x = _bounds.minimum.x + halfSize; x < _bounds.maximum.x; x += _size) { 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 y = _bounds.minimum.y + halfSize; y < _bounds.maximum.y; y += _size) {
for (float z = _bounds.minimum.z + halfSize; z < _bounds.maximum.z; z += _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>& directionImages, const glm::vec3& center, float granularity);
virtual int visit(MetavoxelInfo& info);
private:
QVector<DirectionImages> _directionImages;
glm::vec3 _center;
float _granularity;
};
VoxelizationVisitor::VoxelizationVisitor(const QVector<DirectionImages>& directionImages,
const glm::vec3& center, float granularity) :
MetavoxelVisitor(QVector<AttributePointer>(), QVector<AttributePointer>() <<
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<QRgb>(color));
return STOP_RECURSION;
}
if (distance < closestDistance) {
closestColor = color;
closestDistance = distance;
}
}
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<QRgb>(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) { void SetSpannerTool::applyEdit(const AttributePointer& attribute, const SharedObjectPointer& spanner) {
@ -725,12 +830,11 @@ void SetSpannerTool::applyEdit(const AttributePointer& attribute, const SharedOb
QVector<DirectionImages> directionImages; QVector<DirectionImages> directionImages;
for (unsigned int i = 0; i < sizeof(DIRECTION_VECTORS) / sizeof(DIRECTION_VECTORS[0]); i++) { for (unsigned int i = 0; i < sizeof(DIRECTION_ROTATIONS) / sizeof(DIRECTION_ROTATIONS[0]); i++) {
glm::quat rotation = rotationBetween(DIRECTION_VECTORS[i], IDENTITY_FRONT);
glm::vec3 minima(FLT_MAX, FLT_MAX, FLT_MAX); glm::vec3 minima(FLT_MAX, FLT_MAX, FLT_MAX);
glm::vec3 maxima(-FLT_MAX, -FLT_MAX, -FLT_MAX); glm::vec3 maxima(-FLT_MAX, -FLT_MAX, -FLT_MAX);
for (int j = 0; j < Box::VERTEX_COUNT; j++) { 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); minima = glm::min(minima, rotated);
maxima = glm::max(maxima, 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); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); 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); glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); glLoadIdentity();
glm::vec3 axis = glm::axis(rotation); glm::vec3 axis = glm::axis(DIRECTION_ROTATIONS[i]);
glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); 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); spannerData->getRenderer()->render(1.0f, glm::vec3(), 0.0f);
DirectionImages images = { QImage(width, height, QImage::Format_ARGB32), QVector<float>(width * height) }; DirectionImages images = { QImage(width, height, QImage::Format_ARGB32),
QVector<float>(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_BGRA, GL_UNSIGNED_BYTE, images.color.bits());
glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, images.depth.data()); glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, images.depth.data());
directionImages.append(images); 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()); glViewport(0, 0, Application::getInstance()->getGLWidget()->width(), Application::getInstance()->getGLWidget()->height());
// send the images off to the lab for processing // 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));
} }

View file

@ -373,7 +373,12 @@ static void setNode(const AttributeValue& value, MetavoxelNode*& node, const glm
setNode(value, node, other, blend); setNode(value, node, other, blend);
return; return;
} }
if (!node) { if (node) {
MetavoxelNode* oldNode = node;
node = new MetavoxelNode(value.getAttribute(), oldNode);
oldNode->decrementReferenceCount(value.getAttribute());
} else {
node = new MetavoxelNode(value); node = new MetavoxelNode(value);
} }
int index = 0; 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) { void MetavoxelData::set(const glm::vec3& minimum, const MetavoxelData& data, bool blend) {
// expand to fit the entire data // 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)) { while (!getBounds().contains(bounds)) {
expand(); expand();
} }

View file

@ -61,6 +61,7 @@ public:
MetavoxelData& operator=(const MetavoxelData& other); MetavoxelData& operator=(const MetavoxelData& other);
void setSize(float size) { _size = size; }
float getSize() const { return _size; } float getSize() const { return _size; }
glm::vec3 getMinimum() const { return glm::vec3(_size, _size, _size) * -0.5f; } glm::vec3 getMinimum() const { return glm::vec3(_size, _size, _size) * -0.5f; }

View file

@ -20,18 +20,17 @@ REGISTER_META_OBJECT(SharedObject)
SharedObject::SharedObject() : SharedObject::SharedObject() :
_id(++_lastID), _id(++_lastID),
_remoteID(0), _remoteID(0) {
_referenceCount(0) {
_weakHash.insert(_id, this); _weakHash.insert(_id, this);
} }
void SharedObject::incrementReferenceCount() { void SharedObject::incrementReferenceCount() {
_referenceCount++; _referenceCount.ref();
} }
void SharedObject::decrementReferenceCount() { void SharedObject::decrementReferenceCount() {
if (--_referenceCount == 0) { if (!_referenceCount.deref()) {
_weakHash.remove(_id); _weakHash.remove(_id);
delete this; delete this;
} }

View file

@ -9,6 +9,7 @@
#ifndef __interface__SharedObject__ #ifndef __interface__SharedObject__
#define __interface__SharedObject__ #define __interface__SharedObject__
#include <QAtomicInt>
#include <QHash> #include <QHash>
#include <QMetaType> #include <QMetaType>
#include <QObject> #include <QObject>
@ -42,7 +43,7 @@ public:
void setRemoteID(int remoteID) { _remoteID = remoteID; } void setRemoteID(int remoteID) { _remoteID = remoteID; }
int getReferenceCount() const { return _referenceCount; } int getReferenceCount() const { return _referenceCount.load(); }
void incrementReferenceCount(); void incrementReferenceCount();
void decrementReferenceCount(); void decrementReferenceCount();
@ -62,7 +63,7 @@ private:
int _id; int _id;
int _remoteID; int _remoteID;
int _referenceCount; QAtomicInt _referenceCount;
static int _lastID; static int _lastID;
static WeakSharedObjectHash _weakHash; static WeakSharedObjectHash _weakHash;