mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Frustum class/box intersection testing.
This commit is contained in:
parent
8be42bf305
commit
c11b739ad6
2 changed files with 165 additions and 0 deletions
|
@ -315,6 +315,134 @@ QDebug& operator<<(QDebug& dbg, const Box& box) {
|
|||
return dbg.nospace() << "{type='Box', minimum=" << box.minimum << ", maximum=" << box.maximum << "}";
|
||||
}
|
||||
|
||||
AxisExtents::AxisExtents(const glm::vec3& first0, const glm::vec3& first1, const glm::vec3& first2, const glm::vec3& second) :
|
||||
axis(glm::cross(first2 - first1, first0 - first1)),
|
||||
minimum(glm::dot(first1, axis)),
|
||||
maximum(glm::dot(second, axis)) {
|
||||
}
|
||||
|
||||
AxisExtents::AxisExtents(const glm::vec3& axis, float minimum, float maximum) :
|
||||
axis(axis),
|
||||
minimum(minimum),
|
||||
maximum(maximum) {
|
||||
}
|
||||
|
||||
Frustum::Frustum(const glm::vec3& farTopLeft, const glm::vec3& farTopRight, const glm::vec3& farBottomLeft,
|
||||
const glm::vec3& farBottomRight, const glm::vec3& nearTopLeft, const glm::vec3& nearTopRight,
|
||||
const glm::vec3& nearBottomLeft, const glm::vec3& nearBottomRight) :
|
||||
_bounds(glm::vec3(FLT_MAX, FLT_MAX, FLT_MAX), glm::vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX)) {
|
||||
|
||||
_vertices[0] = farBottomLeft;
|
||||
_vertices[1] = farBottomRight;
|
||||
_vertices[2] = farTopLeft;
|
||||
_vertices[3] = farTopRight;
|
||||
_vertices[4] = nearBottomLeft;
|
||||
_vertices[5] = nearBottomRight;
|
||||
_vertices[6] = nearTopLeft;
|
||||
_vertices[7] = nearTopRight;
|
||||
|
||||
for (int i = 0; i < VERTEX_COUNT; i++) {
|
||||
_bounds.minimum = glm::min(_bounds.minimum, _vertices[i]);
|
||||
_bounds.maximum = glm::max(_bounds.maximum, _vertices[i]);
|
||||
}
|
||||
|
||||
// compute the extents for each side
|
||||
_sideExtents[0] = AxisExtents(nearBottomLeft, nearTopLeft, nearTopRight, farBottomLeft);
|
||||
_sideExtents[1] = AxisExtents(nearBottomLeft, farBottomLeft, farTopLeft, farBottomRight);
|
||||
_sideExtents[2] = AxisExtents(nearBottomRight, nearTopRight, farTopRight, farBottomLeft);
|
||||
_sideExtents[3] = AxisExtents(nearBottomLeft, nearBottomRight, farBottomRight, farTopLeft);
|
||||
_sideExtents[4] = AxisExtents(nearTopLeft, farTopLeft, farTopRight, farBottomRight);
|
||||
|
||||
// the other set of extents are derived from the cross products of the frustum and box edges
|
||||
glm::vec3 edges[] = { nearBottomRight - nearBottomLeft, nearTopLeft - nearBottomLeft, farBottomLeft - nearBottomLeft,
|
||||
farBottomRight - nearBottomRight, farTopLeft - nearTopLeft, farTopRight - nearTopRight };
|
||||
const int AXIS_COUNT = 3;
|
||||
for (uint i = 0, extentIndex = 0; i < sizeof(edges) / sizeof(edges[0]); i++) {
|
||||
for (int j = 0; j < AXIS_COUNT; j++) {
|
||||
glm::vec3 axis;
|
||||
axis[j] = 1.0f;
|
||||
glm::vec3 crossProduct = glm::cross(edges[i], axis);
|
||||
float minimum = FLT_MAX, maximum = -FLT_MAX;
|
||||
for (int k = 0; k < VERTEX_COUNT; k++) {
|
||||
float projection = glm::dot(crossProduct, _vertices[k]);
|
||||
minimum = glm::min(minimum, projection);
|
||||
maximum = glm::max(maximum, projection);
|
||||
}
|
||||
_crossProductExtents[extentIndex++] = AxisExtents(crossProduct, minimum, maximum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Frustum::IntersectionType Frustum::getIntersectionType(const Box& box) const {
|
||||
// first check the bounds (equivalent to checking frustum vertices against box extents)
|
||||
if (!_bounds.intersects(box)) {
|
||||
return NO_INTERSECTION;
|
||||
}
|
||||
|
||||
// check box vertices against side extents
|
||||
bool allInside = true;
|
||||
for (int i = 0; i < SIDE_EXTENT_COUNT; i++) {
|
||||
const AxisExtents& extents = _sideExtents[i];
|
||||
float firstProjection = glm::dot(box.getVertex(0), extents.axis);
|
||||
if (firstProjection < extents.minimum) {
|
||||
allInside = false;
|
||||
for (int j = 1; j < Box::VERTEX_COUNT; j++) {
|
||||
if (glm::dot(box.getVertex(j), extents.axis) >= extents.minimum) {
|
||||
goto sideContinue;
|
||||
}
|
||||
}
|
||||
return NO_INTERSECTION;
|
||||
|
||||
} else if (firstProjection > extents.maximum) {
|
||||
allInside = false;
|
||||
for (int j = 1; j < Box::VERTEX_COUNT; j++) {
|
||||
if (glm::dot(box.getVertex(j), extents.axis) <= extents.maximum) {
|
||||
goto sideContinue;
|
||||
}
|
||||
}
|
||||
return NO_INTERSECTION;
|
||||
|
||||
} else if (allInside) {
|
||||
for (int j = 1; j < Box::VERTEX_COUNT; j++) {
|
||||
float projection = glm::dot(box.getVertex(j), extents.axis);
|
||||
if (projection < extents.minimum || projection > extents.maximum) {
|
||||
allInside = false;
|
||||
goto sideContinue;
|
||||
}
|
||||
}
|
||||
}
|
||||
sideContinue: ;
|
||||
}
|
||||
if (allInside) {
|
||||
return CONTAINS_INTERSECTION;
|
||||
}
|
||||
|
||||
// check box vertices against cross product extents
|
||||
for (int i = 0; i < CROSS_PRODUCT_EXTENT_COUNT; i++) {
|
||||
const AxisExtents& extents = _crossProductExtents[i];
|
||||
float firstProjection = glm::dot(box.getVertex(0), extents.axis);
|
||||
if (firstProjection < extents.minimum) {
|
||||
for (int j = 1; j < Box::VERTEX_COUNT; j++) {
|
||||
if (glm::dot(box.getVertex(j), extents.axis) >= extents.minimum) {
|
||||
goto crossProductContinue;
|
||||
}
|
||||
}
|
||||
return NO_INTERSECTION;
|
||||
|
||||
} else if (firstProjection > extents.maximum) {
|
||||
for (int j = 1; j < Box::VERTEX_COUNT; j++) {
|
||||
if (glm::dot(box.getVertex(j), extents.axis) <= extents.maximum) {
|
||||
goto crossProductContinue;
|
||||
}
|
||||
}
|
||||
return NO_INTERSECTION;
|
||||
}
|
||||
crossProductContinue: ;
|
||||
}
|
||||
|
||||
return PARTIAL_INTERSECTION;
|
||||
}
|
||||
|
||||
QMetaObjectEditor::QMetaObjectEditor(QWidget* parent) : QWidget(parent) {
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
layout->setContentsMargins(QMargins());
|
||||
|
|
|
@ -65,6 +65,43 @@ Box operator*(const glm::mat4& matrix, const Box& box);
|
|||
|
||||
QDebug& operator<<(QDebug& out, const Box& box);
|
||||
|
||||
/// Represents the extents along an axis.
|
||||
class AxisExtents {
|
||||
public:
|
||||
glm::vec3 axis;
|
||||
float minimum;
|
||||
float maximum;
|
||||
|
||||
/// Creates a set of extents given three points on the first plane and one on the second.
|
||||
AxisExtents(const glm::vec3& first0, const glm::vec3& first1, const glm::vec3& first2, const glm::vec3& second);
|
||||
|
||||
AxisExtents(const glm::vec3& axis = glm::vec3(), float minimum = 0.0f, float maximum = 0.0f);
|
||||
};
|
||||
|
||||
/// A simple pyramidal frustum for intersection testing.
|
||||
class Frustum {
|
||||
public:
|
||||
|
||||
Frustum(const glm::vec3& farTopLeft, const glm::vec3& farTopRight, const glm::vec3& farBottomLeft,
|
||||
const glm::vec3& farBottomRight, const glm::vec3& nearTopLeft, const glm::vec3& nearTopRight,
|
||||
const glm::vec3& nearBottomLeft, const glm::vec3& nearBottomRight);
|
||||
|
||||
enum IntersectionType { NO_INTERSECTION, PARTIAL_INTERSECTION, CONTAINS_INTERSECTION };
|
||||
|
||||
IntersectionType getIntersectionType(const Box& box) const;
|
||||
|
||||
private:
|
||||
|
||||
static const int VERTEX_COUNT = 8;
|
||||
static const int SIDE_EXTENT_COUNT = 5;
|
||||
static const int CROSS_PRODUCT_EXTENT_COUNT = 18;
|
||||
|
||||
glm::vec3 _vertices[VERTEX_COUNT];
|
||||
Box _bounds;
|
||||
AxisExtents _sideExtents[SIDE_EXTENT_COUNT];
|
||||
AxisExtents _crossProductExtents[CROSS_PRODUCT_EXTENT_COUNT];
|
||||
};
|
||||
|
||||
/// Editor for meta-object values.
|
||||
class QMetaObjectEditor : public QWidget {
|
||||
Q_OBJECT
|
||||
|
|
Loading…
Reference in a new issue