Some untested ray intersection bits.

This commit is contained in:
Andrzej Kapolka 2014-03-10 14:58:31 -07:00
parent 7fc55e5596
commit 802cc3eeed
4 changed files with 175 additions and 5 deletions

View file

@ -10,6 +10,8 @@
#include <QScriptEngine>
#include <QtDebug>
#include <GeometryUtil.h>
#include "MetavoxelData.h"
#include "MetavoxelUtil.h"
#include "ScriptCache.h"
@ -821,6 +823,65 @@ int SpannerVisitor::visit(MetavoxelInfo& info) {
return info.isLeaf ? STOP_RECURSION : DEFAULT_ORDER;
}
RayIntersectionVisitor::RayIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction,
const QVector<AttributePointer>& inputs, const QVector<AttributePointer>& outputs, const MetavoxelLOD& lod) :
MetavoxelVisitor(inputs, outputs, lod),
_origin(origin),
_direction(direction),
_order(encodeOrder(direction)) {
}
int RayIntersectionVisitor::visit(MetavoxelInfo& info) {
float distance;
if (!info.getBounds().findRayIntersection(_origin, _direction, distance)) {
return STOP_RECURSION;
}
return visit(info, distance);
}
RayIntersectionSpannerVisitor::RayIntersectionSpannerVisitor(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()) {
}
void RayIntersectionSpannerVisitor::prepare() {
Spanner::incrementVisit();
}
class SpannerDistance {
public:
Spanner* spanner;
float distance;
};
bool operator<(const SpannerDistance& first, const SpannerDistance& second) {
return first.distance < second.distance;
}
int RayIntersectionSpannerVisitor::visit(MetavoxelInfo& info, float distance) {
QVarLengthArray<SpannerDistance, 4> spannerDistances;
for (int i = _inputs.size() - _spannerInputCount; i < _inputs.size(); i++) {
foreach (const SharedObjectPointer& object, info.inputValues.at(i).getInlineValue<SharedObjectSet>()) {
Spanner* spanner = static_cast<Spanner*>(object.data());
if (spanner->testAndSetVisited()) {
SpannerDistance spannerDistance = { spanner };
if (spanner->findRayIntersection(_origin, _direction, spannerDistance.distance)) {
spannerDistances.append(spannerDistance);
}
}
}
qStableSort(spannerDistances);
foreach (const SpannerDistance& spannerDistance, spannerDistances) {
if (!visit(spannerDistance.spanner, spannerDistance.distance)) {
return SHORT_CIRCUIT;
}
}
}
return info.isLeaf ? STOP_RECURSION : _order;
}
DefaultMetavoxelGuide::DefaultMetavoxelGuide() {
}
@ -1119,6 +1180,10 @@ SpannerRenderer* Spanner::getRenderer() {
return _renderer;
}
bool Spanner::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
return _bounds.findRayIntersection(origin, direction, distance);
}
QByteArray Spanner::getRendererClassName() const {
return "SpannerRendererer";
}
@ -1212,6 +1277,10 @@ bool Sphere::getAttributeValues(MetavoxelInfo& info) const {
return true;
}
bool Sphere::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
return findRaySphereIntersection(origin, direction, getTranslation(), getScale(), distance);
}
QByteArray Sphere::getRendererClassName() const {
return "SphereRenderer";
}

View file

