13#ifndef TOYMAKERENGINE_SPATIALQUERYMATH_H
14#define TOYMAKERENGINE_SPATIALQUERYMATH_H
24 static constexpr uint8_t kMaxIterations { 32 };
25 static constexpr float kSimplexEpsilon { 0.0001 };
85 bool overlaps(
const Ray& ray,
const ObjectBounds& bounds);
99 bool overlaps(
const glm::vec3& point,
const AxisAlignedBounds& bounds);
113 bool overlaps(
const Ray& ray,
const AxisAlignedBounds& bounds);
127 bool overlaps(
const AxisAlignedBounds& one,
const AxisAlignedBounds& two);
133 bool overlaps(
const ObjectBounds& one,
const ObjectBounds& two);
139 bool overlaps(
const AxisAlignedBounds& one,
const ObjectBounds& two);
176 template <
typename T,
typename U>
177 std::pair<bool, Simplex>
gjkOverlaps(
const T& one,
const U& two);
191 template <
typename T,
typename U>
192 Polytope
buildPolytope(
const T& one,
const U& two,
const Simplex& gjkSimplex);
210 template <
typename T,
typename U>
218 bool contains(
const glm::vec3& point,
const ObjectBounds& bounds);
224 bool contains(
const glm::vec3& point,
const AxisAlignedBounds& bounds);
230 bool contains(
const Ray& ray,
const AxisAlignedBounds& bounds);
236 bool contains(
const Ray& ray,
const ObjectBounds& bounds);
242 bool contains(
const AxisAlignedBounds& one,
const AxisAlignedBounds& two);
248 bool contains(
const ObjectBounds& one,
const AxisAlignedBounds& two);
260 template<
typename T,
typename U>
262 const glm::vec3 supportOne { one.getSupportAlong(along) };
263 const glm::vec3 supportTwo { two.getSupportAlong(-along) };
264 return supportOne - supportTwo;
278 template<
typename T,
typename U>
279 inline std::tuple<glm::vec3, glm::vec3, glm::vec3>
minkowskiDifferenceFull(
const T& one,
const U& two,
const glm::vec3& along) {
280 const glm::vec3 supportOne { one.getSupportAlong(along) };
281 const glm::vec3 supportTwo { two.getSupportAlong(-along) };
282 return { supportOne - supportTwo, supportOne, supportTwo };
285 template <
typename T,
typename U>
286 inline std::pair<bool, Simplex>
gjkOverlaps(
const T& one,
const U& two) {
287 assert(one.isSensible() && two.isSensible() &&
"Invalid object bounds provided");
290 if(!one.isPositiveStrict() || !two.isPositiveStrict()) {
294 glm::vec3 searchDirection { two.getPositionWorld() - one.getPositionWorld() };
298 std::cerr <<
"Invalid overlap where 2 objects share same origin detected.\n";
304 const auto& candidatePoint { std::get<0>(fullDifference) };
305 const auto& supportA { std::get<1>(fullDifference) };
306 const auto& supportB { std::get<2>(fullDifference) };
307 simplex.
append(candidatePoint, supportA, supportB);
310 glm::vec3 toOrigin { -simplex.
mPoints[0] };
311 searchDirection = toOrigin;
312 for(uint8_t iteration { 0 };
squareDistance(toOrigin) && iteration < kMaxIterations; ++iteration) {
314 searchDirection = toOrigin;
321 if(glm::dot(candidatePoint, searchDirection) <= 0.f) {
322 return {
false, simplex };
325 simplex.
append(candidatePoint, supportA, supportB);
326 const auto result { simplex.
evaluate() };
327 toOrigin = result.second;
329 return {
true, simplex };
337 simplex.
mPoints[simplex.
mNPoints] = glm::vec3 { 2.f * kSimplexEpsilon, 0.f, 0.f };
344 const glm::vec3 dirAB { glm::normalize(simplex.
mPoints[1] - simplex.
mPoints[0]) };
345 assert(
squareDistance(dirAB) > 0 &&
"A and B should never be the same point");
346 const glm::vec3 dirOffset { (dirAB.x != 0.f || dirAB.z != 0.f)?
347 glm::vec3{ 0.f, 1.f, 0.f } : glm::vec3{ 1.f, 0.f, 1.f }
349 searchDirection = glm::normalize(-dirAB + dirOffset);
358 const glm::vec3 normABC { glm::normalize(glm::cross(simplex.
mPoints[1] - simplex.
mPoints[0], simplex.
mPoints[2] - simplex.
mPoints[0])) };
359 assert(
isNumber(normABC) &&
isFinite(normABC) &&
"Invalid norm computed, degenerate triangle detected.");
367 assert(
false &&
"Simplex with invalid number of points for this section of the algorithm provided");
372 return {
true, simplex };
376 template <
typename T,
typename U>
387 one.mType == ObjectBounds::TrueVolumeType::SPHERE
388 && two.mType == ObjectBounds::TrueVolumeType::SPHERE
394 const std::pair<bool, Simplex> overlapResult {
gjkOverlaps(one, two) };
395 if(!overlapResult.first) {
397 .mCollided {
false },
421 const glm::vec3 barycentricCoordinates {
422 barycentricSolver * closestPoint
432 const glm::mat3 barycentricOne {
435 const glm::mat3 barycentricTwo {
438 collisionResult.
mContactA.
mPoint = barycentricOne * barycentricCoordinates;
441 &&
"Invalid contact point computed for object A"
443 collisionResult.
mContactB.
mPoint = barycentricTwo * barycentricCoordinates;
446 &&
"Invalid contact point computed for object B"
450 const auto contactNormal {
451 squareDistance(closestPoint)? closestPoint: one.getPositionWorld() - two.getPositionWorld()
453 const auto tangentPair {
getTangents(contactNormal) };
464 = glm::length(closestPoint);
466 return collisionResult;
469 template <
typename T,
typename U>
473 assert(
squareDistance(searchDirection) > 0 &&
"Search direction should always be non-zero");
474 assert(
isFinite(searchDirection) &&
"Search direction should always be finite");
477 std::tuple<glm::vec3, glm::vec3, glm::vec3> differenceFull {
minkowskiDifferenceFull(one, two, searchDirection) };
481 const glm::vec3& supportA { std::get<1>(differenceFull) };
482 const glm::vec3& supportB { std::get<2>(differenceFull) };
483 const glm::vec3& difference { std::get<0>(differenceFull) };
486 uint8_t iterationsLeft { kMaxIterations };
487 while(polytope.
append(difference, supportA, supportB) && iterationsLeft--) {
An object containing a coarse simplified representation, AABB, of spatially queryable objects.
Definition types.hpp:1322
Primitive for EPA algorithm.
Definition types.hpp:636
AreaTriangle getClosestTriangle() const
Returns the closest polytope triangle.
Definition types.cpp:105
AreaTriangle getClosestTriangleSupportB() const
Gets the points of shape B that were responsible for generating the closest triangle of the polytope.
Definition types.cpp:123
bool append(const glm::vec3 &newPoint, const glm::vec3 &supportA, const glm::vec3 &supportB)
Appends a new point, replacing the topmost triangle in the polygon with 3 more triangles including th...
Definition types.cpp:155
glm::vec3 getClosestPoint() const
Returns the closest point to the origin on the triangle face closest to the origin.
Definition types.cpp:91
AreaTriangle getClosestTriangleSupportA() const
Gets the points of shape A that were responsible for generating the closest triangle of the polytope.
Definition types.cpp:114
glm::vec3 getNextSearch() const
Returns the next search direction for a point to add to the polytope.
Definition types.cpp:80
bool isNumber(float number)
Tests whether a float is really a number (as opposed to a special error representation).
Definition util.hpp:92
float squareDistance(const glm::vec3 &vector)
Returns the square of the length of a 3 component vector.
Definition util.hpp:35
bool isFinite(float number)
Tests whether a given number is finite.
Definition util.hpp:47
bool isSensible(const glm::mat3 &matrix)
Determines whether a particular matrix is valid and finite.
Definition math.cpp:775
bool contains(const glm::vec3 &point, const ObjectBounds &bounds)
Returns whether point is contained by bounds.
Definition math.cpp:291
std::pair< bool, glm::vec3 > computeIntersection(const Ray &ray, const Plane &plane)
Returns a bool-vector pair, with bool indicating whether a point of intersection was found,...
Definition math.cpp:45
glm::vec3 minkowskiDifference(const T &one, const U &two, const glm::vec3 &along)
Closely associated with GJK; finds the Minkowski difference between two shapes situated somewhere in ...
Definition math.hpp:261
std::pair< glm::vec3, glm::vec3 > getTangents(const glm::vec3 &vector)
Returns a pair of normalized tangents to an input vector.
Definition util.cpp:121
std::pair< uint8_t, std::pair< glm::vec3, glm::vec3 > > computeIntersections(const Ray &ray, const AxisAlignedBounds &axisAlignedBounds)
Returns an unsigned int and vector-pair pair, with unsigned indicating whether any and how many point...
Definition math.cpp:128
bool overlaps(const glm::vec3 &point, const ObjectBounds &bounds)
Returns a bool value indicating whether point is contained by bounds.
Definition math.cpp:170
glm::mat3 computeBarycentricSolver(const AreaTriangle &triangle)
Computes a Barycentric solver matrix based on an input triangle.
Definition math.cpp:780
Collision checkCollisionSphereSphere(const ObjectBounds &one, const ObjectBounds &two)
Specialization of checkCollision() where both objects being tested are spheres.
Definition math.cpp:827
std::tuple< glm::vec3, glm::vec3, glm::vec3 > minkowskiDifferenceFull(const T &one, const U &two, const glm::vec3 &along)
Closely associated with GJK; finds the Minkowski difference between two shapes situated somewhere in ...
Definition math.hpp:279
Namespace containing all class definitions and functions related to the ToyMaker engine.
Definition application.hpp:25
std::pair< bool, Simplex > gjkOverlaps(const T &one, const U &two)
GJK implementation based on Casey Muratori's video lecture, which is available here.
Definition math.hpp:286
Collision checkCollision(const T &one, const U &two)
Checks whether a pair of convex 3D shapes are colliding, returning information about the collision if...
Definition math.hpp:377
Polytope buildPolytope(const T &one, const U &two, const Simplex &gjkSimplex)
EPA implementation, used to derive contact information for intersections between convex shapes.
Definition math.hpp:470
Classes and structs representing data related to the engine's spatial query system (the precursor to ...
A set of 3 points located in the world forming a (hopefully sensible) triangle.
Definition types.hpp:327
std::array< glm::vec3, 3 > mPoints
The points of the triangle, where each point has 3 components.
Definition types.hpp:332
Data representing everything about a collision.
Definition types.hpp:816
Contact mContactA
Contact information relative to the first collision shape.
Definition types.hpp:827
Contact mContactB
Contact information relative to the second collision shape.
Definition types.hpp:833
A component defining the true bounds of a spatially queryable object situated somewhere in the world.
Definition types.hpp:845
A set of numbers describing a plane situated somewhere in the world.
Definition types.hpp:500
A set of numbers describing a ray with its source at some finite point in the world,...
Definition types.hpp:447
Primitive for GJK algorithm.
Definition types.hpp:549
std::array< glm::vec3, 4 > mPointsSupportA
The point on the LHS of the Minkowski difference, where each index corresponds to a point on mPoints.
Definition types.hpp:561
std::array< glm::vec3, 4 > mPointsSupportB
The point on the RHS of the Minkowski difference, where each index corresponds to a point on mPoints.
Definition types.hpp:567
std::pair< bool, glm::vec3 > evaluate()
Tries to find a 3-simplex that encloses the origin.
Definition types.cpp:665
bool append(const glm::vec3 &candidatePoint, const glm::vec3 &supportA, const glm::vec3 &supportB)
Adds a new point to the simplex.
Definition types.hpp:581
uint8_t mNPoints
The number of points in this simplex.
Definition types.hpp:573
std::array< glm::vec3, 4 > mPoints
Points representing the simplex, derived by finding the Minksowski difference of support points on tw...
Definition types.hpp:555
Contains a couple of classes not tied to any part of the engine in particular, but useful to those pa...