AxisAlignedBox.h#
↰ Parent directory (math
)
Class used to handle common AABB operations.
Includes#
PVRCore/glm.h
PVRCore/types/Types.h
cfloat
Namespaces#
Classes#
Functions#
Source Code#
#pragma once
#include "PVRCore/types/Types.h"
#include "PVRCore/glm.h"
#include <cfloat>
namespace pvr {
namespace math {
struct Frustum
{
glm::vec4 minusX;
glm::vec4 plusX;
glm::vec4 minusY;
glm::vec4 plusY;
glm::vec4 minusZ;
glm::vec4 plusZ;
glm::vec3 points[8];
};
struct ViewingFrustum : public Frustum
{
bool isFrustum() const
{
bool xopp = (glm::dot(glm::vec3(minusX), glm::vec3(plusX)) < 0);
bool yopp = (glm::dot(glm::vec3(minusY), glm::vec3(plusY)) < 0);
bool zopp = (glm::dot(glm::vec3(minusZ), glm::vec3(plusZ)) < 0);
return xopp && yopp && zopp;
};
};
inline float distancePointToPlane(const glm::vec3& point, const glm::vec4& plane) { return glm::dot(point, glm::vec3(plane.x, plane.y, plane.z)) + plane.w; }
inline bool pointOnSide(const glm::vec3& point, const glm::vec4& plane) { return distancePointToPlane(point, plane) >= 0.0f; }
inline void getFrustumPlanes(pvr::Api api, const glm::mat4& projection_from_world, ViewingFrustum& frustum_out)
{
const glm::vec4 row0 = glm::row(projection_from_world, 0);
const glm::vec4 row1 = glm::row(projection_from_world, 1) * (api == pvr::Api::Vulkan ? -1.f : 1.f);
const glm::vec4 row2 = glm::row(projection_from_world, 2);
const glm::vec4 row3 = glm::row(projection_from_world, 3);
frustum_out.minusX = row3 + row0;
frustum_out.plusX = row3 - row0;
frustum_out.minusY = row3 + row1;
frustum_out.plusY = row3 - row1;
frustum_out.minusZ = row3 + row2;
frustum_out.plusZ = row3 - row2;
frustum_out.minusX = frustum_out.minusX * (1 / glm::length(glm::vec3(frustum_out.minusX)));
frustum_out.plusX = frustum_out.plusX * (1 / glm::length(glm::vec3(frustum_out.plusX)));
frustum_out.minusY = frustum_out.minusY * (1 / glm::length(glm::vec3(frustum_out.minusY)));
frustum_out.plusY = frustum_out.plusY * (1 / glm::length(glm::vec3(frustum_out.plusY)));
frustum_out.minusZ = frustum_out.minusZ * (1 / glm::length(glm::vec3(frustum_out.minusZ)));
frustum_out.plusZ = frustum_out.plusZ * (1 / glm::length(glm::vec3(frustum_out.plusZ)));
}
inline glm::vec3 IntersectPlanes(glm::vec4 p0, glm::vec4 p1, glm::vec4 p2)
{
glm::vec3 bxc = glm::cross(glm::vec3(p1), glm::vec3(p2));
glm::vec3 cxa = glm::cross(glm::vec3(p2), glm::vec3(p0));
glm::vec3 axb = glm::cross(glm::vec3(p0), glm::vec3(p1));
glm::vec3 r = -p0.w * bxc - p1.w * cxa - p2.w * axb;
return r * (1 / glm::dot(glm::vec3(p0), bxc));
}
inline void getFrustumPoints(ViewingFrustum& frustum_out)
{
frustum_out.points[0] = IntersectPlanes(frustum_out.minusZ, frustum_out.minusX, frustum_out.minusY);
frustum_out.points[1] = IntersectPlanes(frustum_out.minusZ, frustum_out.minusX, frustum_out.plusY);
frustum_out.points[2] = IntersectPlanes(frustum_out.minusZ, frustum_out.plusX, frustum_out.plusY);
frustum_out.points[3] = IntersectPlanes(frustum_out.minusZ, frustum_out.plusX, frustum_out.minusY);
frustum_out.points[4] = IntersectPlanes(frustum_out.plusZ, frustum_out.minusX, frustum_out.minusY);
frustum_out.points[5] = IntersectPlanes(frustum_out.plusZ, frustum_out.minusX, frustum_out.plusY);
frustum_out.points[6] = IntersectPlanes(frustum_out.plusZ, frustum_out.plusX, frustum_out.plusY);
frustum_out.points[7] = IntersectPlanes(frustum_out.plusZ, frustum_out.plusX, frustum_out.minusY);
}
class AxisAlignedBoxMinMax;
class AxisAlignedBox
{
glm::vec3 _center;
glm::vec3 _halfExtent;
public:
AxisAlignedBox(const glm::vec3& center = glm::vec3(0.0f), const glm::vec3& halfExtent = glm::vec3(0.f)) : _center(center), _halfExtent(halfExtent) {}
AxisAlignedBox(const AxisAlignedBoxMinMax& copyFrom);
void clear()
{
_center.x = _center.y = _center.z = 0.0f;
_halfExtent = glm::vec3(0.f);
}
void setMinMax(const glm::vec3& min, const glm::vec3& max)
{
// compute the center.
_center = (max + min) * .5f;
_halfExtent = (max - min) * .5f;
}
void set(const glm::vec3& center, const glm::vec3& halfExtent)
{
_center = center;
_halfExtent = halfExtent;
}
void add(const glm::vec3& point) { setMinMax(glm::min(point, getMin()), glm::max(point, getMax())); }
void add(const AxisAlignedBox& aabb)
{
add(aabb.getMin());
add(aabb.getMax());
}
void add(float x, float y, float z) { add(glm::vec3(x, y, z)); }
glm::vec3 getMin() const { return _center - _halfExtent; }
glm::vec3 getMax() const { return _center + _halfExtent; }
void getMinMax(glm::vec3& outMin, glm::vec3& outMax) const
{
outMin = _center - _halfExtent;
outMax = _center + _halfExtent;
}
void transform(const glm::mat4& m, AxisAlignedBox& outAABB) const
{
outAABB._center = glm::vec3(m[3]) + (glm::mat3(m) * this->center());
glm::mat3 absModelMatrix;
absModelMatrix[0] = glm::vec3(fabs(m[0][0]), fabs(m[0][1]), fabs(m[0][2]));
absModelMatrix[1] = glm::vec3(fabs(m[1][0]), fabs(m[1][1]), fabs(m[1][2]));
absModelMatrix[2] = glm::vec3(fabs(m[2][0]), fabs(m[2][1]), fabs(m[2][2]));
outAABB._halfExtent = glm::vec3(absModelMatrix * this->getHalfExtent());
}
glm::vec3 getSize() const { return _halfExtent + _halfExtent; }
glm::vec3 getHalfExtent() const { return _halfExtent; }
glm::vec3 topLeftFar() const { return _center + glm::vec3(-_halfExtent.x, _halfExtent.y, _halfExtent.z); }
glm::vec3 topCenterFar() const { return _center + glm::vec3(0, _halfExtent.y, _halfExtent.z); }
glm::vec3 topRightFar() const { return _center + _halfExtent; }
glm::vec3 topLeftNear() const { return _center + glm::vec3(-_halfExtent.x, _halfExtent.y, -_halfExtent.z); }
glm::vec3 topCenterNear() const { return _center + glm::vec3(0., _halfExtent.y, -_halfExtent.z); }
glm::vec3 topRightNear() const { return _center + glm::vec3(_halfExtent.x, _halfExtent.y, -_halfExtent.z); }
glm::vec3 center() const { return _center; }
glm::vec3 centerLeftNear() const { return _center + glm::vec3(-_halfExtent.x, 0, -_halfExtent.z); }
glm::vec3 centerNear() const { return _center + glm::vec3(0, 0, -_halfExtent.z); }
glm::vec3 centerRightNear() const { return _center + glm::vec3(_halfExtent.x, 0, -_halfExtent.z); }
glm::vec3 centerLeftFar() const { return _center + glm::vec3(-_halfExtent.x, 0, _halfExtent.z); }
glm::vec3 centerFar() const { return _center + glm::vec3(0, 0, _halfExtent.z); }
glm::vec3 centerRightFar() const { return _center + glm::vec3(_halfExtent.x, 0, _halfExtent.z); }
glm::vec3 bottomLeftNear() const { return _center + glm::vec3(-_halfExtent.x, -_halfExtent.y, -_halfExtent.z); }
glm::vec3 bottomCenterNear() const { return _center + glm::vec3(0, -_halfExtent.y, -_halfExtent.z); }
glm::vec3 bottomRightNear() const { return _center + glm::vec3(_halfExtent.x, -_halfExtent.y, -_halfExtent.z); }
glm::vec3 bottomLeftFar() const { return _center + glm::vec3(-_halfExtent.x, -_halfExtent.y, _halfExtent.z); }
glm::vec3 bottomCenterFar() const { return _center + glm::vec3(0, -_halfExtent.y, _halfExtent.z); }
glm::vec3 bottomRightFar() const { return _center + glm::vec3(_halfExtent.x, -_halfExtent.y, _halfExtent.z); }
void mergeBox(const AxisAlignedBox& rhs) { setMinMax(glm::min(getMin(), rhs.getMin()), glm::max(getMax(), rhs.getMax())); }
bool operator==(const AxisAlignedBox& rhs) const { return _center == rhs._center && _halfExtent == rhs._halfExtent; }
bool operator!=(const AxisAlignedBox& rhs) const { return !(*this == rhs); }
};
namespace {
inline bool noPointsOnSide(glm::vec3 blf, glm::vec3 tlf, glm::vec3 brf, glm::vec3 trf, glm::vec3 bln, glm::vec3 tln, glm::vec3 brn, glm::vec3 trn, glm::vec4 plane)
{
if (pointOnSide(blf, plane) || pointOnSide(tlf, plane) || pointOnSide(brf, plane) || pointOnSide(trf, plane) || pointOnSide(bln, plane) || pointOnSide(tln, plane) ||
pointOnSide(brn, plane) || pointOnSide(trn, plane))
{ return false; }
return true;
}
} // namespace
inline bool aabbInFrustum(const AxisAlignedBox& box, const ViewingFrustum& frustum)
{
glm::vec3 blf = box.bottomLeftFar();
glm::vec3 tlf = box.topLeftFar();
glm::vec3 brf = box.bottomRightFar();
glm::vec3 trf = box.topRightFar();
glm::vec3 bln = box.bottomLeftNear();
glm::vec3 tln = box.topLeftNear();
glm::vec3 brn = box.bottomRightNear();
glm::vec3 trn = box.topRightNear();
if (noPointsOnSide(blf, tlf, brf, trf, bln, tln, brn, trn, frustum.minusX) || noPointsOnSide(blf, tlf, brf, trf, bln, tln, brn, trn, frustum.plusX) ||
noPointsOnSide(blf, tlf, brf, trf, bln, tln, brn, trn, frustum.minusY) || noPointsOnSide(blf, tlf, brf, trf, bln, tln, brn, trn, frustum.plusY) ||
noPointsOnSide(blf, tlf, brf, trf, bln, tln, brn, trn, frustum.minusZ) || noPointsOnSide(blf, tlf, brf, trf, bln, tln, brn, trn, frustum.plusZ))
{ return false; }
return true;
}
class AxisAlignedBoxMinMax
{
glm::vec3 _min;
glm::vec3 _max;
public:
AxisAlignedBoxMinMax() : _min(std::numeric_limits<float>::max()), _max(std::numeric_limits<float>::lowest()) {}
explicit AxisAlignedBoxMinMax(const AxisAlignedBox& copyFrom) : _min(copyFrom.getMin()), _max(copyFrom.getMax()) {}
void setMin(const glm::vec3& min) { _min = min; }
void setMax(const glm::vec3& max) { _max = max; }
const glm::vec3& getMin() const { return _min; }
const glm::vec3& getMax() const { return _max; }
void add(const glm::vec3& point)
{
_min = glm::min(_min, point);
_max = glm::max(_max, point);
}
};
inline AxisAlignedBox::AxisAlignedBox(const AxisAlignedBoxMinMax& copyFrom) { setMinMax(copyFrom.getMin(), copyFrom.getMax()); }
} // namespace math
} // namespace pvr