@ -191,7 +191,7 @@ public:
glm::vec3 getCenter() const { return minimum + glm::vec3(size, size, size) * 0.5f; }
};
/// Interface for visitors to metavoxels.
/// Base class for visitors to metavoxels.
class MetavoxelVisitor {
public:
@ -241,9 +241,7 @@ protected:
MetavoxelLOD _lod;
};
typedef QSharedPointer<MetavoxelVisitor> MetavoxelVisitorPointer;
/// Interface for visitors to spanners.
/// Base class for visitors to spanners.
class SpannerVisitor : public MetavoxelVisitor {
public:
@ -264,6 +262,49 @@ protected:
int _spannerInputCount;
};
/// Base class for ray intersection visitors.
class RayIntersectionVisitor : public MetavoxelVisitor {
public:
RayIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction,
const QVector<AttributePointer>& inputs,
const QVector<AttributePointer>& outputs = QVector<AttributePointer>(),
const MetavoxelLOD& lod = MetavoxelLOD());
/// Visits a metavoxel that the ray intersects.
virtual int visit(MetavoxelInfo& info, float distance) = 0;
virtual int visit(MetavoxelInfo& info);
protected:
glm::vec3 _origin;
glm::vec3 _direction;
int _order;
};
/// Base class for ray intersection spanner visitors.
class RayIntersectionSpannerVisitor : public RayIntersectionVisitor {
public:
RayIntersectionSpannerVisitor(const glm::vec3& origin, const glm::vec3& direction,
const QVector<AttributePointer>& spannerInputs,
const QVector<AttributePointer>& inputs = QVector<AttributePointer>(),
const QVector<AttributePointer>& outputs = QVector<AttributePointer>(),
const MetavoxelLOD& lod = MetavoxelLOD());
/// Visits a spanner that the ray intersects.
/// \return true to continue, false to short-circuit the tour
virtual bool visit(Spanner* spanner, float distance) = 0;
virtual void prepare();
virtual int visit(MetavoxelInfo& info, float distance);
protected:
int _spannerInputCount;
};
/// Interface for objects that guide metavoxel visitors.
class MetavoxelGuide : public SharedObject {
Q_OBJECT
@ -389,6 +430,9 @@ public:
/// Returns a pointer to the renderer, creating it if necessary.
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;
signals:
void boundsWillChange();
@ -469,7 +513,8 @@ public:
virtual const QVector<AttributePointer>& getAttributes() const;
virtual bool getAttributeValues(MetavoxelInfo& info) const;
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
signals:
void colorChanged(const QColor& color);

View file

@ -150,6 +150,12 @@ Box::Box(const glm::vec3& minimum, const glm::vec3& maximum) :
minimum(minimum), maximum(maximum) {
}
bool Box::contains(const glm::vec3& point) const {
return point.x >= minimum.x && point.x <= maximum.x &&
point.y >= minimum.y && point.y <= maximum.y &&
point.z >= minimum.z && point.z <= maximum.z;
}
bool Box::contains(const Box& other) const {
return other.minimum.x >= minimum.x && other.maximum.x <= maximum.x &&
other.minimum.y >= minimum.y && other.maximum.y <= maximum.y &&
@ -173,6 +179,52 @@ glm::vec3 Box::getVertex(int index) const {
(index & Z_MAXIMUM_FLAG) ? maximum.z : minimum.z);
}
// finds the intersection between a ray and the facing plane on one axis
static bool findIntersection(float origin, float direction, float minimum, float maximum, float& distance) {
if (direction > EPSILON) {
distance = (minimum - origin) / direction;
return true;
} else if (direction < -EPSILON) {
distance = (maximum - origin) / direction;
return true;
}
return false;
}
// determines whether a value is within the extents
static bool isWithin(float value, float minimum, float maximum) {
return value >= minimum && value <= maximum;
}
bool Box::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
// handle the trivial case where the box contains the origin
if (contains(origin)) {
distance = 0.0f;
return true;
}
// check each axis
float axisDistance;
if ((findIntersection(origin.x, direction.x, minimum.x, maximum.x, axisDistance) && axisDistance >= 0 &&
isWithin(origin.y + axisDistance*direction.y, minimum.y, maximum.y) &&
isWithin(origin.z + axisDistance*direction.z, minimum.z, maximum.z))) {
distance = axisDistance;
return true;
}
if ((findIntersection(origin.y, direction.y, minimum.y, maximum.y, axisDistance) && axisDistance >= 0 &&
isWithin(origin.x + axisDistance*direction.x, minimum.x, maximum.x) &&
isWithin(origin.z + axisDistance*direction.z, minimum.z, maximum.z))) {
distance = axisDistance;
return true;
}
if ((findIntersection(origin.z, direction.z, minimum.z, maximum.z, axisDistance) && axisDistance >= 0 &&
isWithin(origin.y + axisDistance*direction.y, minimum.y, maximum.y) &&
isWithin(origin.x + axisDistance*direction.x, minimum.x, maximum.x))) {
distance = axisDistance;
return true;
}
return false;
}
Box operator*(const glm::mat4& matrix, const Box& box) {
// start with the constant component
Box newBox(glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2]), glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2]));

View file

@ -41,6 +41,8 @@ public:
Box(const glm::vec3& minimum = glm::vec3(), const glm::vec3& maximum = glm::vec3());
bool contains(const glm::vec3& point) const;
bool contains(const Box& other) const;
bool intersects(const Box& other) const;
@ -50,6 +52,8 @@ public:
glm::vec3 getVertex(int index) const;
glm::vec3 getCenter() const { return (minimum + maximum) * 0.5f; }
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
};
DECLARE_STREAMABLE_METATYPE(Box)