mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 16:52:10 +02:00
Basic voxelization.
This commit is contained in:
parent
061d7719d4
commit
d706e23012
5 changed files with 138 additions and 23 deletions
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue