Make GJK/EPA collision detection more robust
This commit is contained in:
parent
ccd33c2502
commit
4bad013c91
|
@ -303,4 +303,4 @@ inline Vector3 CollisionBody::getLocalVector(const Vector3& worldVector) const {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -35,9 +35,9 @@
|
||||||
#include "memory/MemoryAllocator.h"
|
#include "memory/MemoryAllocator.h"
|
||||||
#include "constraint/ContactPoint.h"
|
#include "constraint/ContactPoint.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
/// ReactPhysics3D namespace
|
/// ReactPhysics3D namespace
|
||||||
namespace reactphysics3d {
|
namespace reactphysics3d {
|
||||||
|
|
|
@ -81,8 +81,9 @@ int EPAAlgorithm::isOriginInTetrahedron(const Vector3& p1, const Vector3& p2,
|
||||||
/// enlarged objects (with margin) where the original objects (without margin)
|
/// enlarged objects (with margin) where the original objects (without margin)
|
||||||
/// intersect. An initial simplex that contains origin has been computed with
|
/// intersect. An initial simplex that contains origin has been computed with
|
||||||
/// GJK algorithm. The EPA Algorithm will extend this simplex polytope to find
|
/// GJK algorithm. The EPA Algorithm will extend this simplex polytope to find
|
||||||
/// the correct penetration depth
|
/// the correct penetration depth. This method returns true if the EPA penetration
|
||||||
void EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simplex,
|
/// depth computation has succeeded and false it has failed.
|
||||||
|
bool EPAAlgorithm::computePenetrationDepthAndContactPoints(const VoronoiSimplex& simplex,
|
||||||
CollisionShapeInfo shape1Info,
|
CollisionShapeInfo shape1Info,
|
||||||
const Transform& transform1,
|
const Transform& transform1,
|
||||||
CollisionShapeInfo shape2Info,
|
CollisionShapeInfo shape2Info,
|
||||||
|
@ -92,6 +93,8 @@ void EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple
|
||||||
|
|
||||||
PROFILE("EPAAlgorithm::computePenetrationDepthAndContactPoints()");
|
PROFILE("EPAAlgorithm::computePenetrationDepthAndContactPoints()");
|
||||||
|
|
||||||
|
decimal gjkPenDepthSquare = v.lengthSquare();
|
||||||
|
|
||||||
assert(shape1Info.collisionShape->isConvex());
|
assert(shape1Info.collisionShape->isConvex());
|
||||||
assert(shape2Info.collisionShape->isConvex());
|
assert(shape2Info.collisionShape->isConvex());
|
||||||
|
|
||||||
|
@ -118,7 +121,7 @@ void EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple
|
||||||
transform1.getOrientation();
|
transform1.getOrientation();
|
||||||
|
|
||||||
// Get the simplex computed previously by the GJK algorithm
|
// Get the simplex computed previously by the GJK algorithm
|
||||||
unsigned int nbVertices = simplex.getSimplex(suppPointsA, suppPointsB, points);
|
int nbVertices = simplex.getSimplex(suppPointsA, suppPointsB, points);
|
||||||
|
|
||||||
// Compute the tolerance
|
// Compute the tolerance
|
||||||
decimal tolerance = MACHINE_EPSILON * simplex.getMaxLengthSquareOfAPoint();
|
decimal tolerance = MACHINE_EPSILON * simplex.getMaxLengthSquareOfAPoint();
|
||||||
|
@ -137,7 +140,7 @@ void EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple
|
||||||
// Only one point in the simplex (which should be the origin).
|
// Only one point in the simplex (which should be the origin).
|
||||||
// We have a touching contact with zero penetration depth.
|
// We have a touching contact with zero penetration depth.
|
||||||
// We drop that kind of contact. Therefore, we return false
|
// We drop that kind of contact. Therefore, we return false
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
case 2: {
|
case 2: {
|
||||||
// The simplex returned by GJK is a line segment d containing the origin.
|
// The simplex returned by GJK is a line segment d containing the origin.
|
||||||
|
@ -204,7 +207,7 @@ void EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// The origin is not in the initial polytope
|
// The origin is not in the initial polytope
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The polytope contains now 4 vertices
|
// The polytope contains now 4 vertices
|
||||||
|
@ -234,7 +237,7 @@ void EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple
|
||||||
if (!((face0 != NULL) && (face1 != NULL) && (face2 != NULL) && (face3 != NULL)
|
if (!((face0 != NULL) && (face1 != NULL) && (face2 != NULL) && (face3 != NULL)
|
||||||
&& face0->getDistSquare() > 0.0 && face1->getDistSquare() > 0.0
|
&& face0->getDistSquare() > 0.0 && face1->getDistSquare() > 0.0
|
||||||
&& face2->getDistSquare() > 0.0 && face3->getDistSquare() > 0.0)) {
|
&& face2->getDistSquare() > 0.0 && face3->getDistSquare() > 0.0)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Associate the edges of neighbouring triangle faces
|
// Associate the edges of neighbouring triangle faces
|
||||||
|
@ -319,14 +322,14 @@ void EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple
|
||||||
face3 = triangleStore.newTriangle(points, 1, 4, 2);
|
face3 = triangleStore.newTriangle(points, 1, 4, 2);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the constructed tetrahedron is not correct
|
// If the constructed tetrahedron is not correct
|
||||||
if (!((face0 != NULL) && (face1 != NULL) && (face2 != NULL) && (face3 != NULL)
|
if (!((face0 != NULL) && (face1 != NULL) && (face2 != NULL) && (face3 != NULL)
|
||||||
&& face0->getDistSquare() > 0.0 && face1->getDistSquare() > 0.0
|
&& face0->getDistSquare() > 0.0 && face1->getDistSquare() > 0.0
|
||||||
&& face2->getDistSquare() > 0.0 && face3->getDistSquare() > 0.0)) {
|
&& face2->getDistSquare() > 0.0 && face3->getDistSquare() > 0.0)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Associate the edges of neighbouring triangle faces
|
// Associate the edges of neighbouring triangle faces
|
||||||
|
@ -353,7 +356,7 @@ void EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple
|
||||||
// can run the EPA algorithm.
|
// can run the EPA algorithm.
|
||||||
|
|
||||||
if (nbTriangles == 0) {
|
if (nbTriangles == 0) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TriangleEPA* triangle = 0;
|
TriangleEPA* triangle = 0;
|
||||||
|
@ -368,6 +371,7 @@ void EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple
|
||||||
|
|
||||||
// If the candidate face in the heap is not obsolete
|
// If the candidate face in the heap is not obsolete
|
||||||
if (!triangle->getIsObsolete()) {
|
if (!triangle->getIsObsolete()) {
|
||||||
|
|
||||||
// If we have reached the maximum number of support points
|
// If we have reached the maximum number of support points
|
||||||
if (nbVertices == MAX_SUPPORT_POINTS) {
|
if (nbVertices == MAX_SUPPORT_POINTS) {
|
||||||
assert(false);
|
assert(false);
|
||||||
|
@ -388,7 +392,7 @@ void EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple
|
||||||
|
|
||||||
// Update the upper bound of the penetration depth
|
// Update the upper bound of the penetration depth
|
||||||
decimal wDotv = points[indexNewVertex].dot(triangle->getClosestPoint());
|
decimal wDotv = points[indexNewVertex].dot(triangle->getClosestPoint());
|
||||||
assert(wDotv > 0.0);
|
|
||||||
decimal wDotVSquare = wDotv * wDotv / triangle->getDistSquare();
|
decimal wDotVSquare = wDotv * wDotv / triangle->getDistSquare();
|
||||||
if (wDotVSquare < upperBoundSquarePenDepth) {
|
if (wDotVSquare < upperBoundSquarePenDepth) {
|
||||||
upperBoundSquarePenDepth = wDotVSquare;
|
upperBoundSquarePenDepth = wDotVSquare;
|
||||||
|
@ -427,13 +431,22 @@ void EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simple
|
||||||
Vector3 pBLocal = body2Tobody1.getInverse() * triangle->computeClosestPointOfObject(suppPointsB);
|
Vector3 pBLocal = body2Tobody1.getInverse() * triangle->computeClosestPointOfObject(suppPointsB);
|
||||||
Vector3 normal = v.getUnit();
|
Vector3 normal = v.getUnit();
|
||||||
decimal penetrationDepth = v.length();
|
decimal penetrationDepth = v.length();
|
||||||
assert(penetrationDepth > 0.0);
|
|
||||||
|
|
||||||
if (normal.lengthSquare() < MACHINE_EPSILON) return;
|
// If the length of the normal vector is too small, skip this contact point
|
||||||
|
if (normal.lengthSquare() < MACHINE_EPSILON) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Create the contact info object
|
if (penetrationDepth * penetrationDepth > gjkPenDepthSquare && penetrationDepth > 0) {
|
||||||
ContactPointInfo contactInfo(shape1Info.proxyShape, shape2Info.proxyShape, shape1Info.collisionShape,
|
|
||||||
shape2Info.collisionShape, normal, penetrationDepth, pALocal, pBLocal);
|
|
||||||
|
|
||||||
narrowPhaseCallback->notifyContact(shape1Info.overlappingPair, contactInfo);
|
// Create the contact info object
|
||||||
|
ContactPointInfo contactInfo(shape1Info.proxyShape, shape2Info.proxyShape, shape1Info.collisionShape,
|
||||||
|
shape2Info.collisionShape, normal, penetrationDepth, pALocal, pBLocal);
|
||||||
|
|
||||||
|
narrowPhaseCallback->notifyContact(shape1Info.overlappingPair, contactInfo);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
#define REACTPHYSICS3D_EPA_ALGORITHM_H
|
#define REACTPHYSICS3D_EPA_ALGORITHM_H
|
||||||
|
|
||||||
// Libraries
|
// Libraries
|
||||||
#include "collision/narrowphase/GJK/Simplex.h"
|
#include "collision/narrowphase/GJK/VoronoiSimplex.h"
|
||||||
#include "collision/shapes/CollisionShape.h"
|
#include "collision/shapes/CollisionShape.h"
|
||||||
#include "collision/CollisionShapeInfo.h"
|
#include "collision/CollisionShapeInfo.h"
|
||||||
#include "constraint/ContactPoint.h"
|
#include "constraint/ContactPoint.h"
|
||||||
|
@ -123,13 +123,13 @@ class EPAAlgorithm {
|
||||||
void init(MemoryAllocator* memoryAllocator);
|
void init(MemoryAllocator* memoryAllocator);
|
||||||
|
|
||||||
/// Compute the penetration depth with EPA algorithm.
|
/// Compute the penetration depth with EPA algorithm.
|
||||||
void computePenetrationDepthAndContactPoints(const Simplex& simplex,
|
bool computePenetrationDepthAndContactPoints(const VoronoiSimplex& simplex,
|
||||||
CollisionShapeInfo shape1Info,
|
CollisionShapeInfo shape1Info,
|
||||||
const Transform& transform1,
|
const Transform& transform1,
|
||||||
CollisionShapeInfo shape2Info,
|
CollisionShapeInfo shape2Info,
|
||||||
const Transform& transform2,
|
const Transform& transform2,
|
||||||
Vector3& v,
|
Vector3& v,
|
||||||
NarrowPhaseCallback* narrowPhaseCallback);
|
NarrowPhaseCallback* narrowPhaseCallback);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add a triangle face in the candidate triangle heap in the EPA algorithm
|
// Add a triangle face in the candidate triangle heap in the EPA algorithm
|
||||||
|
|
|
@ -69,6 +69,7 @@ void GJKAlgorithm::testCollision(const CollisionShapeInfo& shape1Info,
|
||||||
Vector3 pB; // Closest point of object B
|
Vector3 pB; // Closest point of object B
|
||||||
decimal vDotw;
|
decimal vDotw;
|
||||||
decimal prevDistSquare;
|
decimal prevDistSquare;
|
||||||
|
bool contactFound = false;
|
||||||
|
|
||||||
assert(shape1Info.collisionShape->isConvex());
|
assert(shape1Info.collisionShape->isConvex());
|
||||||
assert(shape2Info.collisionShape->isConvex());
|
assert(shape2Info.collisionShape->isConvex());
|
||||||
|
@ -79,6 +80,8 @@ void GJKAlgorithm::testCollision(const CollisionShapeInfo& shape1Info,
|
||||||
void** shape1CachedCollisionData = shape1Info.cachedCollisionData;
|
void** shape1CachedCollisionData = shape1Info.cachedCollisionData;
|
||||||
void** shape2CachedCollisionData = shape2Info.cachedCollisionData;
|
void** shape2CachedCollisionData = shape2Info.cachedCollisionData;
|
||||||
|
|
||||||
|
bool isPolytopeShape = shape1->isPolyhedron() && shape2->isPolyhedron();
|
||||||
|
|
||||||
// Get the local-space to world-space transforms
|
// Get the local-space to world-space transforms
|
||||||
const Transform transform1 = shape1Info.shapeToWorldTransform;
|
const Transform transform1 = shape1Info.shapeToWorldTransform;
|
||||||
const Transform transform2 = shape2Info.shapeToWorldTransform;
|
const Transform transform2 = shape2Info.shapeToWorldTransform;
|
||||||
|
@ -98,7 +101,7 @@ void GJKAlgorithm::testCollision(const CollisionShapeInfo& shape1Info,
|
||||||
assert(margin > 0.0);
|
assert(margin > 0.0);
|
||||||
|
|
||||||
// Create a simplex set
|
// Create a simplex set
|
||||||
Simplex simplex;
|
VoronoiSimplex simplex;
|
||||||
|
|
||||||
// Get the previous point V (last cached separating axis)
|
// Get the previous point V (last cached separating axis)
|
||||||
Vector3 v = mCurrentOverlappingPair->getCachedSeparatingAxis();
|
Vector3 v = mCurrentOverlappingPair->getCachedSeparatingAxis();
|
||||||
|
@ -131,31 +134,9 @@ void GJKAlgorithm::testCollision(const CollisionShapeInfo& shape1Info,
|
||||||
// If the objects intersect only in the margins
|
// If the objects intersect only in the margins
|
||||||
if (simplex.isPointInSimplex(w) || distSquare - vDotw <= distSquare * REL_ERROR_SQUARE) {
|
if (simplex.isPointInSimplex(w) || distSquare - vDotw <= distSquare * REL_ERROR_SQUARE) {
|
||||||
|
|
||||||
// Compute the closet points of both objects (without the margins)
|
// Contact point has been found
|
||||||
simplex.computeClosestPointsOfAandB(pA, pB);
|
contactFound = true;
|
||||||
|
break;
|
||||||
// Project those two points on the margins to have the closest points of both
|
|
||||||
// object with the margins
|
|
||||||
decimal dist = sqrt(distSquare);
|
|
||||||
assert(dist > 0.0);
|
|
||||||
pA = (pA - (shape1->getMargin() / dist) * v);
|
|
||||||
pB = body2Tobody1.getInverse() * (pB + (shape2->getMargin() / dist) * v);
|
|
||||||
|
|
||||||
// Compute the contact info
|
|
||||||
Vector3 normal = transform1.getOrientation() * (-v.getUnit());
|
|
||||||
decimal penetrationDepth = margin - dist;
|
|
||||||
|
|
||||||
// Reject the contact if the penetration depth is negative (due too numerical errors)
|
|
||||||
if (penetrationDepth <= 0.0) return;
|
|
||||||
|
|
||||||
// Create the contact info object
|
|
||||||
ContactPointInfo contactInfo(shape1Info.proxyShape, shape2Info.proxyShape, shape1Info.collisionShape,
|
|
||||||
shape2Info.collisionShape, normal, penetrationDepth, pA, pB);
|
|
||||||
|
|
||||||
narrowPhaseCallback->notifyContact(shape1Info.overlappingPair, contactInfo);
|
|
||||||
|
|
||||||
// There is an intersection, therefore we return
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the new support point to the simplex
|
// Add the new support point to the simplex
|
||||||
|
@ -164,62 +145,24 @@ void GJKAlgorithm::testCollision(const CollisionShapeInfo& shape1Info,
|
||||||
// If the simplex is affinely dependent
|
// If the simplex is affinely dependent
|
||||||
if (simplex.isAffinelyDependent()) {
|
if (simplex.isAffinelyDependent()) {
|
||||||
|
|
||||||
// Compute the closet points of both objects (without the margins)
|
// Contact point has been found
|
||||||
simplex.computeClosestPointsOfAandB(pA, pB);
|
contactFound = true;
|
||||||
|
break;
|
||||||
// Project those two points on the margins to have the closest points of both
|
|
||||||
// object with the margins
|
|
||||||
decimal dist = sqrt(distSquare);
|
|
||||||
assert(dist > 0.0);
|
|
||||||
pA = (pA - (shape1->getMargin() / dist) * v);
|
|
||||||
pB = body2Tobody1.getInverse() * (pB + (shape2->getMargin() / dist) * v);
|
|
||||||
|
|
||||||
// Compute the contact info
|
|
||||||
Vector3 normal = transform1.getOrientation() * (-v.getUnit());
|
|
||||||
decimal penetrationDepth = margin - dist;
|
|
||||||
|
|
||||||
// Reject the contact if the penetration depth is negative (due too numerical errors)
|
|
||||||
if (penetrationDepth <= 0.0) return;
|
|
||||||
|
|
||||||
// Create the contact info object
|
|
||||||
ContactPointInfo contactInfo(shape1Info.proxyShape, shape2Info.proxyShape, shape1Info.collisionShape,
|
|
||||||
shape2Info.collisionShape, normal, penetrationDepth, pA, pB);
|
|
||||||
|
|
||||||
narrowPhaseCallback->notifyContact(shape1Info.overlappingPair, contactInfo);
|
|
||||||
|
|
||||||
// There is an intersection, therefore we return
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the point of the simplex closest to the origin
|
// Compute the point of the simplex closest to the origin
|
||||||
// If the computation of the closest point fail
|
// If the computation of the closest point fails
|
||||||
if (!simplex.computeClosestPoint(v)) {
|
if (!simplex.computeClosestPoint(v)) {
|
||||||
|
|
||||||
// Compute the closet points of both objects (without the margins)
|
// Contact point has been found
|
||||||
simplex.computeClosestPointsOfAandB(pA, pB);
|
contactFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Project those two points on the margins to have the closest points of both
|
// Closest point is almost the origin, go to EPA algorithm
|
||||||
// object with the margins
|
// Vector v to small to continue computing support points
|
||||||
decimal dist = sqrt(distSquare);
|
if (v.lengthSquare() < MACHINE_EPSILON) {
|
||||||
assert(dist > 0.0);
|
break;
|
||||||
pA = (pA - (shape1->getMargin() / dist) * v);
|
|
||||||
pB = body2Tobody1.getInverse() * (pB + (shape2->getMargin() / dist) * v);
|
|
||||||
|
|
||||||
// Compute the contact info
|
|
||||||
Vector3 normal = transform1.getOrientation() * (-v.getUnit());
|
|
||||||
decimal penetrationDepth = margin - dist;
|
|
||||||
|
|
||||||
// Reject the contact if the penetration depth is negative (due too numerical errors)
|
|
||||||
if (penetrationDepth <= 0.0) return;
|
|
||||||
|
|
||||||
// Create the contact info object
|
|
||||||
ContactPointInfo contactInfo(shape1Info.proxyShape, shape2Info.proxyShape, shape1Info.collisionShape,
|
|
||||||
shape2Info.collisionShape, normal, penetrationDepth, pA, pB);
|
|
||||||
|
|
||||||
narrowPhaseCallback->notifyContact(shape1Info.overlappingPair, contactInfo);
|
|
||||||
|
|
||||||
// There is an intersection, therefore we return
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store and update the squared distance of the closest point
|
// Store and update the squared distance of the closest point
|
||||||
|
@ -228,46 +171,65 @@ void GJKAlgorithm::testCollision(const CollisionShapeInfo& shape1Info,
|
||||||
|
|
||||||
// If the distance to the closest point doesn't improve a lot
|
// If the distance to the closest point doesn't improve a lot
|
||||||
if (prevDistSquare - distSquare <= MACHINE_EPSILON * prevDistSquare) {
|
if (prevDistSquare - distSquare <= MACHINE_EPSILON * prevDistSquare) {
|
||||||
|
|
||||||
simplex.backupClosestPointInSimplex(v);
|
simplex.backupClosestPointInSimplex(v);
|
||||||
|
|
||||||
// Get the new squared distance
|
// Get the new squared distance
|
||||||
distSquare = v.lengthSquare();
|
distSquare = v.lengthSquare();
|
||||||
|
|
||||||
// Compute the closet points of both objects (without the margins)
|
// Contact point has been found
|
||||||
simplex.computeClosestPointsOfAandB(pA, pB);
|
contactFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Project those two points on the margins to have the closest points of both
|
} while((isPolytopeShape && !simplex.isFull()) || (!isPolytopeShape && !simplex.isFull() &&
|
||||||
// object with the margins
|
distSquare > MACHINE_EPSILON * simplex.getMaxLengthSquareOfAPoint()));
|
||||||
decimal dist = sqrt(distSquare);
|
|
||||||
assert(dist > 0.0);
|
|
||||||
pA = (pA - (shape1->getMargin() / dist) * v);
|
|
||||||
pB = body2Tobody1.getInverse() * (pB + (shape2->getMargin() / dist) * v);
|
|
||||||
|
|
||||||
// Compute the contact info
|
bool isEPAResultValid = false;
|
||||||
Vector3 normal = transform1.getOrientation() * (-v.getUnit());
|
|
||||||
decimal penetrationDepth = margin - dist;
|
|
||||||
|
|
||||||
// Reject the contact if the penetration depth is negative (due too numerical errors)
|
// If no contact has been found (penetration case)
|
||||||
if (penetrationDepth <= 0.0) return;
|
if (!contactFound) {
|
||||||
|
|
||||||
// Create the contact info object
|
// The objects (without margins) intersect. Therefore, we run the GJK algorithm
|
||||||
ContactPointInfo contactInfo(shape1Info.proxyShape, shape2Info.proxyShape, shape1Info.collisionShape,
|
// again but on the enlarged objects to compute a simplex polytope that contains
|
||||||
shape2Info.collisionShape, normal, penetrationDepth, pA, pB);
|
// the origin. Then, we give that simplex polytope to the EPA algorithm to compute
|
||||||
|
// the correct penetration depth and contact points between the enlarged objects.
|
||||||
|
isEPAResultValid = computePenetrationDepthForEnlargedObjects(shape1Info, transform1, shape2Info,
|
||||||
|
transform2, narrowPhaseCallback, v);
|
||||||
|
}
|
||||||
|
|
||||||
narrowPhaseCallback->notifyContact(shape1Info.overlappingPair, contactInfo);
|
if ((contactFound || !isEPAResultValid) && distSquare > MACHINE_EPSILON) {
|
||||||
|
|
||||||
// There is an intersection, therefore we return
|
// Compute the closet points of both objects (without the margins)
|
||||||
|
simplex.computeClosestPointsOfAandB(pA, pB);
|
||||||
|
|
||||||
|
// Project those two points on the margins to have the closest points of both
|
||||||
|
// object with the margins
|
||||||
|
decimal dist = std::sqrt(distSquare);
|
||||||
|
assert(dist > 0.0);
|
||||||
|
pA = (pA - (shape1->getMargin() / dist) * v);
|
||||||
|
pB = body2Tobody1.getInverse() * (pB + (shape2->getMargin() / dist) * v);
|
||||||
|
|
||||||
|
// Compute the contact info
|
||||||
|
Vector3 normal = transform1.getOrientation() * (-v.getUnit());
|
||||||
|
decimal penetrationDepth = margin - dist;
|
||||||
|
|
||||||
|
// If the penetration depth is negative (due too numerical errors), there is no contact
|
||||||
|
if (penetrationDepth <= 0.0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} while(!simplex.isFull() && distSquare > MACHINE_EPSILON *
|
|
||||||
simplex.getMaxLengthSquareOfAPoint());
|
|
||||||
|
|
||||||
// The objects (without margins) intersect. Therefore, we run the GJK algorithm
|
// Do not generate a contact point with zero normal length
|
||||||
// again but on the enlarged objects to compute a simplex polytope that contains
|
if (normal.lengthSquare() < MACHINE_EPSILON) {
|
||||||
// the origin. Then, we give that simplex polytope to the EPA algorithm to compute
|
return;
|
||||||
// the correct penetration depth and contact points between the enlarged objects.
|
}
|
||||||
return computePenetrationDepthForEnlargedObjects(shape1Info, transform1, shape2Info,
|
|
||||||
transform2, narrowPhaseCallback, v);
|
// Create the contact info object
|
||||||
|
ContactPointInfo contactInfo(shape1Info.proxyShape, shape2Info.proxyShape, shape1Info.collisionShape,
|
||||||
|
shape2Info.collisionShape, normal, penetrationDepth, pA, pB);
|
||||||
|
|
||||||
|
narrowPhaseCallback->notifyContact(shape1Info.overlappingPair, contactInfo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This method runs the GJK algorithm on the two enlarged objects (with margin)
|
/// This method runs the GJK algorithm on the two enlarged objects (with margin)
|
||||||
|
@ -275,7 +237,7 @@ void GJKAlgorithm::testCollision(const CollisionShapeInfo& shape1Info,
|
||||||
/// assumed to intersect in the original objects (without margin). Therefore such
|
/// assumed to intersect in the original objects (without margin). Therefore such
|
||||||
/// a polytope must exist. Then, we give that polytope to the EPA algorithm to
|
/// a polytope must exist. Then, we give that polytope to the EPA algorithm to
|
||||||
/// compute the correct penetration depth and contact points of the enlarged objects.
|
/// compute the correct penetration depth and contact points of the enlarged objects.
|
||||||
void GJKAlgorithm::computePenetrationDepthForEnlargedObjects(const CollisionShapeInfo& shape1Info,
|
bool GJKAlgorithm::computePenetrationDepthForEnlargedObjects(const CollisionShapeInfo& shape1Info,
|
||||||
const Transform& transform1,
|
const Transform& transform1,
|
||||||
const CollisionShapeInfo& shape2Info,
|
const CollisionShapeInfo& shape2Info,
|
||||||
const Transform& transform2,
|
const Transform& transform2,
|
||||||
|
@ -283,7 +245,7 @@ void GJKAlgorithm::computePenetrationDepthForEnlargedObjects(const CollisionShap
|
||||||
Vector3& v) {
|
Vector3& v) {
|
||||||
PROFILE("GJKAlgorithm::computePenetrationDepthForEnlargedObjects()");
|
PROFILE("GJKAlgorithm::computePenetrationDepthForEnlargedObjects()");
|
||||||
|
|
||||||
Simplex simplex;
|
VoronoiSimplex simplex;
|
||||||
Vector3 suppA;
|
Vector3 suppA;
|
||||||
Vector3 suppB;
|
Vector3 suppB;
|
||||||
Vector3 w;
|
Vector3 w;
|
||||||
|
@ -297,6 +259,8 @@ void GJKAlgorithm::computePenetrationDepthForEnlargedObjects(const CollisionShap
|
||||||
const ConvexShape* shape1 = static_cast<const ConvexShape*>(shape1Info.collisionShape);
|
const ConvexShape* shape1 = static_cast<const ConvexShape*>(shape1Info.collisionShape);
|
||||||
const ConvexShape* shape2 = static_cast<const ConvexShape*>(shape2Info.collisionShape);
|
const ConvexShape* shape2 = static_cast<const ConvexShape*>(shape2Info.collisionShape);
|
||||||
|
|
||||||
|
bool isPolytopeShape = shape1->isPolyhedron() && shape2->isPolyhedron();
|
||||||
|
|
||||||
void** shape1CachedCollisionData = shape1Info.cachedCollisionData;
|
void** shape1CachedCollisionData = shape1Info.cachedCollisionData;
|
||||||
void** shape2CachedCollisionData = shape2Info.cachedCollisionData;
|
void** shape2CachedCollisionData = shape2Info.cachedCollisionData;
|
||||||
|
|
||||||
|
@ -322,18 +286,18 @@ void GJKAlgorithm::computePenetrationDepthForEnlargedObjects(const CollisionShap
|
||||||
if (vDotw > 0.0) {
|
if (vDotw > 0.0) {
|
||||||
|
|
||||||
// No intersection, we return
|
// No intersection, we return
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the new support point to the simplex
|
// Add the new support point to the simplex
|
||||||
simplex.addPoint(w, suppA, suppB);
|
simplex.addPoint(w, suppA, suppB);
|
||||||
|
|
||||||
if (simplex.isAffinelyDependent()) {
|
if (simplex.isAffinelyDependent()) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!simplex.computeClosestPoint(v)) {
|
if (!simplex.computeClosestPoint(v)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store and update the square distance
|
// Store and update the square distance
|
||||||
|
@ -341,11 +305,11 @@ void GJKAlgorithm::computePenetrationDepthForEnlargedObjects(const CollisionShap
|
||||||
distSquare = v.lengthSquare();
|
distSquare = v.lengthSquare();
|
||||||
|
|
||||||
if (prevDistSquare - distSquare <= MACHINE_EPSILON * prevDistSquare) {
|
if (prevDistSquare - distSquare <= MACHINE_EPSILON * prevDistSquare) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} while(!simplex.isFull() && distSquare > MACHINE_EPSILON *
|
} while((!simplex.isFull() && isPolytopeShape) || (!isPolytopeShape && !simplex.isFull() &&
|
||||||
simplex.getMaxLengthSquareOfAPoint());
|
distSquare > MACHINE_EPSILON * simplex.getMaxLengthSquareOfAPoint()));
|
||||||
|
|
||||||
// Give the simplex computed with GJK algorithm to the EPA algorithm
|
// Give the simplex computed with GJK algorithm to the EPA algorithm
|
||||||
// which will compute the correct penetration depth and contact points
|
// which will compute the correct penetration depth and contact points
|
||||||
|
@ -372,7 +336,7 @@ bool GJKAlgorithm::testPointInside(const Vector3& localPoint, ProxyShape* proxyS
|
||||||
const Vector3 suppB(localPoint);
|
const Vector3 suppB(localPoint);
|
||||||
|
|
||||||
// Create a simplex set
|
// Create a simplex set
|
||||||
Simplex simplex;
|
VoronoiSimplex simplex;
|
||||||
|
|
||||||
// Initial supporting direction
|
// Initial supporting direction
|
||||||
Vector3 v(1, 1, 1);
|
Vector3 v(1, 1, 1);
|
||||||
|
@ -446,7 +410,7 @@ bool GJKAlgorithm::raycast(const Ray& ray, ProxyShape* proxyShape, RaycastInfo&
|
||||||
Vector3 w;
|
Vector3 w;
|
||||||
|
|
||||||
// Create a simplex set
|
// Create a simplex set
|
||||||
Simplex simplex;
|
VoronoiSimplex simplex;
|
||||||
|
|
||||||
Vector3 n(decimal(0.0), decimal(0.0), decimal(0.0));
|
Vector3 n(decimal(0.0), decimal(0.0), decimal(0.0));
|
||||||
decimal lambda = decimal(0.0);
|
decimal lambda = decimal(0.0);
|
||||||
|
|
|
@ -75,7 +75,7 @@ class GJKAlgorithm : public NarrowPhaseAlgorithm {
|
||||||
GJKAlgorithm& operator=(const GJKAlgorithm& algorithm);
|
GJKAlgorithm& operator=(const GJKAlgorithm& algorithm);
|
||||||
|
|
||||||
/// Compute the penetration depth for enlarged objects.
|
/// Compute the penetration depth for enlarged objects.
|
||||||
void computePenetrationDepthForEnlargedObjects(const CollisionShapeInfo& shape1Info,
|
bool computePenetrationDepthForEnlargedObjects(const CollisionShapeInfo& shape1Info,
|
||||||
const Transform& transform1,
|
const Transform& transform1,
|
||||||
const CollisionShapeInfo& shape2Info,
|
const CollisionShapeInfo& shape2Info,
|
||||||
const Transform& transform2,
|
const Transform& transform2,
|
||||||
|
|
|
@ -150,10 +150,7 @@ bool VoronoiSimplex::isAffinelyDependent() const {
|
||||||
/// pA = sum(lambda_i * a_i) where "a_i" are the support points of object A
|
/// pA = sum(lambda_i * a_i) where "a_i" are the support points of object A
|
||||||
/// pB = sum(lambda_i * b_i) where "b_i" are the support points of object B
|
/// pB = sum(lambda_i * b_i) where "b_i" are the support points of object B
|
||||||
/// with lambda_i = deltaX_i / deltaX
|
/// with lambda_i = deltaX_i / deltaX
|
||||||
void VoronoiSimplex::computeClosestPointsOfAandB(Vector3& pA, Vector3& pB) {
|
void VoronoiSimplex::computeClosestPointsOfAandB(Vector3& pA, Vector3& pB) const {
|
||||||
|
|
||||||
// Recompute the closest point (if necessary)
|
|
||||||
//recomputeClosestPoint();
|
|
||||||
|
|
||||||
pA = mClosestSuppPointA;
|
pA = mClosestSuppPointA;
|
||||||
pB = mClosestSuppPointB;
|
pB = mClosestSuppPointB;
|
||||||
|
@ -380,6 +377,7 @@ void VoronoiSimplex::computeClosestPointOnTriangle(const Vector3& a, const Vecto
|
||||||
|
|
||||||
// The origin is in the Voronoi region of edge AB
|
// The origin is in the Voronoi region of edge AB
|
||||||
// We return the projection of the origin on the edge AB
|
// We return the projection of the origin on the edge AB
|
||||||
|
assert(std::abs(d1 - d3) > MACHINE_EPSILON);
|
||||||
decimal v = d1 / (d1 - d3);
|
decimal v = d1 / (d1 - d3);
|
||||||
|
|
||||||
// Set the barycentric coords of the closest point on the triangle
|
// Set the barycentric coords of the closest point on the triangle
|
||||||
|
@ -410,6 +408,7 @@ void VoronoiSimplex::computeClosestPointOnTriangle(const Vector3& a, const Vecto
|
||||||
|
|
||||||
// The origin is in the Voronoi region of edge AC
|
// The origin is in the Voronoi region of edge AC
|
||||||
// We return the projection of the origin on the edge AC
|
// We return the projection of the origin on the edge AC
|
||||||
|
assert(std::abs(d2 - d6) > MACHINE_EPSILON);
|
||||||
decimal w = d2 / (d2 - d6);
|
decimal w = d2 / (d2 - d6);
|
||||||
|
|
||||||
// Set the barycentric coords of the closest point on the triangle
|
// Set the barycentric coords of the closest point on the triangle
|
||||||
|
@ -425,6 +424,7 @@ void VoronoiSimplex::computeClosestPointOnTriangle(const Vector3& a, const Vecto
|
||||||
|
|
||||||
// The origin is in the Voronoi region of edge BC
|
// The origin is in the Voronoi region of edge BC
|
||||||
// We return the projection of the origin on the edge BC
|
// We return the projection of the origin on the edge BC
|
||||||
|
assert(std::abs((d4 - d3) + (d5 - d6)) > MACHINE_EPSILON);
|
||||||
decimal w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
|
decimal w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
|
||||||
|
|
||||||
// Set the barycentric coords of the closest point on the triangle
|
// Set the barycentric coords of the closest point on the triangle
|
||||||
|
|
|
@ -165,7 +165,7 @@ class VoronoiSimplex {
|
||||||
void backupClosestPointInSimplex(Vector3& point);
|
void backupClosestPointInSimplex(Vector3& point);
|
||||||
|
|
||||||
/// Compute the closest points "pA" and "pB" of object A and B.
|
/// Compute the closest points "pA" and "pB" of object A and B.
|
||||||
void computeClosestPointsOfAandB(Vector3& pA, Vector3& pB);
|
void computeClosestPointsOfAandB(Vector3& pA, Vector3& pB) const;
|
||||||
|
|
||||||
/// Compute the closest point to the origin of the current simplex.
|
/// Compute the closest point to the origin of the current simplex.
|
||||||
bool computeClosestPoint(Vector3& v);
|
bool computeClosestPoint(Vector3& v);
|
||||||
|
|
|
@ -99,6 +99,9 @@ class BoxShape : public ConvexShape {
|
||||||
/// Return the local bounds of the shape in x, y and z directions
|
/// Return the local bounds of the shape in x, y and z directions
|
||||||
virtual void getLocalBounds(Vector3& min, Vector3& max) const;
|
virtual void getLocalBounds(Vector3& min, Vector3& max) const;
|
||||||
|
|
||||||
|
/// Return true if the collision shape is a polyhedron
|
||||||
|
virtual bool isPolyhedron() const;
|
||||||
|
|
||||||
/// Return the local inertia tensor of the collision shape
|
/// Return the local inertia tensor of the collision shape
|
||||||
virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const;
|
virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const;
|
||||||
};
|
};
|
||||||
|
@ -134,6 +137,11 @@ inline void BoxShape::getLocalBounds(Vector3& min, Vector3& max) const {
|
||||||
min = -max;
|
min = -max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return true if the collision shape is a polyhedron
|
||||||
|
inline bool BoxShape::isPolyhedron() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Return the number of bytes used by the collision shape
|
// Return the number of bytes used by the collision shape
|
||||||
inline size_t BoxShape::getSizeInBytes() const {
|
inline size_t BoxShape::getSizeInBytes() const {
|
||||||
return sizeof(BoxShape);
|
return sizeof(BoxShape);
|
||||||
|
|
|
@ -101,6 +101,9 @@ class CapsuleShape : public ConvexShape {
|
||||||
/// Return the local bounds of the shape in x, y and z directions
|
/// Return the local bounds of the shape in x, y and z directions
|
||||||
virtual void getLocalBounds(Vector3& min, Vector3& max) const;
|
virtual void getLocalBounds(Vector3& min, Vector3& max) const;
|
||||||
|
|
||||||
|
/// Return true if the collision shape is a polyhedron
|
||||||
|
virtual bool isPolyhedron() const;
|
||||||
|
|
||||||
/// Return the local inertia tensor of the collision shape
|
/// Return the local inertia tensor of the collision shape
|
||||||
virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const;
|
virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const;
|
||||||
};
|
};
|
||||||
|
@ -154,6 +157,11 @@ inline void CapsuleShape::getLocalBounds(Vector3& min, Vector3& max) const {
|
||||||
min.z = min.x;
|
min.z = min.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return true if the collision shape is a polyhedron
|
||||||
|
inline bool CapsuleShape::isPolyhedron() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Return a local support point in a given direction without the object margin.
|
// Return a local support point in a given direction without the object margin.
|
||||||
/// A capsule is the convex hull of two spheres S1 and S2. The support point in the direction "d"
|
/// A capsule is the convex hull of two spheres S1 and S2. The support point in the direction "d"
|
||||||
/// of the convex hull of a set of convex objects is the support point "p" in the set of all
|
/// of the convex hull of a set of convex objects is the support point "p" in the set of all
|
||||||
|
|
|
@ -98,6 +98,9 @@ class CollisionShape {
|
||||||
/// Return true if the collision shape is convex, false if it is concave
|
/// Return true if the collision shape is convex, false if it is concave
|
||||||
virtual bool isConvex() const=0;
|
virtual bool isConvex() const=0;
|
||||||
|
|
||||||
|
/// Return true if the collision shape is a polyhedron
|
||||||
|
virtual bool isPolyhedron() const=0;
|
||||||
|
|
||||||
/// Return the local bounds of the shape in x, y and z directions
|
/// Return the local bounds of the shape in x, y and z directions
|
||||||
virtual void getLocalBounds(Vector3& min, Vector3& max) const=0;
|
virtual void getLocalBounds(Vector3& min, Vector3& max) const=0;
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,9 @@ class ConcaveShape : public CollisionShape {
|
||||||
/// Return true if the collision shape is convex, false if it is concave
|
/// Return true if the collision shape is convex, false if it is concave
|
||||||
virtual bool isConvex() const;
|
virtual bool isConvex() const;
|
||||||
|
|
||||||
|
/// Return true if the collision shape is a polyhedron
|
||||||
|
virtual bool isPolyhedron() const;
|
||||||
|
|
||||||
/// Use a callback method on all triangles of the concave shape inside a given AABB
|
/// Use a callback method on all triangles of the concave shape inside a given AABB
|
||||||
virtual void testAllTriangles(TriangleCallback& callback, const AABB& localAABB) const=0;
|
virtual void testAllTriangles(TriangleCallback& callback, const AABB& localAABB) const=0;
|
||||||
|
|
||||||
|
@ -116,11 +119,16 @@ inline decimal ConcaveShape::getTriangleMargin() const {
|
||||||
return mTriangleMargin;
|
return mTriangleMargin;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return true if the collision shape is convex, false if it is concave
|
// Return true if the collision shape is convex, false if it is concave
|
||||||
inline bool ConcaveShape::isConvex() const {
|
inline bool ConcaveShape::isConvex() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return true if the collision shape is a polyhedron
|
||||||
|
inline bool ConcaveShape::isPolyhedron() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Return true if a point is inside the collision shape
|
// Return true if a point is inside the collision shape
|
||||||
inline bool ConcaveShape::testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const {
|
inline bool ConcaveShape::testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -107,6 +107,9 @@ class ConeShape : public ConvexShape {
|
||||||
/// Return the local bounds of the shape in x, y and z directions
|
/// Return the local bounds of the shape in x, y and z directions
|
||||||
virtual void getLocalBounds(Vector3& min, Vector3& max) const;
|
virtual void getLocalBounds(Vector3& min, Vector3& max) const;
|
||||||
|
|
||||||
|
/// Return true if the collision shape is a polyhedron
|
||||||
|
virtual bool isPolyhedron() const;
|
||||||
|
|
||||||
/// Return the local inertia tensor of the collision shape
|
/// Return the local inertia tensor of the collision shape
|
||||||
virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const;
|
virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const;
|
||||||
};
|
};
|
||||||
|
@ -159,6 +162,11 @@ inline void ConeShape::getLocalBounds(Vector3& min, Vector3& max) const {
|
||||||
min.z = min.x;
|
min.z = min.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return true if the collision shape is a polyhedron
|
||||||
|
inline bool ConeShape::isPolyhedron() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Return the local inertia tensor of the collision shape
|
// Return the local inertia tensor of the collision shape
|
||||||
/**
|
/**
|
||||||
* @param[out] tensor The 3x3 inertia tensor matrix of the shape in local-space
|
* @param[out] tensor The 3x3 inertia tensor matrix of the shape in local-space
|
||||||
|
|
|
@ -140,6 +140,9 @@ class ConvexMeshShape : public ConvexShape {
|
||||||
/// Add an edge into the convex mesh by specifying the two vertex indices of the edge.
|
/// Add an edge into the convex mesh by specifying the two vertex indices of the edge.
|
||||||
void addEdge(uint v1, uint v2);
|
void addEdge(uint v1, uint v2);
|
||||||
|
|
||||||
|
/// Return true if the collision shape is a polyhedron
|
||||||
|
virtual bool isPolyhedron() const;
|
||||||
|
|
||||||
/// Return true if the edges information is used to speed up the collision detection
|
/// Return true if the edges information is used to speed up the collision detection
|
||||||
bool isEdgesInformationUsed() const;
|
bool isEdgesInformationUsed() const;
|
||||||
|
|
||||||
|
@ -159,6 +162,11 @@ inline size_t ConvexMeshShape::getSizeInBytes() const {
|
||||||
return sizeof(ConvexMeshShape);
|
return sizeof(ConvexMeshShape);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return true if the collision shape is a polyhedron
|
||||||
|
inline bool ConvexMeshShape::isPolyhedron() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Return the local bounds of the shape in x, y and z directions
|
// Return the local bounds of the shape in x, y and z directions
|
||||||
/**
|
/**
|
||||||
* @param min The minimum bounds of the shape in local-space coordinates
|
* @param min The minimum bounds of the shape in local-space coordinates
|
||||||
|
|
|
@ -98,6 +98,9 @@ class CylinderShape : public ConvexShape {
|
||||||
/// Return the height
|
/// Return the height
|
||||||
decimal getHeight() const;
|
decimal getHeight() const;
|
||||||
|
|
||||||
|
/// Return true if the collision shape is a polyhedron
|
||||||
|
virtual bool isPolyhedron() const;
|
||||||
|
|
||||||
/// Set the scaling vector of the collision shape
|
/// Set the scaling vector of the collision shape
|
||||||
virtual void setLocalScaling(const Vector3& scaling);
|
virtual void setLocalScaling(const Vector3& scaling);
|
||||||
|
|
||||||
|
@ -124,6 +127,11 @@ inline decimal CylinderShape::getHeight() const {
|
||||||
return mHalfHeight + mHalfHeight;
|
return mHalfHeight + mHalfHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return true if the collision shape is a polyhedron
|
||||||
|
inline bool CylinderShape::isPolyhedron() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Set the scaling vector of the collision shape
|
// Set the scaling vector of the collision shape
|
||||||
inline void CylinderShape::setLocalScaling(const Vector3& scaling) {
|
inline void CylinderShape::setLocalScaling(const Vector3& scaling) {
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,9 @@ class SphereShape : public ConvexShape {
|
||||||
/// Return the radius of the sphere
|
/// Return the radius of the sphere
|
||||||
decimal getRadius() const;
|
decimal getRadius() const;
|
||||||
|
|
||||||
|
/// Return true if the collision shape is a polyhedron
|
||||||
|
virtual bool isPolyhedron() const;
|
||||||
|
|
||||||
/// Set the scaling vector of the collision shape
|
/// Set the scaling vector of the collision shape
|
||||||
virtual void setLocalScaling(const Vector3& scaling);
|
virtual void setLocalScaling(const Vector3& scaling);
|
||||||
|
|
||||||
|
@ -104,6 +107,11 @@ inline decimal SphereShape::getRadius() const {
|
||||||
return mMargin;
|
return mMargin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return true if the collision shape is a polyhedron
|
||||||
|
inline bool SphereShape::isPolyhedron() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Set the scaling vector of the collision shape
|
// Set the scaling vector of the collision shape
|
||||||
inline void SphereShape::setLocalScaling(const Vector3& scaling) {
|
inline void SphereShape::setLocalScaling(const Vector3& scaling) {
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,9 @@ class TriangleShape : public ConvexShape {
|
||||||
/// Return the coordinates of a given vertex of the triangle
|
/// Return the coordinates of a given vertex of the triangle
|
||||||
Vector3 getVertex(int index) const;
|
Vector3 getVertex(int index) const;
|
||||||
|
|
||||||
|
/// Return true if the collision shape is a polyhedron
|
||||||
|
virtual bool isPolyhedron() const;
|
||||||
|
|
||||||
// ---------- Friendship ---------- //
|
// ---------- Friendship ---------- //
|
||||||
|
|
||||||
friend class ConcaveMeshRaycastCallback;
|
friend class ConcaveMeshRaycastCallback;
|
||||||
|
@ -218,6 +221,11 @@ inline Vector3 TriangleShape::getVertex(int index) const {
|
||||||
return mPoints[index];
|
return mPoints[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return true if the collision shape is a polyhedron
|
||||||
|
inline bool TriangleShape::isPolyhedron() const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue
Block a user