Implement more OBB methods
This commit is contained in:
@@ -6,6 +6,11 @@
|
||||
|
||||
|
||||
namespace J3ML::Geometry {
|
||||
/// A 3D arbitrarily oriented bounding box
|
||||
// This data structure represents a box in 3D space. The local axes of this box can be arbitrarily oriented/rotated
|
||||
// with respect to the global world coordinate system. This allows OBBs to more tightly bound objects than AABBs do,
|
||||
// which always align with the world space axes. This flexibility has the drawback that the geometry tests and operations
|
||||
// involving OBBs are more costly, and representing an OBB in memory takes more space (15 floats vs 6 floats)
|
||||
class OBB : public Shape
|
||||
{
|
||||
public:
|
||||
@@ -16,7 +21,9 @@ namespace J3ML::Geometry {
|
||||
// Specifies normalized direction vectors for the local axes
|
||||
Vector3 axis[3];
|
||||
|
||||
/// Default constructor that does not initialize any member values.
|
||||
OBB() {}
|
||||
// Constructs an OBB by explicitly initializing all member values
|
||||
OBB(const Vector3& pos, const Vector3& radii, const Vector3& axis0, const Vector3& axis1, const Vector3& axis2);
|
||||
OBB(const AABB& aabb);
|
||||
inline static int NumFaces() { return 6; }
|
||||
@@ -24,7 +31,7 @@ namespace J3ML::Geometry {
|
||||
inline static int NumVertices() { return 8; }
|
||||
|
||||
Polyhedron ToPolyhedron() const;
|
||||
|
||||
//PBVolume<6> ToPBVolume() const;
|
||||
AABB MinimalEnclosingAABB() const
|
||||
{
|
||||
AABB aabb;
|
||||
@@ -38,6 +45,8 @@ namespace J3ML::Geometry {
|
||||
Vector3 HalfSize() const;
|
||||
Vector3 Diagonal() const;
|
||||
Vector3 HalfDiagonal() const;
|
||||
void Transform(const Matrix3x3& transform);
|
||||
void Transform(const Matrix4x4& transform);
|
||||
bool IsFinite() const;
|
||||
bool IsDegenerate() const;
|
||||
Vector3 CenterPoint() const;
|
||||
@@ -45,9 +54,31 @@ namespace J3ML::Geometry {
|
||||
|
||||
Vector3 AnyPointFast() const;
|
||||
|
||||
float Volume();
|
||||
float SurfaceArea();
|
||||
float Volume() const;
|
||||
float SurfaceArea() const;
|
||||
Geometry::LineSegment Edge(int edgeIndex) const;
|
||||
Vector3 CornerPoint(int cornerIndex) const;
|
||||
|
||||
Vector3 PointInside(float x, float y, float z) const;
|
||||
Vector3 PointInside(const Vector3& pt) const;
|
||||
|
||||
void ProjectToAxis(const Vector3 &direction, float &outMin, float &outMax) const;
|
||||
|
||||
int UniqueFaceNormals(Vector3 *out) const;
|
||||
|
||||
int UniqueEdgeDirections(Vector3 *out) const;
|
||||
|
||||
Vector3 PointOnEdge(int edgeIndex, float u) const;
|
||||
|
||||
Vector3 FaceCenterPoint(int faceIndex) const;
|
||||
|
||||
void GetCornerPoints(Vector3 *outPointArray) const;
|
||||
|
||||
void GetFacePlanes(Plane *outPlaneArray) const;
|
||||
|
||||
Plane FacePlane(int faceIndex) const;
|
||||
|
||||
void ExtremePointsAlongDirection(const Vector3 &dir, const Vector3 *pointArray, int numPoints, int &idxSmallest,
|
||||
int &idxLargest, float &smallestD, float &largestD);
|
||||
};
|
||||
}
|
@@ -3,6 +3,7 @@
|
||||
#include <J3ML/Geometry/LineSegment.h>
|
||||
#include <J3ML/Geometry/Polyhedron.h>
|
||||
#include <J3ML/Geometry/OBB.h>
|
||||
#include <J3ML/Geometry/Sphere.h>
|
||||
|
||||
namespace J3ML::Geometry
|
||||
{
|
||||
@@ -41,8 +42,277 @@ namespace J3ML::Geometry
|
||||
return p;
|
||||
}
|
||||
|
||||
Vector3 OBB::CornerPoint(int cornerIndex) const {
|
||||
// TODO: implement
|
||||
return Vector3();
|
||||
Sphere OBB::MinimalEnclosingSphere() const {
|
||||
Sphere s;
|
||||
s.Position = pos;
|
||||
s.Radius = HalfDiagonal().Length();
|
||||
return s;
|
||||
}
|
||||
|
||||
Sphere OBB::MaximalContainedSphere() const {
|
||||
Sphere s;
|
||||
s.Position = pos;
|
||||
s.Radius = r.MinElement();
|
||||
return s;
|
||||
}
|
||||
|
||||
bool OBB::IsFinite() const {
|
||||
return pos.IsFinite() && r.IsFinite() && axis[0].IsFinite() && axis[1].IsFinite() && axis[2].IsFinite();
|
||||
}
|
||||
|
||||
bool OBB::IsDegenerate() const
|
||||
{
|
||||
return !(r.x > 0.f && r.y > 0.f && r.z > 0.f);
|
||||
}
|
||||
|
||||
Vector3 OBB::CenterPoint() const
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
|
||||
Vector3 OBB::PointInside(float x, float y, float z) const
|
||||
{
|
||||
assert(0.f <= x && x <= 1.f);
|
||||
assert(0.f <= y && y <= 1.f);
|
||||
assert(0.f <= z && z <= 1.f);
|
||||
|
||||
return pos + axis[0] * (2.f * r.x * x - r.x)
|
||||
+ axis[1] * (2.f * r.y * y - r.y)
|
||||
+ axis[2] * (2.f * r.z * z - r.z);
|
||||
}
|
||||
|
||||
Vector3 OBB::PointInside(const Vector3& pt) const
|
||||
{
|
||||
return PointInside(pt.x, pt.y, pt.z);
|
||||
}
|
||||
|
||||
LineSegment OBB::Edge(int edgeIndex) const
|
||||
{
|
||||
assert(0 <= edgeIndex && edgeIndex <= 11);
|
||||
|
||||
switch(edgeIndex)
|
||||
{
|
||||
default: // For release builds where Assert() is disabled, return always the first option if out-of-bounds
|
||||
case 0: return LineSegment(CornerPoint(0), CornerPoint(1));
|
||||
case 1: return LineSegment(CornerPoint(0), CornerPoint(2));
|
||||
case 2: return LineSegment(CornerPoint(0), CornerPoint(4));
|
||||
case 3: return LineSegment(CornerPoint(1), CornerPoint(3));
|
||||
case 4: return LineSegment(CornerPoint(1), CornerPoint(5));
|
||||
case 5: return LineSegment(CornerPoint(2), CornerPoint(3));
|
||||
case 6: return LineSegment(CornerPoint(2), CornerPoint(6));
|
||||
case 7: return LineSegment(CornerPoint(3), CornerPoint(7));
|
||||
case 8: return LineSegment(CornerPoint(4), CornerPoint(5));
|
||||
case 9: return LineSegment(CornerPoint(4), CornerPoint(6));
|
||||
case 10: return LineSegment(CornerPoint(5), CornerPoint(7));
|
||||
case 11: return LineSegment(CornerPoint(6), CornerPoint(7));
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 OBB::CornerPoint(int cornerIndex) const
|
||||
{
|
||||
assert(0 <= cornerIndex && cornerIndex <= 7);
|
||||
switch(cornerIndex)
|
||||
{
|
||||
default: // For release builds, return always the first option if out of bounds
|
||||
case 0: return pos - r.x * axis[0] - r.y * axis[1] - r.z * axis[2];
|
||||
case 1: return pos - r.x * axis[0] - r.y * axis[1] + r.z * axis[2];
|
||||
case 2: return pos - r.x * axis[0] + r.y * axis[1] - r.z * axis[2];
|
||||
case 3: return pos - r.x * axis[0] + r.y * axis[1] + r.z * axis[2];
|
||||
case 4: return pos + r.x * axis[0] - r.y * axis[1] - r.z * axis[2];
|
||||
case 5: return pos + r.x * axis[0] - r.y * axis[1] + r.z * axis[2];
|
||||
case 6: return pos + r.x * axis[0] + r.y * axis[1] - r.z * axis[2];
|
||||
case 7: return pos + r.x * axis[0] + r.y * axis[1] + r.z * axis[2];
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 OBB::ExtremePoint(const Vector3& direction) const
|
||||
{
|
||||
Vector3 pt = pos;
|
||||
pt += axis[0] * (Vector3::Dot(direction, axis[0]) >= 0.f ? r.x : -r.x);
|
||||
pt += axis[1] * (Vector3::Dot(direction, axis[1]) >= 0.f ? r.y : -r.y);
|
||||
pt += axis[2] * (Vector3::Dot(direction, axis[2]) >= 0.f ? r.z : -r.z);
|
||||
return pt;
|
||||
}
|
||||
|
||||
Vector3 OBB::ExtremePoint(const Vector3& direction, float &projectionDistance) const
|
||||
{
|
||||
Vector3 extremePoint = ExtremePoint(direction);
|
||||
projectionDistance = extremePoint.Dot(direction);
|
||||
return extremePoint;
|
||||
}
|
||||
|
||||
void OBB::ProjectToAxis(const Vector3& direction, float& outMin, float& outMax) const
|
||||
{
|
||||
float x = std::abs(Vector3::Dot(direction, axis[0]) * r.x);
|
||||
float y = std::abs(Vector3::Dot(direction, axis[1]) * r.y);
|
||||
float z = std::abs(Vector3::Dot(direction, axis[2]) * r.z);
|
||||
float pt = Vector3::Dot(direction, pos);
|
||||
outMin = pt - x - y - z;
|
||||
outMax = pt + x + y + z;
|
||||
}
|
||||
|
||||
int OBB::UniqueFaceNormals(Vector3* out) const
|
||||
{
|
||||
out[0] = axis[0];
|
||||
out[1] = axis[1];
|
||||
out[2] = axis[2];
|
||||
return 3;
|
||||
}
|
||||
|
||||
int OBB::UniqueEdgeDirections(Vector3* out) const
|
||||
{
|
||||
out[0] = axis[0];
|
||||
out[1] = axis[1];
|
||||
out[2] = axis[2];
|
||||
return 3;
|
||||
}
|
||||
|
||||
Vector3 OBB::PointOnEdge(int edgeIndex, float u) const
|
||||
{
|
||||
assert(0 <= edgeIndex && edgeIndex <= 11);
|
||||
assert(0 <= u && u <= 1.f);
|
||||
|
||||
edgeIndex = std::clamp(edgeIndex, 0, 11);
|
||||
Vector3 d = axis[edgeIndex/4] * (2.f * u - 1.f) * r[edgeIndex/4];
|
||||
switch(edgeIndex)
|
||||
{
|
||||
default:
|
||||
case 0: return pos - r.y * axis[1] - r.z * axis[2] + d;
|
||||
case 1: return pos - r.y * axis[1] + r.z * axis[2] + d;
|
||||
case 2: return pos + r.y * axis[1] - r.z * axis[2] + d;
|
||||
case 3: return pos + r.y * axis[1] + r.z * axis[2] + d;
|
||||
|
||||
case 4: return pos - r.x * axis[0] - r.z * axis[2] + d;
|
||||
case 5: return pos - r.x * axis[0] + r.z * axis[2] + d;
|
||||
case 6: return pos + r.x * axis[0] - r.z * axis[2] + d;
|
||||
case 7: return pos + r.x * axis[0] + r.z * axis[2] + d;
|
||||
|
||||
case 8: return pos - r.x * axis[0] - r.y * axis[1] + d;
|
||||
case 9: return pos - r.x * axis[0] + r.y * axis[1] + d;
|
||||
case 10: return pos + r.x * axis[0] - r.y * axis[1] + d;
|
||||
case 11: return pos + r.x * axis[0] + r.y * axis[1] + d;
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 OBB::FaceCenterPoint(int faceIndex) const
|
||||
{
|
||||
assert(0 <= faceIndex && faceIndex <= 6);
|
||||
switch(faceIndex)
|
||||
{
|
||||
default:
|
||||
case 0: return pos - r.x * axis[0];
|
||||
case 1: return pos + r.x * axis[0];
|
||||
case 2: return pos - r.y * axis[1];
|
||||
case 3: return pos + r.y * axis[1];
|
||||
case 4: return pos - r.z * axis[2];
|
||||
case 5: return pos + r.z * axis[2];
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 OBB::FacePoint(int faceIndex, float u, float v) const
|
||||
{
|
||||
assert(0 <= faceIndex && faceIndex <= 5);
|
||||
assert(0 <= u && u <= 1.f);
|
||||
assert(0 <= v && v <= 1.f);
|
||||
|
||||
int uIdx = faceIndex/2;
|
||||
int vIdx = (faceIndex/2 + 1) % 3;
|
||||
Vector3 U = axis[uIdx] * (2.f * u - 1.f) * r[uIdx];
|
||||
Vector3 V = axis[vIdx] * (2.f * v - 1.f) * r[vIdx];
|
||||
|
||||
switch(faceIndex)
|
||||
{
|
||||
default:
|
||||
case 0: return pos - r.z * axis[2] + U + V;
|
||||
case 1: return pos + r.z * axis[2] + U + V;
|
||||
case 2: return pos - r.x * axis[0] + U + V;
|
||||
case 3: return pos + r.x * axis[0] + U + V;
|
||||
case 4: return pos - r.y * axis[1] + U + V;
|
||||
case 5: return pos + r.y * axis[1] + U + V;
|
||||
}
|
||||
}
|
||||
|
||||
Plane OBB::FacePlane(int faceIndex) const
|
||||
{
|
||||
assert(0 <= faceIndex && faceIndex <= 5);
|
||||
switch(faceIndex)
|
||||
{
|
||||
default:
|
||||
case 0: return Plane(FaceCenterPoint(0), -axis[0]);
|
||||
case 1: return Plane(FaceCenterPoint(1), axis[0]);
|
||||
case 2: return Plane(FaceCenterPoint(2), -axis[1]);
|
||||
case 3: return Plane(FaceCenterPoint(3), axis[1]);
|
||||
case 4: return Plane(FaceCenterPoint(4), -axis[2]);
|
||||
case 5: return Plane(FaceCenterPoint(5), axis[2]);
|
||||
}
|
||||
}
|
||||
|
||||
void OBB::GetCornerPoints(Vector3 *outPointArray) const
|
||||
{
|
||||
assert(outPointArray);
|
||||
for (int i = 0; i < 8; ++i)
|
||||
outPointArray[i] = CornerPoint(i);
|
||||
}
|
||||
|
||||
void OBB::GetFacePlanes(Plane *outPlaneArray) const
|
||||
{
|
||||
assert(outPlaneArray);
|
||||
for (int i = 0; i < 6; ++i)
|
||||
outPlaneArray[i] = FacePlane(i);
|
||||
}
|
||||
|
||||
void OBB::ExtremePointsAlongDirection(const Vector3& dir, const Vector3* pointArray, int numPoints, int &idxSmallest, int &idxLargest, float &smallestD, float &largestD)
|
||||
{
|
||||
assert(pointArray || numPoints == 0);
|
||||
|
||||
idxSmallest = idxLargest = 0;
|
||||
|
||||
smallestD = INFINITY;
|
||||
largestD = -INFINITY;
|
||||
|
||||
for (int i = 0; i < numPoints; ++i)
|
||||
{
|
||||
float d = Vector3::Dot(pointArray[i], dir);
|
||||
if (d < smallestD)
|
||||
{
|
||||
smallestD = d;
|
||||
idxSmallest = i;
|
||||
}
|
||||
if (d > largestD)
|
||||
{
|
||||
largestD = d;
|
||||
idxLargest = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 OBB::Size() const {
|
||||
return r * 2.f;
|
||||
}
|
||||
|
||||
Vector3 OBB::HalfSize() const {
|
||||
return r;
|
||||
}
|
||||
|
||||
Vector3 OBB::Diagonal() const {
|
||||
return 2.f * HalfDiagonal();
|
||||
}
|
||||
|
||||
Vector3 OBB::HalfDiagonal() const {
|
||||
return axis[0] * r[0] + axis[1] * r[1] + axis[2] * r[2];
|
||||
}
|
||||
|
||||
float OBB::Volume() const {
|
||||
Vector3 size = Size();
|
||||
return size.x*size.y*size.z;
|
||||
}
|
||||
|
||||
float OBB::SurfaceArea() const {
|
||||
const Vector3 size = Size();
|
||||
|
||||
return 2.f * (size.x*size.y + size.x*size.z + size.y*size.z);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
Reference in New Issue
Block a user