Change raycasting so that a ray is given by two points instead of a point and a direction
This commit is contained in:
parent
08e286d27c
commit
e9257ec56f
|
@ -34,6 +34,7 @@
|
||||||
/// Namespace reactphysics3d
|
/// Namespace reactphysics3d
|
||||||
namespace reactphysics3d {
|
namespace reactphysics3d {
|
||||||
|
|
||||||
|
// TODO : Make this class abstract
|
||||||
// Class Body
|
// Class Body
|
||||||
/**
|
/**
|
||||||
* This class is an abstract class to represent a body of the physics engine.
|
* This class is an abstract class to represent a body of the physics engine.
|
||||||
|
@ -53,6 +54,7 @@ class Body {
|
||||||
/// True if the body is allowed to go to sleep for better efficiency
|
/// True if the body is allowed to go to sleep for better efficiency
|
||||||
bool mIsAllowedToSleep;
|
bool mIsAllowedToSleep;
|
||||||
|
|
||||||
|
// TODO : Use this variable to make bodies active or not
|
||||||
/// True if the body is active
|
/// True if the body is active
|
||||||
bool mIsActive;
|
bool mIsActive;
|
||||||
|
|
||||||
|
|
|
@ -212,31 +212,19 @@ bool CollisionBody::testPointInside(const Vector3& worldPoint) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raycast method
|
|
||||||
bool CollisionBody::raycast(const Ray& ray) {
|
|
||||||
|
|
||||||
// For each collision shape of the body
|
|
||||||
for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) {
|
|
||||||
|
|
||||||
// Test if the ray hits the collision shape
|
|
||||||
if (shape->raycast(ray)) return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Raycast method with feedback information
|
// Raycast method with feedback information
|
||||||
/// The method returns the closest hit among all the collision shapes of the body
|
/// The method returns the closest hit among all the collision shapes of the body
|
||||||
bool CollisionBody::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) {
|
bool CollisionBody::raycast(const Ray& ray, RaycastInfo& raycastInfo) {
|
||||||
|
|
||||||
bool isHit = false;
|
bool isHit = false;
|
||||||
|
Ray rayTemp(ray);
|
||||||
|
|
||||||
// For each collision shape of the body
|
// For each collision shape of the body
|
||||||
for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) {
|
for (ProxyShape* shape = mProxyCollisionShapes; shape != NULL; shape = shape->mNext) {
|
||||||
|
|
||||||
// Test if the ray hits the collision shape
|
// Test if the ray hits the collision shape
|
||||||
if (shape->raycast(ray, raycastInfo, distance)) {
|
if (shape->raycast(rayTemp, raycastInfo)) {
|
||||||
distance = raycastInfo.distance;
|
rayTemp.maxFraction = raycastInfo.hitFraction;
|
||||||
isHit = true;
|
isHit = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,12 +165,8 @@ class CollisionBody : public Body {
|
||||||
/// Return true if a point is inside the collision body
|
/// Return true if a point is inside the collision body
|
||||||
bool testPointInside(const Vector3& worldPoint) const;
|
bool testPointInside(const Vector3& worldPoint) const;
|
||||||
|
|
||||||
/// Raycast method
|
|
||||||
bool raycast(const Ray& ray);
|
|
||||||
|
|
||||||
/// Raycast method with feedback information
|
/// Raycast method with feedback information
|
||||||
bool raycast(const Ray& ray, RaycastInfo& raycastInfo,
|
bool raycast(const Ray& ray, RaycastInfo& raycastInfo);
|
||||||
decimal distance = RAYCAST_INFINITY_DISTANCE);
|
|
||||||
|
|
||||||
// -------------------- Friendship -------------------- //
|
// -------------------- Friendship -------------------- //
|
||||||
|
|
||||||
|
|
|
@ -99,12 +99,8 @@ class ProxyShape {
|
||||||
/// Return true if a point is inside the collision shape
|
/// Return true if a point is inside the collision shape
|
||||||
bool testPointInside(const Vector3& worldPoint);
|
bool testPointInside(const Vector3& worldPoint);
|
||||||
|
|
||||||
/// Raycast method
|
|
||||||
bool raycast(const Ray& ray);
|
|
||||||
|
|
||||||
/// Raycast method with feedback information
|
/// Raycast method with feedback information
|
||||||
bool raycast(const Ray& ray, RaycastInfo& raycastInfo,
|
bool raycast(const Ray& ray, RaycastInfo& raycastInfo);
|
||||||
decimal distance = RAYCAST_INFINITY_DISTANCE);
|
|
||||||
|
|
||||||
// -------------------- Friendship -------------------- //
|
// -------------------- Friendship -------------------- //
|
||||||
|
|
||||||
|
@ -169,14 +165,9 @@ inline decimal ProxyShape::getMargin() const {
|
||||||
return mCollisionShape->getMargin();
|
return mCollisionShape->getMargin();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raycast method
|
|
||||||
inline bool ProxyShape::raycast(const Ray& ray) {
|
|
||||||
return mCollisionShape->raycast(ray, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Raycast method with feedback information
|
// Raycast method with feedback information
|
||||||
inline bool ProxyShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) {
|
inline bool ProxyShape::raycast(const Ray& ray, RaycastInfo& raycastInfo) {
|
||||||
return mCollisionShape->raycast(ray, raycastInfo, this, distance);
|
return mCollisionShape->raycast(ray, raycastInfo, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,8 +63,9 @@ struct RaycastInfo {
|
||||||
/// Surface normal at hit point in world-space coordinates
|
/// Surface normal at hit point in world-space coordinates
|
||||||
Vector3 worldNormal;
|
Vector3 worldNormal;
|
||||||
|
|
||||||
/// Distance from the ray origin to the hit point
|
/// Fraction distance of the hit point between point1 and point2 of the ray
|
||||||
decimal distance;
|
/// The hit point "p" is such that p = point1 + hitFraction * (point2 - point1)
|
||||||
|
decimal hitFraction;
|
||||||
|
|
||||||
/// Pointer to the hit collision body
|
/// Pointer to the hit collision body
|
||||||
CollisionBody* body;
|
CollisionBody* body;
|
||||||
|
|
|
@ -397,8 +397,7 @@ bool GJKAlgorithm::testPointInside(const Vector3& localPoint, ProxyShape* collis
|
||||||
// Ray casting algorithm agains a convex collision shape using the GJK Algorithm
|
// Ray casting algorithm agains a convex collision shape using the GJK Algorithm
|
||||||
/// This method implements the GJK ray casting algorithm described by Gino Van Den Bergen in
|
/// This method implements the GJK ray casting algorithm described by Gino Van Den Bergen in
|
||||||
/// "Ray Casting against General Convex Objects with Application to Continuous Collision Detection".
|
/// "Ray Casting against General Convex Objects with Application to Continuous Collision Detection".
|
||||||
bool GJKAlgorithm::raycast(const Ray& ray, ProxyShape* collisionShape, RaycastInfo& raycastInfo,
|
bool GJKAlgorithm::raycast(const Ray& ray, ProxyShape* collisionShape, RaycastInfo& raycastInfo) {
|
||||||
decimal maxDistance) {
|
|
||||||
|
|
||||||
Vector3 suppA; // Current lower bound point on the ray (starting at ray's origin)
|
Vector3 suppA; // Current lower bound point on the ray (starting at ray's origin)
|
||||||
Vector3 suppB; // Support point on the collision shape
|
Vector3 suppB; // Support point on the collision shape
|
||||||
|
@ -408,8 +407,13 @@ bool GJKAlgorithm::raycast(const Ray& ray, ProxyShape* collisionShape, RaycastIn
|
||||||
// Convert the ray origin and direction into the local-space of the collision shape
|
// Convert the ray origin and direction into the local-space of the collision shape
|
||||||
const Transform localToWorldTransform = collisionShape->getLocalToWorldTransform();
|
const Transform localToWorldTransform = collisionShape->getLocalToWorldTransform();
|
||||||
const Transform worldToLocalTransform = localToWorldTransform.getInverse();
|
const Transform worldToLocalTransform = localToWorldTransform.getInverse();
|
||||||
Vector3 origin = worldToLocalTransform * ray.origin;
|
Vector3 point1 = worldToLocalTransform * ray.point1;
|
||||||
Vector3 rayDirection = worldToLocalTransform.getOrientation() * ray.direction.getUnit();
|
Vector3 point2 = worldToLocalTransform * ray.point2;
|
||||||
|
Vector3 rayDirection = point2 - point1;
|
||||||
|
|
||||||
|
// If the points of the segment are two close, return no hit
|
||||||
|
if (rayDirection.lengthSquare() < machineEpsilonSquare) return false;
|
||||||
|
|
||||||
Vector3 w;
|
Vector3 w;
|
||||||
|
|
||||||
// Create a simplex set
|
// Create a simplex set
|
||||||
|
@ -417,7 +421,7 @@ bool GJKAlgorithm::raycast(const Ray& ray, ProxyShape* collisionShape, RaycastIn
|
||||||
|
|
||||||
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);
|
||||||
suppA = origin; // Current lower bound point on the ray (starting at ray's origin)
|
suppA = point1; // Current lower bound point on the ray (starting at ray's origin)
|
||||||
suppB = collisionShape->getLocalSupportPointWithoutMargin(rayDirection);
|
suppB = collisionShape->getLocalSupportPointWithoutMargin(rayDirection);
|
||||||
Vector3 v = suppA - suppB;
|
Vector3 v = suppA - suppB;
|
||||||
decimal vDotW, vDotR;
|
decimal vDotW, vDotR;
|
||||||
|
@ -444,7 +448,7 @@ bool GJKAlgorithm::raycast(const Ray& ray, ProxyShape* collisionShape, RaycastIn
|
||||||
|
|
||||||
// We have found a better lower bound for the hit point along the ray
|
// We have found a better lower bound for the hit point along the ray
|
||||||
lambda = lambda - vDotW / vDotR;
|
lambda = lambda - vDotW / vDotR;
|
||||||
suppA = origin + lambda * rayDirection;
|
suppA = point1 + lambda * rayDirection;
|
||||||
w = suppA - suppB;
|
w = suppA - suppB;
|
||||||
n = v;
|
n = v;
|
||||||
}
|
}
|
||||||
|
@ -465,7 +469,7 @@ bool GJKAlgorithm::raycast(const Ray& ray, ProxyShape* collisionShape, RaycastIn
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the current lower bound distance is larger than the maximum raycasting distance
|
// If the current lower bound distance is larger than the maximum raycasting distance
|
||||||
if (lambda > maxDistance) return false;
|
if (lambda > ray.maxFraction) return false;
|
||||||
|
|
||||||
nbIterations++;
|
nbIterations++;
|
||||||
}
|
}
|
||||||
|
@ -478,8 +482,8 @@ bool GJKAlgorithm::raycast(const Ray& ray, ProxyShape* collisionShape, RaycastIn
|
||||||
Vector3 pointB;
|
Vector3 pointB;
|
||||||
simplex.computeClosestPointsOfAandB(pointA, pointB);
|
simplex.computeClosestPointsOfAandB(pointA, pointB);
|
||||||
|
|
||||||
// A raycast hit has been found, we fill in the raycast info object
|
// A raycast hit has been found, we fill in the raycast info
|
||||||
raycastInfo.distance = lambda;
|
raycastInfo.hitFraction = lambda;
|
||||||
raycastInfo.worldPoint = localToWorldTransform * pointB;
|
raycastInfo.worldPoint = localToWorldTransform * pointB;
|
||||||
raycastInfo.body = collisionShape->getBody();
|
raycastInfo.body = collisionShape->getBody();
|
||||||
raycastInfo.proxyShape = collisionShape;
|
raycastInfo.proxyShape = collisionShape;
|
||||||
|
|
|
@ -99,8 +99,7 @@ class GJKAlgorithm : public NarrowPhaseAlgorithm {
|
||||||
bool testPointInside(const Vector3& localPoint, ProxyShape* collisionShape);
|
bool testPointInside(const Vector3& localPoint, ProxyShape* collisionShape);
|
||||||
|
|
||||||
/// Ray casting algorithm agains a convex collision shape using the GJK Algorithm
|
/// Ray casting algorithm agains a convex collision shape using the GJK Algorithm
|
||||||
bool raycast(const Ray& ray, ProxyShape* collisionShape, RaycastInfo& raycastInfo,
|
bool raycast(const Ray& ray, ProxyShape* collisionShape, RaycastInfo& raycastInfo);
|
||||||
decimal maxDistance);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ BoxShape::BoxShape(const BoxShape& shape) : CollisionShape(shape), mExtent(shape
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
BoxShape::~BoxShape() {
|
BoxShape::~BoxShape() {
|
||||||
|
|
||||||
|
@ -62,61 +63,15 @@ void BoxShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const
|
||||||
0.0, 0.0, factor * (xSquare + ySquare));
|
0.0, 0.0, factor * (xSquare + ySquare));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raycast method
|
|
||||||
bool BoxShape::raycast(const Ray& ray, ProxyShape* proxyShape) const {
|
|
||||||
|
|
||||||
const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform();
|
|
||||||
const Transform worldToLocalTransform = localToWorldTransform.getInverse();
|
|
||||||
Vector3 origin = worldToLocalTransform * ray.origin;
|
|
||||||
Vector3 rayDirection = worldToLocalTransform.getOrientation() * ray.direction.getUnit();
|
|
||||||
decimal tMin = decimal(0.0);
|
|
||||||
decimal tMax = DECIMAL_LARGEST;
|
|
||||||
|
|
||||||
// For each of the three slabs
|
|
||||||
for (int i=0; i<3; i++) {
|
|
||||||
|
|
||||||
// If ray is parallel to the slab
|
|
||||||
if (std::abs(rayDirection[i]) < MACHINE_EPSILON) {
|
|
||||||
|
|
||||||
// If the ray's origin is not inside the slab, there is no hit
|
|
||||||
if (origin[i] > mExtent[i] || origin[i] < -mExtent[i]) return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
// Compute the intersection of the ray with the near and far plane of the slab
|
|
||||||
decimal oneOverD = decimal(1.0) / rayDirection[i];
|
|
||||||
decimal t1 = (-mExtent[i] - origin[i]) * oneOverD;
|
|
||||||
decimal t2 = (mExtent[i] - origin [i]) * oneOverD;
|
|
||||||
|
|
||||||
// Swap t1 and t2 if need so that t1 is intersection with near plane and
|
|
||||||
// t2 with far plane
|
|
||||||
if (t1 > t2) std::swap(t1, t2);
|
|
||||||
|
|
||||||
// If t1 is negative, the origin is inside the box and therefore, there is no hit
|
|
||||||
if (t1 < decimal(0.0)) return false;
|
|
||||||
|
|
||||||
// Compute the intersection of the of slab intersection interval with previous slabs
|
|
||||||
tMin = std::max(tMin, t1);
|
|
||||||
tMax = std::min(tMax, t2);
|
|
||||||
|
|
||||||
// If the slabs intersection is empty, there is no hit
|
|
||||||
if (tMin > tMax) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A hit has been found
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Raycast method with feedback information
|
// Raycast method with feedback information
|
||||||
bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape,
|
bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const {
|
||||||
decimal distance) const {
|
|
||||||
|
|
||||||
const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform();
|
const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform();
|
||||||
const Transform worldToLocalTransform = localToWorldTransform.getInverse();
|
const Transform worldToLocalTransform = localToWorldTransform.getInverse();
|
||||||
Vector3 origin = worldToLocalTransform * ray.origin;
|
const Vector3 point1 = worldToLocalTransform * ray.point1;
|
||||||
Vector3 rayDirection = worldToLocalTransform.getOrientation() * ray.direction.getUnit();
|
const Vector3 point2 = worldToLocalTransform * ray.point2;
|
||||||
decimal tMin = decimal(0.0);
|
Vector3 rayDirection = point2 - point1;
|
||||||
|
decimal tMin = DECIMAL_SMALLEST;
|
||||||
decimal tMax = DECIMAL_LARGEST;
|
decimal tMax = DECIMAL_LARGEST;
|
||||||
Vector3 normalDirection(decimal(0), decimal(0), decimal(0));
|
Vector3 normalDirection(decimal(0), decimal(0), decimal(0));
|
||||||
Vector3 currentNormal;
|
Vector3 currentNormal;
|
||||||
|
@ -128,14 +83,14 @@ bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pro
|
||||||
if (std::abs(rayDirection[i]) < MACHINE_EPSILON) {
|
if (std::abs(rayDirection[i]) < MACHINE_EPSILON) {
|
||||||
|
|
||||||
// If the ray's origin is not inside the slab, there is no hit
|
// If the ray's origin is not inside the slab, there is no hit
|
||||||
if (origin[i] > mExtent[i] || origin[i] < -mExtent[i]) return false;
|
if (point1[i] > mExtent[i] || point1[i] < -mExtent[i]) return false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
// Compute the intersection of the ray with the near and far plane of the slab
|
// Compute the intersection of the ray with the near and far plane of the slab
|
||||||
decimal oneOverD = decimal(1.0) / rayDirection[i];
|
decimal oneOverD = decimal(1.0) / rayDirection[i];
|
||||||
decimal t1 = (-mExtent[i] - origin[i]) * oneOverD;
|
decimal t1 = (-mExtent[i] - point1[i]) * oneOverD;
|
||||||
decimal t2 = (mExtent[i] - origin [i]) * oneOverD;
|
decimal t2 = (mExtent[i] - point1 [i]) * oneOverD;
|
||||||
currentNormal = -mExtent;
|
currentNormal = -mExtent;
|
||||||
|
|
||||||
// Swap t1 and t2 if need so that t1 is intersection with near plane and
|
// Swap t1 and t2 if need so that t1 is intersection with near plane and
|
||||||
|
@ -145,9 +100,6 @@ bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pro
|
||||||
currentNormal = -currentNormal;
|
currentNormal = -currentNormal;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If t1 is negative, the origin is inside the box and therefore, there is no hit
|
|
||||||
if (t1 < decimal(0.0)) return false;
|
|
||||||
|
|
||||||
// Compute the intersection of the of slab intersection interval with previous slabs
|
// Compute the intersection of the of slab intersection interval with previous slabs
|
||||||
if (t1 > tMin) {
|
if (t1 > tMin) {
|
||||||
tMin = t1;
|
tMin = t1;
|
||||||
|
@ -155,20 +107,23 @@ bool BoxShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pro
|
||||||
}
|
}
|
||||||
tMax = std::min(tMax, t2);
|
tMax = std::min(tMax, t2);
|
||||||
|
|
||||||
// If tMin is larger than the maximum raycasting distance, we return no hit
|
// If tMin is larger than the maximum raycasting fraction, we return no hit
|
||||||
if (tMin > distance) return false;
|
if (tMin > ray.maxFraction) return false;
|
||||||
|
|
||||||
// If the slabs intersection is empty, there is no hit
|
// If the slabs intersection is empty, there is no hit
|
||||||
if (tMin > tMax) return false;
|
if (tMin > tMax) return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If tMin is negative, we return no hit
|
||||||
|
if (tMin < decimal(0.0)) return false;
|
||||||
|
|
||||||
// The ray intersects the three slabs, we compute the hit point
|
// The ray intersects the three slabs, we compute the hit point
|
||||||
Vector3 localHitPoint = origin + tMin * rayDirection;
|
Vector3 localHitPoint = point1 + tMin * rayDirection;
|
||||||
|
|
||||||
raycastInfo.body = proxyShape->getBody();
|
raycastInfo.body = proxyShape->getBody();
|
||||||
raycastInfo.proxyShape = proxyShape;
|
raycastInfo.proxyShape = proxyShape;
|
||||||
raycastInfo.distance = tMin;
|
raycastInfo.hitFraction = tMin;
|
||||||
raycastInfo.worldPoint = localToWorldTransform * localHitPoint;
|
raycastInfo.worldPoint = localToWorldTransform * localHitPoint;
|
||||||
raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection;
|
raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection;
|
||||||
|
|
||||||
|
|
|
@ -78,12 +78,8 @@ class BoxShape : public CollisionShape {
|
||||||
/// Return true if a point is inside the collision shape
|
/// Return true if a point is inside the collision shape
|
||||||
virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const;
|
virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const;
|
||||||
|
|
||||||
/// Raycast method
|
|
||||||
virtual bool raycast(const Ray& ray, ProxyShape* proxyShape) const;
|
|
||||||
|
|
||||||
/// Raycast method with feedback information
|
/// Raycast method with feedback information
|
||||||
virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape,
|
virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const;
|
||||||
decimal distance = RAYCAST_INFINITY_DISTANCE) const;
|
|
||||||
|
|
||||||
public :
|
public :
|
||||||
|
|
||||||
|
|
|
@ -143,103 +143,37 @@ bool CapsuleShape::testPointInside(const Vector3& localPoint, ProxyShape* proxyS
|
||||||
(xSquare + zSquare + diffYCenterSphere2 * diffYCenterSphere2) < squareRadius;
|
(xSquare + zSquare + diffYCenterSphere2 * diffYCenterSphere2) < squareRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raycast method
|
|
||||||
bool CapsuleShape::raycast(const Ray& ray, ProxyShape* proxyShape) const {
|
|
||||||
|
|
||||||
// Transform the ray direction and origin in local-space coordinates
|
|
||||||
const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform();
|
|
||||||
const Transform worldToLocalTransform = localToWorldTransform.getInverse();
|
|
||||||
Vector3 origin = worldToLocalTransform * ray.origin;
|
|
||||||
Vector3 n = worldToLocalTransform.getOrientation() * ray.direction.getUnit();
|
|
||||||
|
|
||||||
const decimal epsilon = decimal(0.00001);
|
|
||||||
Vector3 p(decimal(0), -mHalfHeight, decimal(0));
|
|
||||||
Vector3 q(decimal(0), mHalfHeight, decimal(0));
|
|
||||||
Vector3 d = q - p;
|
|
||||||
Vector3 m = origin - p;
|
|
||||||
decimal t;
|
|
||||||
|
|
||||||
decimal mDotD = m.dot(d);
|
|
||||||
decimal nDotD = n.dot(d);
|
|
||||||
decimal dDotD = d.dot(d);
|
|
||||||
decimal mDotN = m.dot(n);
|
|
||||||
|
|
||||||
decimal a = dDotD - nDotD * nDotD;
|
|
||||||
decimal k = m.dot(m) - mRadius * mRadius;
|
|
||||||
decimal c = dDotD * k - mDotD * mDotD;
|
|
||||||
|
|
||||||
// If the ray is parallel to the cylinder axis
|
|
||||||
if (std::abs(a) < epsilon) {
|
|
||||||
|
|
||||||
// If the origin is outside the surface of the cylinder, we return no hit
|
|
||||||
if (c > decimal(0.0)) return false;
|
|
||||||
|
|
||||||
// Here we know that the segment intersect an endcap of the cylinder
|
|
||||||
|
|
||||||
// If the ray intersects with the "p" endcap of the capsule
|
|
||||||
if (mDotD < decimal(0.0)) {
|
|
||||||
|
|
||||||
// Check intersection with the sphere "p" endcap of the capsule
|
|
||||||
return raycastWithSphereEndCap(origin, n, p);
|
|
||||||
}
|
|
||||||
else if (mDotD > dDotD) { // If the ray intersects with the "q" endcap of the cylinder
|
|
||||||
|
|
||||||
// Check intersection with the sphere "q" endcap of the capsule
|
|
||||||
return raycastWithSphereEndCap(origin, n, q);
|
|
||||||
}
|
|
||||||
else { // If the origin is inside the cylinder, we return no hit
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
decimal b = dDotD * mDotN - nDotD * mDotD;
|
|
||||||
decimal discriminant = b * b - a * c;
|
|
||||||
|
|
||||||
// If the discriminant is negative, no real roots and therfore, no hit
|
|
||||||
if (discriminant < decimal(0.0)) return false;
|
|
||||||
|
|
||||||
// Compute the smallest root (first intersection along the ray)
|
|
||||||
decimal t0 = t = (-b - std::sqrt(discriminant)) / a;
|
|
||||||
|
|
||||||
// If the intersection is outside the cylinder on "p" endcap side
|
|
||||||
decimal value = mDotD + t * nDotD;
|
|
||||||
if (value < decimal(0.0)) {
|
|
||||||
|
|
||||||
// Check intersection with the sphere "p" endcap of the capsule
|
|
||||||
return raycastWithSphereEndCap(origin, n, p);
|
|
||||||
}
|
|
||||||
else if (value > dDotD) { // If the intersection is outside the cylinder on the "q" side
|
|
||||||
|
|
||||||
// Check intersection with the sphere "q" endcap of the capsule
|
|
||||||
return raycastWithSphereEndCap(origin, n, q);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the intersection is behind the origin of the ray, we return no hit
|
|
||||||
return (t0 >= decimal(0.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Raycast method with feedback information
|
// Raycast method with feedback information
|
||||||
bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape,
|
bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const {
|
||||||
decimal distance) const {
|
|
||||||
|
|
||||||
// Transform the ray direction and origin in local-space coordinates
|
// Transform the ray direction and origin in local-space coordinates
|
||||||
const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform();
|
const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform();
|
||||||
const Transform worldToLocalTransform = localToWorldTransform.getInverse();
|
const Transform worldToLocalTransform = localToWorldTransform.getInverse();
|
||||||
Vector3 origin = worldToLocalTransform * ray.origin;
|
const Vector3 point1 = worldToLocalTransform * ray.point1;
|
||||||
Vector3 n = worldToLocalTransform.getOrientation() * ray.direction.getUnit();
|
const Vector3 point2 = worldToLocalTransform * ray.point2;
|
||||||
|
const Vector3 n = point2 - point1;
|
||||||
|
|
||||||
const decimal epsilon = decimal(0.00001);
|
const decimal epsilon = decimal(0.01);
|
||||||
Vector3 p(decimal(0), -mHalfHeight, decimal(0));
|
Vector3 p(decimal(0), -mHalfHeight, decimal(0));
|
||||||
Vector3 q(decimal(0), mHalfHeight, decimal(0));
|
Vector3 q(decimal(0), mHalfHeight, decimal(0));
|
||||||
Vector3 d = q - p;
|
Vector3 d = q - p;
|
||||||
Vector3 m = origin - p;
|
Vector3 m = point1 - p;
|
||||||
decimal t;
|
decimal t;
|
||||||
|
|
||||||
decimal mDotD = m.dot(d);
|
decimal mDotD = m.dot(d);
|
||||||
decimal nDotD = n.dot(d);
|
decimal nDotD = n.dot(d);
|
||||||
decimal dDotD = d.dot(d);
|
decimal dDotD = d.dot(d);
|
||||||
|
|
||||||
|
// Test if the segment is outside the cylinder
|
||||||
|
decimal vec1DotD = (point1 - Vector3(decimal(0.0), -mHalfHeight - mRadius, decimal(0.0))).dot(d);
|
||||||
|
if (vec1DotD < decimal(0.0) && vec1DotD + nDotD < decimal(0.0)) return false;
|
||||||
|
decimal ddotDExtraCaps = decimal(2.0) * mRadius * d.y;
|
||||||
|
if (vec1DotD > dDotD + ddotDExtraCaps && vec1DotD + nDotD > dDotD + ddotDExtraCaps) return false;
|
||||||
|
|
||||||
|
decimal nDotN = n.dot(n);
|
||||||
decimal mDotN = m.dot(n);
|
decimal mDotN = m.dot(n);
|
||||||
|
|
||||||
decimal a = dDotD - nDotD * nDotD;
|
decimal a = dDotD * nDotN - nDotD * nDotD;
|
||||||
decimal k = m.dot(m) - mRadius * mRadius;
|
decimal k = m.dot(m) - mRadius * mRadius;
|
||||||
decimal c = dDotD * k - mDotD * mDotD;
|
decimal c = dDotD * k - mDotD * mDotD;
|
||||||
|
|
||||||
|
@ -256,11 +190,11 @@ bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape*
|
||||||
|
|
||||||
// Check intersection between the ray and the "p" sphere endcap of the capsule
|
// Check intersection between the ray and the "p" sphere endcap of the capsule
|
||||||
Vector3 hitLocalPoint;
|
Vector3 hitLocalPoint;
|
||||||
decimal hitDistance;
|
decimal hitFraction;
|
||||||
if (raycastWithSphereEndCap(origin, n, p, distance, hitLocalPoint, hitDistance)) {
|
if (raycastWithSphereEndCap(point1, point2, p, ray.maxFraction, hitLocalPoint, hitFraction)) {
|
||||||
raycastInfo.body = proxyShape->getBody();
|
raycastInfo.body = proxyShape->getBody();
|
||||||
raycastInfo.proxyShape = proxyShape;
|
raycastInfo.proxyShape = proxyShape;
|
||||||
raycastInfo.distance = hitDistance;
|
raycastInfo.hitFraction = hitFraction;
|
||||||
raycastInfo.worldPoint = localToWorldTransform * hitLocalPoint;
|
raycastInfo.worldPoint = localToWorldTransform * hitLocalPoint;
|
||||||
Vector3 normalDirection = (hitLocalPoint - p).getUnit();
|
Vector3 normalDirection = (hitLocalPoint - p).getUnit();
|
||||||
raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection;
|
raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection;
|
||||||
|
@ -274,11 +208,11 @@ bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape*
|
||||||
|
|
||||||
// Check intersection between the ray and the "q" sphere endcap of the capsule
|
// Check intersection between the ray and the "q" sphere endcap of the capsule
|
||||||
Vector3 hitLocalPoint;
|
Vector3 hitLocalPoint;
|
||||||
decimal hitDistance;
|
decimal hitFraction;
|
||||||
if (raycastWithSphereEndCap(origin, n, q, distance, hitLocalPoint, hitDistance)) {
|
if (raycastWithSphereEndCap(point1, point2, q, ray.maxFraction, hitLocalPoint, hitFraction)) {
|
||||||
raycastInfo.body = proxyShape->getBody();
|
raycastInfo.body = proxyShape->getBody();
|
||||||
raycastInfo.proxyShape = proxyShape;
|
raycastInfo.proxyShape = proxyShape;
|
||||||
raycastInfo.distance = hitDistance;
|
raycastInfo.hitFraction = hitFraction;
|
||||||
raycastInfo.worldPoint = localToWorldTransform * hitLocalPoint;
|
raycastInfo.worldPoint = localToWorldTransform * hitLocalPoint;
|
||||||
Vector3 normalDirection = (hitLocalPoint - q).getUnit();
|
Vector3 normalDirection = (hitLocalPoint - q).getUnit();
|
||||||
raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection;
|
raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection;
|
||||||
|
@ -307,11 +241,11 @@ bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape*
|
||||||
|
|
||||||
// Check intersection between the ray and the "p" sphere endcap of the capsule
|
// Check intersection between the ray and the "p" sphere endcap of the capsule
|
||||||
Vector3 hitLocalPoint;
|
Vector3 hitLocalPoint;
|
||||||
decimal hitDistance;
|
decimal hitFraction;
|
||||||
if (raycastWithSphereEndCap(origin, n, p, distance, hitLocalPoint, hitDistance)) {
|
if (raycastWithSphereEndCap(point1, point2, p, ray.maxFraction, hitLocalPoint, hitFraction)) {
|
||||||
raycastInfo.body = proxyShape->getBody();
|
raycastInfo.body = proxyShape->getBody();
|
||||||
raycastInfo.proxyShape = proxyShape;
|
raycastInfo.proxyShape = proxyShape;
|
||||||
raycastInfo.distance = hitDistance;
|
raycastInfo.hitFraction = hitFraction;
|
||||||
raycastInfo.worldPoint = localToWorldTransform * hitLocalPoint;
|
raycastInfo.worldPoint = localToWorldTransform * hitLocalPoint;
|
||||||
Vector3 normalDirection = (hitLocalPoint - p).getUnit();
|
Vector3 normalDirection = (hitLocalPoint - p).getUnit();
|
||||||
raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection;
|
raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection;
|
||||||
|
@ -325,11 +259,11 @@ bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape*
|
||||||
|
|
||||||
// Check intersection between the ray and the "q" sphere endcap of the capsule
|
// Check intersection between the ray and the "q" sphere endcap of the capsule
|
||||||
Vector3 hitLocalPoint;
|
Vector3 hitLocalPoint;
|
||||||
decimal hitDistance;
|
decimal hitFraction;
|
||||||
if (raycastWithSphereEndCap(origin, n, q, distance, hitLocalPoint, hitDistance)) {
|
if (raycastWithSphereEndCap(point1, point2, q, ray.maxFraction, hitLocalPoint, hitFraction)) {
|
||||||
raycastInfo.body = proxyShape->getBody();
|
raycastInfo.body = proxyShape->getBody();
|
||||||
raycastInfo.proxyShape = proxyShape;
|
raycastInfo.proxyShape = proxyShape;
|
||||||
raycastInfo.distance = hitDistance;
|
raycastInfo.hitFraction = hitFraction;
|
||||||
raycastInfo.worldPoint = localToWorldTransform * hitLocalPoint;
|
raycastInfo.worldPoint = localToWorldTransform * hitLocalPoint;
|
||||||
Vector3 normalDirection = (hitLocalPoint - q).getUnit();
|
Vector3 normalDirection = (hitLocalPoint - q).getUnit();
|
||||||
raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection;
|
raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection;
|
||||||
|
@ -344,13 +278,13 @@ bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape*
|
||||||
|
|
||||||
// If the intersection is behind the origin of the ray or beyond the maximum
|
// If the intersection is behind the origin of the ray or beyond the maximum
|
||||||
// raycasting distance, we return no hit
|
// raycasting distance, we return no hit
|
||||||
if (t < decimal(0.0) || t > distance) return false;
|
if (t < decimal(0.0) || t > ray.maxFraction) return false;
|
||||||
|
|
||||||
// Compute the hit information
|
// Compute the hit information
|
||||||
Vector3 localHitPoint = origin + t * n;
|
Vector3 localHitPoint = point1 + t * n;
|
||||||
raycastInfo.body = proxyShape->getBody();
|
raycastInfo.body = proxyShape->getBody();
|
||||||
raycastInfo.proxyShape = proxyShape;
|
raycastInfo.proxyShape = proxyShape;
|
||||||
raycastInfo.distance = t;
|
raycastInfo.hitFraction = t;
|
||||||
raycastInfo.worldPoint = localToWorldTransform * localHitPoint;
|
raycastInfo.worldPoint = localToWorldTransform * localHitPoint;
|
||||||
Vector3 v = localHitPoint - p;
|
Vector3 v = localHitPoint - p;
|
||||||
Vector3 w = (v.dot(d) / d.lengthSquare()) * d;
|
Vector3 w = (v.dot(d) / d.lengthSquare()) * d;
|
||||||
|
@ -361,64 +295,46 @@ bool CapsuleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape*
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raycasting method between a ray one of the two spheres end cap of the capsule
|
// Raycasting method between a ray one of the two spheres end cap of the capsule
|
||||||
bool CapsuleShape::raycastWithSphereEndCap(const Vector3& rayOrigin, const Vector3& rayDirection,
|
bool CapsuleShape::raycastWithSphereEndCap(const Vector3& point1, const Vector3& point2,
|
||||||
const Vector3& sphereCenter, decimal maxDistance,
|
const Vector3& sphereCenter, decimal maxFraction,
|
||||||
Vector3& hitLocalPoint, decimal& hitDistance) const {
|
Vector3& hitLocalPoint, decimal& hitFraction) const {
|
||||||
|
|
||||||
Vector3 m = rayOrigin - sphereCenter;
|
const Vector3 m = point1 - sphereCenter;
|
||||||
decimal c = m.dot(m) - mRadius * mRadius;
|
decimal c = m.dot(m) - mRadius * mRadius;
|
||||||
|
|
||||||
// If the origin of the ray is inside the sphere, we return no intersection
|
// If the origin of the ray is inside the sphere, we return no intersection
|
||||||
if (c < decimal(0.0)) return false;
|
if (c < decimal(0.0)) return false;
|
||||||
|
|
||||||
|
const Vector3 rayDirection = point2 - point1;
|
||||||
decimal b = m.dot(rayDirection);
|
decimal b = m.dot(rayDirection);
|
||||||
|
|
||||||
// If the origin of the ray is outside the sphere and the ray
|
// If the origin of the ray is outside the sphere and the ray
|
||||||
// is pointing away from the sphere and there is no intersection
|
// is pointing away from the sphere, there is no intersection
|
||||||
if (c >= decimal(0.0) && b > decimal(0.0)) return false;
|
if (b > decimal(0.0)) return false;
|
||||||
|
|
||||||
|
decimal raySquareLength = rayDirection.lengthSquare();
|
||||||
|
|
||||||
// Compute the discriminant of the quadratic equation
|
// Compute the discriminant of the quadratic equation
|
||||||
decimal discriminant = b * b - c;
|
decimal discriminant = b * b - raySquareLength * c;
|
||||||
|
|
||||||
// If the discriminant is negative, there is no intersection
|
// If the discriminant is negative or the ray length is very small, there is no intersection
|
||||||
if (discriminant < decimal(0.0)) return false;
|
if (discriminant < decimal(0.0) || raySquareLength < MACHINE_EPSILON) return false;
|
||||||
|
|
||||||
// Compute the solution "t" closest to the origin
|
// Compute the solution "t" closest to the origin
|
||||||
decimal t = -b - std::sqrt(discriminant);
|
decimal t = -b - std::sqrt(discriminant);
|
||||||
|
|
||||||
assert(t >= decimal(0.0));
|
assert(t >= decimal(0.0));
|
||||||
|
|
||||||
// If the intersection distance is larger than the allowed distance, return no intersection
|
// If the hit point is withing the segment ray fraction
|
||||||
if (t > maxDistance) return false;
|
if (t < maxFraction * raySquareLength) {
|
||||||
|
|
||||||
// Compute the hit point and distance
|
// Compute the intersection information
|
||||||
hitLocalPoint = rayOrigin + t * rayDirection;
|
t /= raySquareLength;
|
||||||
hitDistance = t;
|
hitFraction = t;
|
||||||
|
hitLocalPoint = point1 + t * rayDirection;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raycasting method between a ray one of the two spheres end cap of the capsule
|
return false;
|
||||||
/// This method returns true if there is an intersection and false otherwise but does not
|
|
||||||
/// compute the intersection point.
|
|
||||||
bool CapsuleShape::raycastWithSphereEndCap(const Vector3& rayOrigin, const Vector3& rayDirection,
|
|
||||||
const Vector3& sphereCenter) const {
|
|
||||||
|
|
||||||
Vector3 m = rayOrigin - sphereCenter;
|
|
||||||
decimal c = m.dot(m) - mRadius * mRadius;
|
|
||||||
|
|
||||||
// If the origin of the ray is inside the sphere, we return no intersection
|
|
||||||
if (c < decimal(0.0)) return false;
|
|
||||||
|
|
||||||
decimal b = m.dot(rayDirection);
|
|
||||||
|
|
||||||
// If the origin of the ray is outside the sphere and the ray
|
|
||||||
// is pointing away from the sphere and there is no intersection
|
|
||||||
if (c >= decimal(0.0) && b > decimal(0.0)) return false;
|
|
||||||
|
|
||||||
// Compute the discriminant of the quadratic equation
|
|
||||||
decimal discriminant = b * b - c;
|
|
||||||
|
|
||||||
// If the discriminant is negative, there is no intersection
|
|
||||||
return (discriminant >= decimal(0.0));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,21 +75,13 @@ class CapsuleShape : public CollisionShape {
|
||||||
/// Return true if a point is inside the collision shape
|
/// Return true if a point is inside the collision shape
|
||||||
virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const;
|
virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const;
|
||||||
|
|
||||||
/// Raycast method
|
|
||||||
virtual bool raycast(const Ray& ray, ProxyShape* proxyShape) const;
|
|
||||||
|
|
||||||
/// Raycast method with feedback information
|
/// Raycast method with feedback information
|
||||||
virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape,
|
virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const;
|
||||||
decimal distance = RAYCAST_INFINITY_DISTANCE) const;
|
|
||||||
|
|
||||||
/// Raycasting method between a ray one of the two spheres end cap of the capsule
|
/// Raycasting method between a ray one of the two spheres end cap of the capsule
|
||||||
bool raycastWithSphereEndCap(const Vector3& rayOrigin, const Vector3& rayDirection,
|
bool raycastWithSphereEndCap(const Vector3& point1, const Vector3& point2,
|
||||||
const Vector3& sphereCenter, decimal maxDistance,
|
const Vector3& sphereCenter, decimal maxFraction,
|
||||||
Vector3& hitLocalPoint, decimal& hitDistance) const;
|
Vector3& hitLocalPoint, decimal& hitFraction) const;
|
||||||
|
|
||||||
// Raycasting method between a ray one of the two spheres end cap of the capsule
|
|
||||||
bool raycastWithSphereEndCap(const Vector3& rayOrigin, const Vector3& rayDirection,
|
|
||||||
const Vector3& sphereCenter) const;
|
|
||||||
|
|
||||||
public :
|
public :
|
||||||
|
|
||||||
|
|
|
@ -85,12 +85,8 @@ class CollisionShape {
|
||||||
/// Return true if a point is inside the collision shape
|
/// Return true if a point is inside the collision shape
|
||||||
virtual bool testPointInside(const Vector3& worldPoint, ProxyShape* proxyShape) const=0;
|
virtual bool testPointInside(const Vector3& worldPoint, ProxyShape* proxyShape) const=0;
|
||||||
|
|
||||||
/// Raycast method
|
|
||||||
virtual bool raycast(const Ray& ray, ProxyShape* proxyShape) const=0;
|
|
||||||
|
|
||||||
/// Raycast method with feedback information
|
/// Raycast method with feedback information
|
||||||
virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape,
|
virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const=0;
|
||||||
decimal distance = RAYCAST_INFINITY_DISTANCE) const=0;
|
|
||||||
|
|
||||||
public :
|
public :
|
||||||
|
|
||||||
|
|
|
@ -95,120 +95,18 @@ Vector3 ConeShape::getLocalSupportPointWithoutMargin(const Vector3& direction,
|
||||||
return supportPoint;
|
return supportPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raycast method
|
|
||||||
// This implementation is based on the technique described by David Eberly in the article
|
|
||||||
// "Intersection of a Line and a Cone" that can be found at
|
|
||||||
// http://www.geometrictools.com/Documentation/IntersectionLineCone.pdf
|
|
||||||
bool ConeShape::raycast(const Ray& ray, ProxyShape* proxyShape) const {
|
|
||||||
|
|
||||||
// Transform the ray direction and origin in local-space coordinates
|
|
||||||
const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform();
|
|
||||||
const Transform worldToLocalTransform = localToWorldTransform.getInverse();
|
|
||||||
Vector3 origin = worldToLocalTransform * ray.origin;
|
|
||||||
Vector3 r = worldToLocalTransform.getOrientation() * ray.direction.getUnit();
|
|
||||||
|
|
||||||
const decimal epsilon = decimal(0.00001);
|
|
||||||
Vector3 V(0, mHalfHeight, 0);
|
|
||||||
Vector3 centerBase(0, -mHalfHeight, 0);
|
|
||||||
Vector3 axis(0, decimal(-1.0), 0);
|
|
||||||
decimal heightSquare = decimal(4.0) * mHalfHeight * mHalfHeight;
|
|
||||||
decimal cosThetaSquare = heightSquare / (heightSquare + mRadius * mRadius);
|
|
||||||
decimal factor = decimal(1.0) - cosThetaSquare;
|
|
||||||
Vector3 delta = origin - V;
|
|
||||||
decimal c0 = -cosThetaSquare * delta.x * delta.x + factor * delta.y * delta.y -
|
|
||||||
cosThetaSquare * delta.z * delta.z;
|
|
||||||
decimal c1 = -cosThetaSquare * delta.x * r.x + factor * delta.y * r.y - cosThetaSquare * delta.z * r.z;
|
|
||||||
decimal c2 = -cosThetaSquare * r.x * r.x + factor * r.y * r.y - cosThetaSquare * r.z * r.z;
|
|
||||||
decimal tHit[] = {decimal(-1.0), decimal(-1.0), decimal(-1.0)};
|
|
||||||
Vector3 localHitPoint[3];
|
|
||||||
|
|
||||||
// If c2 is different from zero
|
|
||||||
if (std::abs(c2) > MACHINE_EPSILON) {
|
|
||||||
decimal gamma = c1 * c1 - c0 * c2;
|
|
||||||
|
|
||||||
// If there is no real roots in the quadratic equation
|
|
||||||
if (gamma < decimal(0.0)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (gamma > decimal(0.0)) { // The equation has two real roots
|
|
||||||
|
|
||||||
// Compute two intersections
|
|
||||||
decimal sqrRoot = std::sqrt(gamma);
|
|
||||||
tHit[0] = (-c1 - sqrRoot) / c2;
|
|
||||||
tHit[1] = (-c1 + sqrRoot) / c2;
|
|
||||||
}
|
|
||||||
else { // If the equation has a single real root
|
|
||||||
|
|
||||||
// Compute the intersection
|
|
||||||
tHit[0] = -c1 / c2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else { // If c2 == 0
|
|
||||||
|
|
||||||
// If c2 = 0 and c1 != 0
|
|
||||||
if (std::abs(c1) > MACHINE_EPSILON) {
|
|
||||||
tHit[0] = -c0 / (decimal(2.0) * c1);
|
|
||||||
}
|
|
||||||
else { // If c2 = c1 = 0
|
|
||||||
|
|
||||||
// If c0 is different from zero, no solution and if c0 = 0, we have a
|
|
||||||
// degenerate case, the whole ray is contained in the cone side
|
|
||||||
// but we return no hit in this case
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the origin of the ray is inside the cone, we return no hit
|
|
||||||
if (testPointInside(origin, NULL)) return false;
|
|
||||||
|
|
||||||
localHitPoint[0] = origin + tHit[0] * r;
|
|
||||||
localHitPoint[1] = origin + tHit[1] * r;
|
|
||||||
|
|
||||||
// Only keep hit points in one side of the double cone (the cone we are interested in)
|
|
||||||
if (axis.dot(localHitPoint[0] - V) < decimal(0.0)) {
|
|
||||||
tHit[0] = decimal(-1.0);
|
|
||||||
}
|
|
||||||
if (axis.dot(localHitPoint[1] - V) < decimal(0.0)) {
|
|
||||||
tHit[1] = decimal(-1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only keep hit points that are within the correct height of the cone
|
|
||||||
if (localHitPoint[0].y < decimal(-mHalfHeight)) {
|
|
||||||
tHit[0] = decimal(-1.0);
|
|
||||||
}
|
|
||||||
if (localHitPoint[1].y < decimal(-mHalfHeight)) {
|
|
||||||
tHit[1] = decimal(-1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tHit[0] >= decimal(0.0) || tHit[1] >= decimal(0.0)) return true;
|
|
||||||
|
|
||||||
// If the ray is in direction of the base plane of the cone
|
|
||||||
if (r.y > epsilon) {
|
|
||||||
|
|
||||||
// Compute the intersection with the base plane of the cone
|
|
||||||
tHit[2] = (-mHalfHeight + origin.y) / (-r.y);
|
|
||||||
|
|
||||||
// Only keep this intersection if it is inside the cone radius
|
|
||||||
localHitPoint[2] = origin + tHit[2] * r;
|
|
||||||
|
|
||||||
return ((localHitPoint[2] - centerBase).lengthSquare() <= mRadius * mRadius);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Raycast method with feedback information
|
// Raycast method with feedback information
|
||||||
// This implementation is based on the technique described by David Eberly in the article
|
// This implementation is based on the technique described by David Eberly in the article
|
||||||
// "Intersection of a Line and a Cone" that can be found at
|
// "Intersection of a Line and a Cone" that can be found at
|
||||||
// http://www.geometrictools.com/Documentation/IntersectionLineCone.pdf
|
// http://www.geometrictools.com/Documentation/IntersectionLineCone.pdf
|
||||||
bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape,
|
bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const {
|
||||||
decimal maxDistance) const {
|
|
||||||
|
|
||||||
// Transform the ray direction and origin in local-space coordinates
|
// Transform the ray direction and origin in local-space coordinates
|
||||||
const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform();
|
const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform();
|
||||||
const Transform worldToLocalTransform = localToWorldTransform.getInverse();
|
const Transform worldToLocalTransform = localToWorldTransform.getInverse();
|
||||||
Vector3 origin = worldToLocalTransform * ray.origin;
|
const Vector3 point1 = worldToLocalTransform * ray.point1;
|
||||||
Vector3 r = worldToLocalTransform.getOrientation() * ray.direction.getUnit();
|
const Vector3 point2 = worldToLocalTransform * ray.point2;
|
||||||
|
const Vector3 r = point2 - point1;
|
||||||
|
|
||||||
const decimal epsilon = decimal(0.00001);
|
const decimal epsilon = decimal(0.00001);
|
||||||
Vector3 V(0, mHalfHeight, 0);
|
Vector3 V(0, mHalfHeight, 0);
|
||||||
|
@ -217,7 +115,7 @@ bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pr
|
||||||
decimal heightSquare = decimal(4.0) * mHalfHeight * mHalfHeight;
|
decimal heightSquare = decimal(4.0) * mHalfHeight * mHalfHeight;
|
||||||
decimal cosThetaSquare = heightSquare / (heightSquare + mRadius * mRadius);
|
decimal cosThetaSquare = heightSquare / (heightSquare + mRadius * mRadius);
|
||||||
decimal factor = decimal(1.0) - cosThetaSquare;
|
decimal factor = decimal(1.0) - cosThetaSquare;
|
||||||
Vector3 delta = origin - V;
|
Vector3 delta = point1 - V;
|
||||||
decimal c0 = -cosThetaSquare * delta.x * delta.x + factor * delta.y * delta.y -
|
decimal c0 = -cosThetaSquare * delta.x * delta.x + factor * delta.y * delta.y -
|
||||||
cosThetaSquare * delta.z * delta.z;
|
cosThetaSquare * delta.z * delta.z;
|
||||||
decimal c1 = -cosThetaSquare * delta.x * r.x + factor * delta.y * r.y - cosThetaSquare * delta.z * r.z;
|
decimal c1 = -cosThetaSquare * delta.x * r.x + factor * delta.y * r.y - cosThetaSquare * delta.z * r.z;
|
||||||
|
@ -263,10 +161,10 @@ bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pr
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the origin of the ray is inside the cone, we return no hit
|
// If the origin of the ray is inside the cone, we return no hit
|
||||||
if (testPointInside(origin, NULL)) return false;
|
if (testPointInside(point1, NULL)) return false;
|
||||||
|
|
||||||
localHitPoint[0] = origin + tHit[0] * r;
|
localHitPoint[0] = point1 + tHit[0] * r;
|
||||||
localHitPoint[1] = origin + tHit[1] * r;
|
localHitPoint[1] = point1 + tHit[1] * r;
|
||||||
|
|
||||||
// Only keep hit points in one side of the double cone (the cone we are interested in)
|
// Only keep hit points in one side of the double cone (the cone we are interested in)
|
||||||
if (axis.dot(localHitPoint[0] - V) < decimal(0.0)) {
|
if (axis.dot(localHitPoint[0] - V) < decimal(0.0)) {
|
||||||
|
@ -288,10 +186,10 @@ bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pr
|
||||||
if (r.y > epsilon) {
|
if (r.y > epsilon) {
|
||||||
|
|
||||||
// Compute the intersection with the base plane of the cone
|
// Compute the intersection with the base plane of the cone
|
||||||
tHit[2] = (-origin.y - mHalfHeight) / (r.y);
|
tHit[2] = (-point1.y - mHalfHeight) / (r.y);
|
||||||
|
|
||||||
// Only keep this intersection if it is inside the cone radius
|
// Only keep this intersection if it is inside the cone radius
|
||||||
localHitPoint[2] = origin + tHit[2] * r;
|
localHitPoint[2] = point1 + tHit[2] * r;
|
||||||
|
|
||||||
if ((localHitPoint[2] - centerBase).lengthSquare() > mRadius * mRadius) {
|
if ((localHitPoint[2] - centerBase).lengthSquare() > mRadius * mRadius) {
|
||||||
tHit[2] = decimal(-1.0);
|
tHit[2] = decimal(-1.0);
|
||||||
|
@ -313,7 +211,7 @@ bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pr
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hitIndex < 0) return false;
|
if (hitIndex < 0) return false;
|
||||||
if (t > maxDistance) return false;
|
if (t > ray.maxFraction) return false;
|
||||||
|
|
||||||
// Compute the normal direction for hit against side of the cone
|
// Compute the normal direction for hit against side of the cone
|
||||||
if (hitIndex != 2) {
|
if (hitIndex != 2) {
|
||||||
|
@ -329,7 +227,7 @@ bool ConeShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* pr
|
||||||
|
|
||||||
raycastInfo.body = proxyShape->getBody();
|
raycastInfo.body = proxyShape->getBody();
|
||||||
raycastInfo.proxyShape = proxyShape;
|
raycastInfo.proxyShape = proxyShape;
|
||||||
raycastInfo.distance = t;
|
raycastInfo.hitFraction = t;
|
||||||
raycastInfo.worldPoint = localToWorldTransform * localHitPoint[hitIndex];
|
raycastInfo.worldPoint = localToWorldTransform * localHitPoint[hitIndex];
|
||||||
raycastInfo.worldNormal = localToWorldTransform.getOrientation() * localNormal[hitIndex];
|
raycastInfo.worldNormal = localToWorldTransform.getOrientation() * localNormal[hitIndex];
|
||||||
|
|
||||||
|
|
|
@ -83,12 +83,8 @@ class ConeShape : public CollisionShape {
|
||||||
/// Return true if a point is inside the collision shape
|
/// Return true if a point is inside the collision shape
|
||||||
virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const;
|
virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const;
|
||||||
|
|
||||||
/// Raycast method
|
|
||||||
virtual bool raycast(const Ray& ray, ProxyShape* proxyShape) const;
|
|
||||||
|
|
||||||
/// Raycast method with feedback information
|
/// Raycast method with feedback information
|
||||||
virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape,
|
virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const;
|
||||||
decimal maxDistance = RAYCAST_INFINITY_DISTANCE) const;
|
|
||||||
|
|
||||||
public :
|
public :
|
||||||
|
|
||||||
|
|
|
@ -230,16 +230,8 @@ bool ConvexMeshShape::isEqualTo(const CollisionShape& otherCollisionShape) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raycast method
|
|
||||||
bool ConvexMeshShape::raycast(const Ray& ray, ProxyShape* proxyShape) const {
|
|
||||||
RaycastInfo raycastInfo;
|
|
||||||
return proxyShape->mBody->mWorld.mCollisionDetection.mNarrowPhaseGJKAlgorithm.raycast(
|
|
||||||
ray, proxyShape, raycastInfo, RAYCAST_INFINITY_DISTANCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Raycast method with feedback information
|
// Raycast method with feedback information
|
||||||
bool ConvexMeshShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape,
|
bool ConvexMeshShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const {
|
||||||
decimal distance) const {
|
|
||||||
return proxyShape->mBody->mWorld.mCollisionDetection.mNarrowPhaseGJKAlgorithm.raycast(
|
return proxyShape->mBody->mWorld.mCollisionDetection.mNarrowPhaseGJKAlgorithm.raycast(
|
||||||
ray, proxyShape, raycastInfo, distance);
|
ray, proxyShape, raycastInfo);
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,12 +104,8 @@ class ConvexMeshShape : public CollisionShape {
|
||||||
/// Return true if a point is inside the collision shape
|
/// Return true if a point is inside the collision shape
|
||||||
virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const;
|
virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const;
|
||||||
|
|
||||||
/// Raycast method
|
|
||||||
virtual bool raycast(const Ray& ray, ProxyShape* proxyShape) const;
|
|
||||||
|
|
||||||
/// Raycast method with feedback information
|
/// Raycast method with feedback information
|
||||||
virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape,
|
virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const;
|
||||||
decimal distance = RAYCAST_INFINITY_DISTANCE) const;
|
|
||||||
|
|
||||||
public :
|
public :
|
||||||
|
|
||||||
|
|
|
@ -88,122 +88,37 @@ Vector3 CylinderShape::getLocalSupportPointWithoutMargin(const Vector3& directio
|
||||||
return supportPoint;
|
return supportPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raycast method
|
|
||||||
/// Algorithm based on the one described at page 194 in Real-ime Collision Detection by
|
|
||||||
/// Morgan Kaufmann.
|
|
||||||
bool CylinderShape::raycast(const Ray& ray, ProxyShape* proxyShape) const {
|
|
||||||
|
|
||||||
// Transform the ray direction and origin in local-space coordinates
|
|
||||||
const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform();
|
|
||||||
const Transform worldToLocalTransform = localToWorldTransform.getInverse();
|
|
||||||
Vector3 origin = worldToLocalTransform * ray.origin;
|
|
||||||
Vector3 n = worldToLocalTransform.getOrientation() * ray.direction.getUnit();
|
|
||||||
|
|
||||||
const decimal epsilon = decimal(0.00001);
|
|
||||||
Vector3 p(decimal(0), -mHalfHeight, decimal(0));
|
|
||||||
Vector3 q(decimal(0), mHalfHeight, decimal(0));
|
|
||||||
Vector3 d = q - p;
|
|
||||||
Vector3 m = origin - p;
|
|
||||||
decimal t;
|
|
||||||
|
|
||||||
decimal mDotD = m.dot(d);
|
|
||||||
decimal nDotD = n.dot(d);
|
|
||||||
decimal dDotD = d.dot(d);
|
|
||||||
decimal mDotN = m.dot(n);
|
|
||||||
|
|
||||||
decimal a = dDotD - nDotD * nDotD;
|
|
||||||
decimal k = m.dot(m) - mRadius * mRadius;
|
|
||||||
decimal c = dDotD * k - mDotD * mDotD;
|
|
||||||
|
|
||||||
// If the ray is parallel to the cylinder axis
|
|
||||||
if (std::abs(a) < epsilon) {
|
|
||||||
|
|
||||||
// If the origin is outside the surface of the cylinder, we return no hit
|
|
||||||
if (c > decimal(0.0)) return false;
|
|
||||||
|
|
||||||
// Here we know that the segment intersect an endcap of the cylinder
|
|
||||||
|
|
||||||
// If the ray intersects with the "p" endcap of the cylinder
|
|
||||||
if (mDotD < decimal(0.0)) {
|
|
||||||
|
|
||||||
t = -mDotN;
|
|
||||||
|
|
||||||
return (t >= decimal(0.0));
|
|
||||||
}
|
|
||||||
else if (mDotD > dDotD) { // If the ray intersects with the "q" endcap of the cylinder
|
|
||||||
|
|
||||||
t = (nDotD - mDotN);
|
|
||||||
|
|
||||||
return (t >= decimal(0.0));
|
|
||||||
}
|
|
||||||
else { // If the origin is inside the cylinder, we return no hit
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
decimal b = dDotD * mDotN - nDotD * mDotD;
|
|
||||||
decimal discriminant = b * b - a * c;
|
|
||||||
|
|
||||||
// If the discriminant is negative, no real roots and therfore, no hit
|
|
||||||
if (discriminant < decimal(0.0)) return false;
|
|
||||||
|
|
||||||
// Compute the smallest root (first intersection along the ray)
|
|
||||||
decimal t0 = t = (-b - std::sqrt(discriminant)) / a;
|
|
||||||
|
|
||||||
// If the intersection is outside the cylinder on "p" endcap side
|
|
||||||
decimal value = mDotD + t * nDotD;
|
|
||||||
if (value < decimal(0.0)) {
|
|
||||||
|
|
||||||
// If the ray is pointing away from the "p" endcap, we return no hit
|
|
||||||
if (nDotD <= decimal(0.0)) return false;
|
|
||||||
|
|
||||||
// Compute the intersection against the "p" endcap (intersection agains whole plane)
|
|
||||||
t = -mDotD / nDotD;
|
|
||||||
|
|
||||||
// Keep the intersection if the it is inside the cylinder radius
|
|
||||||
return (t >= decimal(0.0) && k + t * (decimal(2.0) * mDotN + t) <= decimal(0.0));
|
|
||||||
}
|
|
||||||
else if (value > dDotD) { // If the intersection is outside the cylinder on the "q" side
|
|
||||||
|
|
||||||
// If the ray is pointing away from the "q" endcap, we return no hit
|
|
||||||
if (nDotD >= decimal(0.0)) return false;
|
|
||||||
|
|
||||||
// Compute the intersection against the "q" endcap (intersection against whole plane)
|
|
||||||
t = (dDotD - mDotD) / nDotD;
|
|
||||||
|
|
||||||
// Keep the intersection if it is inside the cylinder radius
|
|
||||||
return (t >= decimal(0.0) && k + dDotD - decimal(2.0) * mDotD + t * (decimal(2.0) *
|
|
||||||
(mDotN - nDotD) + t) <= decimal(0.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the intersection is behind the origin of the ray, we return no hit
|
|
||||||
return (t0 >= decimal(0.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Raycast method with feedback information
|
// Raycast method with feedback information
|
||||||
/// Algorithm based on the one described at page 194 in Real-ime Collision Detection by
|
/// Algorithm based on the one described at page 194 in Real-ime Collision Detection by
|
||||||
/// Morgan Kaufmann.
|
/// Morgan Kaufmann.
|
||||||
bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape,
|
bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const {
|
||||||
decimal distance) const {
|
|
||||||
|
|
||||||
// Transform the ray direction and origin in local-space coordinates
|
// Transform the ray direction and origin in local-space coordinates
|
||||||
const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform();
|
const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform();
|
||||||
const Transform worldToLocalTransform = localToWorldTransform.getInverse();
|
const Transform worldToLocalTransform = localToWorldTransform.getInverse();
|
||||||
Vector3 origin = worldToLocalTransform * ray.origin;
|
const Vector3 pointA = worldToLocalTransform * ray.point1;
|
||||||
Vector3 n = worldToLocalTransform.getOrientation() * ray.direction.getUnit();
|
const Vector3 pointB = worldToLocalTransform * ray.point2;
|
||||||
|
const Vector3 n = pointB - pointA;
|
||||||
|
|
||||||
const decimal epsilon = decimal(0.00001);
|
const decimal epsilon = decimal(0.01);
|
||||||
Vector3 p(decimal(0), -mHalfHeight, decimal(0));
|
Vector3 p(decimal(0), -mHalfHeight, decimal(0));
|
||||||
Vector3 q(decimal(0), mHalfHeight, decimal(0));
|
Vector3 q(decimal(0), mHalfHeight, decimal(0));
|
||||||
Vector3 d = q - p;
|
Vector3 d = q - p;
|
||||||
Vector3 m = origin - p;
|
Vector3 m = pointA - p;
|
||||||
decimal t;
|
decimal t;
|
||||||
|
|
||||||
decimal mDotD = m.dot(d);
|
decimal mDotD = m.dot(d);
|
||||||
decimal nDotD = n.dot(d);
|
decimal nDotD = n.dot(d);
|
||||||
decimal dDotD = d.dot(d);
|
decimal dDotD = d.dot(d);
|
||||||
|
|
||||||
|
// Test if the segment is outside the cylinder
|
||||||
|
if (mDotD < decimal(0.0) && mDotD + nDotD < decimal(0.0)) return false;
|
||||||
|
if (mDotD > dDotD && mDotD + nDotD > dDotD) return false;
|
||||||
|
|
||||||
|
decimal nDotN = n.dot(n);
|
||||||
decimal mDotN = m.dot(n);
|
decimal mDotN = m.dot(n);
|
||||||
|
|
||||||
decimal a = dDotD - nDotD * nDotD;
|
decimal a = dDotD * nDotN - nDotD * nDotD;
|
||||||
decimal k = m.dot(m) - mRadius * mRadius;
|
decimal k = m.dot(m) - mRadius * mRadius;
|
||||||
decimal c = dDotD * k - mDotD * mDotD;
|
decimal c = dDotD * k - mDotD * mDotD;
|
||||||
|
|
||||||
|
@ -218,17 +133,17 @@ bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape
|
||||||
// If the ray intersects with the "p" endcap of the cylinder
|
// If the ray intersects with the "p" endcap of the cylinder
|
||||||
if (mDotD < decimal(0.0)) {
|
if (mDotD < decimal(0.0)) {
|
||||||
|
|
||||||
t = -mDotN;
|
t = -mDotN / nDotN;
|
||||||
|
|
||||||
// If the intersection is behind the origin of the ray or beyond the maximum
|
// If the intersection is behind the origin of the ray or beyond the maximum
|
||||||
// raycasting distance, we return no hit
|
// raycasting distance, we return no hit
|
||||||
if (t < decimal(0.0) || t > distance) return false;
|
if (t < decimal(0.0) || t > ray.maxFraction) return false;
|
||||||
|
|
||||||
// Compute the hit information
|
// Compute the hit information
|
||||||
Vector3 localHitPoint = origin + t * n;
|
Vector3 localHitPoint = pointA + t * n;
|
||||||
raycastInfo.body = proxyShape->getBody();
|
raycastInfo.body = proxyShape->getBody();
|
||||||
raycastInfo.proxyShape = proxyShape;
|
raycastInfo.proxyShape = proxyShape;
|
||||||
raycastInfo.distance = t;
|
raycastInfo.hitFraction = t;
|
||||||
raycastInfo.worldPoint = localToWorldTransform * localHitPoint;
|
raycastInfo.worldPoint = localToWorldTransform * localHitPoint;
|
||||||
Vector3 normalDirection(0, decimal(-1), 0);
|
Vector3 normalDirection(0, decimal(-1), 0);
|
||||||
raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection;
|
raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection;
|
||||||
|
@ -237,17 +152,17 @@ bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape
|
||||||
}
|
}
|
||||||
else if (mDotD > dDotD) { // If the ray intersects with the "q" endcap of the cylinder
|
else if (mDotD > dDotD) { // If the ray intersects with the "q" endcap of the cylinder
|
||||||
|
|
||||||
t = (nDotD - mDotN);
|
t = (nDotD - mDotN) / nDotN;
|
||||||
|
|
||||||
// If the intersection is behind the origin of the ray or beyond the maximum
|
// If the intersection is behind the origin of the ray or beyond the maximum
|
||||||
// raycasting distance, we return no hit
|
// raycasting distance, we return no hit
|
||||||
if (t < decimal(0.0) || t > distance) return false;
|
if (t < decimal(0.0) || t > ray.maxFraction) return false;
|
||||||
|
|
||||||
// Compute the hit information
|
// Compute the hit information
|
||||||
Vector3 localHitPoint = origin + t * n;
|
Vector3 localHitPoint = pointA + t * n;
|
||||||
raycastInfo.body = proxyShape->getBody();
|
raycastInfo.body = proxyShape->getBody();
|
||||||
raycastInfo.proxyShape = proxyShape;
|
raycastInfo.proxyShape = proxyShape;
|
||||||
raycastInfo.distance = t;
|
raycastInfo.hitFraction = t;
|
||||||
raycastInfo.worldPoint = localToWorldTransform * localHitPoint;
|
raycastInfo.worldPoint = localToWorldTransform * localHitPoint;
|
||||||
Vector3 normalDirection(0, decimal(1.0), 0);
|
Vector3 normalDirection(0, decimal(1.0), 0);
|
||||||
raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection;
|
raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection;
|
||||||
|
@ -282,13 +197,13 @@ bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape
|
||||||
|
|
||||||
// If the intersection is behind the origin of the ray or beyond the maximum
|
// If the intersection is behind the origin of the ray or beyond the maximum
|
||||||
// raycasting distance, we return no hit
|
// raycasting distance, we return no hit
|
||||||
if (t < decimal(0.0) || t > distance) return false;
|
if (t < decimal(0.0) || t > ray.maxFraction) return false;
|
||||||
|
|
||||||
// Compute the hit information
|
// Compute the hit information
|
||||||
Vector3 localHitPoint = origin + t * n;
|
Vector3 localHitPoint = pointA + t * n;
|
||||||
raycastInfo.body = proxyShape->getBody();
|
raycastInfo.body = proxyShape->getBody();
|
||||||
raycastInfo.proxyShape = proxyShape;
|
raycastInfo.proxyShape = proxyShape;
|
||||||
raycastInfo.distance = t;
|
raycastInfo.hitFraction = t;
|
||||||
raycastInfo.worldPoint = localToWorldTransform * localHitPoint;
|
raycastInfo.worldPoint = localToWorldTransform * localHitPoint;
|
||||||
Vector3 normalDirection(0, decimal(-1.0), 0);
|
Vector3 normalDirection(0, decimal(-1.0), 0);
|
||||||
raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection;
|
raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection;
|
||||||
|
@ -309,13 +224,13 @@ bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape
|
||||||
|
|
||||||
// If the intersection is behind the origin of the ray or beyond the maximum
|
// If the intersection is behind the origin of the ray or beyond the maximum
|
||||||
// raycasting distance, we return no hit
|
// raycasting distance, we return no hit
|
||||||
if (t < decimal(0.0) || t > distance) return false;
|
if (t < decimal(0.0) || t > ray.maxFraction) return false;
|
||||||
|
|
||||||
// Compute the hit information
|
// Compute the hit information
|
||||||
Vector3 localHitPoint = origin + t * n;
|
Vector3 localHitPoint = pointA + t * n;
|
||||||
raycastInfo.body = proxyShape->getBody();
|
raycastInfo.body = proxyShape->getBody();
|
||||||
raycastInfo.proxyShape = proxyShape;
|
raycastInfo.proxyShape = proxyShape;
|
||||||
raycastInfo.distance = t;
|
raycastInfo.hitFraction = t;
|
||||||
raycastInfo.worldPoint = localToWorldTransform * localHitPoint;
|
raycastInfo.worldPoint = localToWorldTransform * localHitPoint;
|
||||||
Vector3 normalDirection(0, decimal(1.0), 0);
|
Vector3 normalDirection(0, decimal(1.0), 0);
|
||||||
raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection;
|
raycastInfo.worldNormal = localToWorldTransform.getOrientation() * normalDirection;
|
||||||
|
@ -327,13 +242,13 @@ bool CylinderShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape
|
||||||
|
|
||||||
// If the intersection is behind the origin of the ray or beyond the maximum
|
// If the intersection is behind the origin of the ray or beyond the maximum
|
||||||
// raycasting distance, we return no hit
|
// raycasting distance, we return no hit
|
||||||
if (t < decimal(0.0) || t > distance) return false;
|
if (t < decimal(0.0) || t > ray.maxFraction) return false;
|
||||||
|
|
||||||
// Compute the hit information
|
// Compute the hit information
|
||||||
Vector3 localHitPoint = origin + t * n;
|
Vector3 localHitPoint = pointA + t * n;
|
||||||
raycastInfo.body = proxyShape->getBody();
|
raycastInfo.body = proxyShape->getBody();
|
||||||
raycastInfo.proxyShape = proxyShape;
|
raycastInfo.proxyShape = proxyShape;
|
||||||
raycastInfo.distance = t;
|
raycastInfo.hitFraction = t;
|
||||||
raycastInfo.worldPoint = localToWorldTransform * localHitPoint;
|
raycastInfo.worldPoint = localToWorldTransform * localHitPoint;
|
||||||
Vector3 v = localHitPoint - p;
|
Vector3 v = localHitPoint - p;
|
||||||
Vector3 w = (v.dot(d) / d.lengthSquare()) * d;
|
Vector3 w = (v.dot(d) / d.lengthSquare()) * d;
|
||||||
|
|
|
@ -80,12 +80,8 @@ class CylinderShape : public CollisionShape {
|
||||||
/// Return true if a point is inside the collision shape
|
/// Return true if a point is inside the collision shape
|
||||||
virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const;
|
virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const;
|
||||||
|
|
||||||
/// Raycast method
|
|
||||||
virtual bool raycast(const Ray& ray, ProxyShape* proxyShape) const;
|
|
||||||
|
|
||||||
/// Raycast method with feedback information
|
/// Raycast method with feedback information
|
||||||
virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape,
|
virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const;
|
||||||
decimal distance = RAYCAST_INFINITY_DISTANCE) const;
|
|
||||||
|
|
||||||
public :
|
public :
|
||||||
|
|
||||||
|
|
|
@ -47,72 +47,51 @@ SphereShape::~SphereShape() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raycast method
|
|
||||||
bool SphereShape::raycast(const Ray& ray, ProxyShape* proxyShape) const {
|
|
||||||
|
|
||||||
const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform();
|
|
||||||
const Transform worldToLocalTransform = localToWorldTransform.getInverse();
|
|
||||||
Vector3 origin = worldToLocalTransform * ray.origin;
|
|
||||||
decimal c = origin.dot(origin) - mRadius * mRadius;
|
|
||||||
|
|
||||||
// If the origin of the ray is inside the sphere, we return no intersection
|
|
||||||
if (c < decimal(0.0)) return false;
|
|
||||||
|
|
||||||
Vector3 rayDirection = worldToLocalTransform.getOrientation() * ray.direction.getUnit();
|
|
||||||
decimal b = origin.dot(rayDirection);
|
|
||||||
|
|
||||||
// If the origin of the ray is outside the sphere and the ray
|
|
||||||
// is pointing away from the sphere and there is no intersection
|
|
||||||
if (c >= decimal(0.0) && b > decimal(0.0)) return false;
|
|
||||||
|
|
||||||
// Compute the discriminant of the quadratic equation
|
|
||||||
decimal discriminant = b*b - c;
|
|
||||||
|
|
||||||
// If the discriminant is negative, there is no intersection
|
|
||||||
return (discriminant >= decimal(0.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Raycast method with feedback information
|
// Raycast method with feedback information
|
||||||
bool SphereShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape,
|
bool SphereShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const {
|
||||||
decimal distance) const {
|
|
||||||
|
|
||||||
const Transform localToWorldTransform = proxyShape->getLocalToWorldTransform();
|
// We perform the intersection test in world-space
|
||||||
const Transform worldToLocalTransform = localToWorldTransform.getInverse();
|
|
||||||
Vector3 origin = worldToLocalTransform * ray.origin;
|
const Vector3 sphereCenter = proxyShape->getLocalToWorldTransform().getPosition();
|
||||||
decimal c = origin.dot(origin) - mRadius * mRadius;
|
const Vector3 m = ray.point1 - sphereCenter;
|
||||||
|
decimal c = m.dot(m) - mRadius * mRadius;
|
||||||
|
|
||||||
// If the origin of the ray is inside the sphere, we return no intersection
|
// If the origin of the ray is inside the sphere, we return no intersection
|
||||||
if (c < decimal(0.0)) return false;
|
if (c < decimal(0.0)) return false;
|
||||||
|
|
||||||
Vector3 rayDirection = worldToLocalTransform.getOrientation() * ray.direction.getUnit();
|
const Vector3 rayDirection = ray.point2 - ray.point1;
|
||||||
decimal b = origin.dot(rayDirection);
|
decimal b = m.dot(rayDirection);
|
||||||
|
|
||||||
// If the origin of the ray is outside the sphere and the ray
|
// If the origin of the ray is outside the sphere and the ray
|
||||||
// is pointing away from the sphere and there is no intersection
|
// is pointing away from the sphere, there is no intersection
|
||||||
if (c >= decimal(0.0) && b > decimal(0.0)) return false;
|
if (b > decimal(0.0)) return false;
|
||||||
|
|
||||||
|
decimal raySquareLength = rayDirection.lengthSquare();
|
||||||
|
|
||||||
// Compute the discriminant of the quadratic equation
|
// Compute the discriminant of the quadratic equation
|
||||||
decimal discriminant = b*b - c;
|
decimal discriminant = b * b - raySquareLength * c;
|
||||||
|
|
||||||
// If the discriminant is negative, there is no intersection
|
// If the discriminant is negative or the ray length is very small, there is no intersection
|
||||||
if (discriminant < decimal(0.0)) return false;
|
if (discriminant < decimal(0.0) || raySquareLength < MACHINE_EPSILON) return false;
|
||||||
|
|
||||||
// Compute the solution "t" closest to the origin
|
// Compute the solution "t" closest to the origin
|
||||||
decimal t = -b - std::sqrt(discriminant);
|
decimal t = -b - std::sqrt(discriminant);
|
||||||
|
|
||||||
assert(t >= decimal(0.0));
|
assert(t >= decimal(0.0));
|
||||||
|
|
||||||
// If the intersection distance is larger than the allowed distance, return no intersection
|
// If the hit point is withing the segment ray fraction
|
||||||
if (t > distance) return false;
|
if (t < ray.maxFraction * raySquareLength) {
|
||||||
|
|
||||||
// Compute the intersection information
|
// Compute the intersection information
|
||||||
Vector3 localPoint = origin + t * rayDirection;
|
t /= raySquareLength;
|
||||||
raycastInfo.body = proxyShape->getBody();
|
raycastInfo.body = proxyShape->getBody();
|
||||||
raycastInfo.proxyShape = proxyShape;
|
raycastInfo.proxyShape = proxyShape;
|
||||||
raycastInfo.distance = t;
|
raycastInfo.hitFraction = t;
|
||||||
raycastInfo.worldPoint = localToWorldTransform * localPoint;
|
raycastInfo.worldPoint = ray.point1 + t * rayDirection;
|
||||||
raycastInfo.worldNormal = (raycastInfo.worldPoint -
|
raycastInfo.worldNormal = (raycastInfo.worldPoint - sphereCenter).getUnit();
|
||||||
localToWorldTransform.getPosition()).getUnit();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,12 +70,8 @@ class SphereShape : public CollisionShape {
|
||||||
/// Return true if a point is inside the collision shape
|
/// Return true if a point is inside the collision shape
|
||||||
virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const;
|
virtual bool testPointInside(const Vector3& localPoint, ProxyShape* proxyShape) const;
|
||||||
|
|
||||||
/// Raycast method
|
|
||||||
virtual bool raycast(const Ray& ray, ProxyShape* proxyShape) const;
|
|
||||||
|
|
||||||
/// Raycast method with feedback information
|
/// Raycast method with feedback information
|
||||||
virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape,
|
virtual bool raycast(const Ray& ray, RaycastInfo& raycastInfo, ProxyShape* proxyShape) const;
|
||||||
decimal distance = RAYCAST_INFINITY_DISTANCE) const;
|
|
||||||
|
|
||||||
public :
|
public :
|
||||||
|
|
||||||
|
|
|
@ -131,9 +131,6 @@ const decimal DYNAMIC_TREE_AABB_GAP = decimal(0.1);
|
||||||
/// followin constant with the linear velocity and the elapsed time between two frames.
|
/// followin constant with the linear velocity and the elapsed time between two frames.
|
||||||
const decimal DYNAMIC_TREE_AABB_LIN_GAP_MULTIPLIER = decimal(1.7);
|
const decimal DYNAMIC_TREE_AABB_LIN_GAP_MULTIPLIER = decimal(1.7);
|
||||||
|
|
||||||
/// Raycasting infinity distance constant
|
|
||||||
const decimal RAYCAST_INFINITY_DISTANCE = std::numeric_limits<decimal>::infinity();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -166,14 +166,8 @@ void CollisionWorld::removeCollisionShape(CollisionShape* collisionShape) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Raycast method
|
|
||||||
bool CollisionWorld::raycast(const Ray& ray, decimal distance) {
|
|
||||||
// TODO : Implement this method
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Raycast method with feedback information
|
/// Raycast method with feedback information
|
||||||
bool CollisionWorld::raycast(const Ray& ray, RaycastInfo& raycastInfo, decimal distance) {
|
bool CollisionWorld::raycast(const Ray& ray, RaycastInfo& raycastInfo) {
|
||||||
// TODO : Implement this method
|
// TODO : Implement this method
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,12 +120,8 @@ class CollisionWorld {
|
||||||
/// Destroy a collision body
|
/// Destroy a collision body
|
||||||
void destroyCollisionBody(CollisionBody* collisionBody);
|
void destroyCollisionBody(CollisionBody* collisionBody);
|
||||||
|
|
||||||
/// Raycast method
|
|
||||||
bool raycast(const Ray& ray, decimal distance = RAYCAST_INFINITY_DISTANCE);
|
|
||||||
|
|
||||||
/// Raycast method with feedback information
|
/// Raycast method with feedback information
|
||||||
bool raycast(const Ray& ray, RaycastInfo& raycastInfo,
|
bool raycast(const Ray& ray, RaycastInfo& raycastInfo);
|
||||||
decimal distance = RAYCAST_INFINITY_DISTANCE);
|
|
||||||
|
|
||||||
// -------------------- Friendship -------------------- //
|
// -------------------- Friendship -------------------- //
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,9 @@ namespace reactphysics3d {
|
||||||
|
|
||||||
// Class Ray
|
// Class Ray
|
||||||
/**
|
/**
|
||||||
* This structure represents a 3D ray with a origin point and a direction.
|
* This structure represents a 3D ray represented by two points.
|
||||||
|
* The ray goes from point1 to point1 + maxFraction * (point2 - point1).
|
||||||
|
* The points are specified in world-space coordinates.
|
||||||
*/
|
*/
|
||||||
struct Ray {
|
struct Ray {
|
||||||
|
|
||||||
|
@ -42,22 +44,25 @@ struct Ray {
|
||||||
|
|
||||||
// -------------------- Attributes -------------------- //
|
// -------------------- Attributes -------------------- //
|
||||||
|
|
||||||
/// Origin point of the ray
|
/// First point of the ray (origin)
|
||||||
Vector3 origin;
|
Vector3 point1;
|
||||||
|
|
||||||
/// Direction vector of the ray
|
/// Second point of the ray
|
||||||
Vector3 direction;
|
Vector3 point2;
|
||||||
|
|
||||||
|
/// Maximum fraction value
|
||||||
|
decimal maxFraction;
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
/// Constructor with arguments
|
/// Constructor with arguments
|
||||||
Ray(const Vector3& originPoint, const Vector3& directionVector)
|
Ray(const Vector3& p1, const Vector3& p2, decimal maxFrac = decimal(1.0))
|
||||||
: origin(originPoint), direction(directionVector) {
|
: point1(p1), point2(p2), maxFraction(maxFrac) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copy-constructor
|
/// Copy-constructor
|
||||||
Ray(const Ray& ray) : origin(ray.origin), direction(ray.direction) {
|
Ray(const Ray& ray) : point1(ray.point1), point2(ray.point2), maxFraction(ray.maxFraction) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,8 +74,9 @@ struct Ray {
|
||||||
/// Overloaded assignment operator
|
/// Overloaded assignment operator
|
||||||
Ray& operator=(const Ray& ray) {
|
Ray& operator=(const Ray& ray) {
|
||||||
if (&ray != this) {
|
if (&ray != this) {
|
||||||
origin = ray.origin;
|
point1 = ray.point1;
|
||||||
direction = ray.direction;
|
point2 = ray.point2;
|
||||||
|
maxFraction = ray.maxFraction;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "Vector3.h"
|
#include "Vector3.h"
|
||||||
#include "Vector2.h"
|
#include "Vector2.h"
|
||||||
#include "Transform.h"
|
#include "Transform.h"
|
||||||
|
#include "Ray.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "mathematics_functions.h"
|
#include "mathematics_functions.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
|
@ -51,6 +51,8 @@
|
||||||
#include "collision/shapes/CapsuleShape.h"
|
#include "collision/shapes/CapsuleShape.h"
|
||||||
#include "collision/shapes/ConvexMeshShape.h"
|
#include "collision/shapes/ConvexMeshShape.h"
|
||||||
#include "collision/shapes/AABB.h"
|
#include "collision/shapes/AABB.h"
|
||||||
|
#include "collision/ProxyShape.h"
|
||||||
|
#include "collision/RaycastInfo.h"
|
||||||
#include "constraint/BallAndSocketJoint.h"
|
#include "constraint/BallAndSocketJoint.h"
|
||||||
#include "constraint/SliderJoint.h"
|
#include "constraint/SliderJoint.h"
|
||||||
#include "constraint/HingeJoint.h"
|
#include "constraint/HingeJoint.h"
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user