164 lines
5.3 KiB
C++
164 lines
5.3 KiB
C++
/** @file
|
|
* Original ReactPhysics3D C++ library by Daniel Chappuis <http://www.reactphysics3d.com/> This code is re-licensed with permission from ReactPhysics3D author.
|
|
* @author Daniel CHAPPUIS
|
|
* @author Edouard DUPIN
|
|
* @copyright 2010-2016, Daniel Chappuis
|
|
* @copyright 2017, Edouard DUPIN
|
|
* @license MPL v2.0 (see license file)
|
|
*/
|
|
#include <ephysics/collision/shapes/TriangleShape.hpp>
|
|
#include <ephysics/collision/ProxyShape.hpp>
|
|
#include <ephysics/engine/Profiler.hpp>
|
|
#include <ephysics/configuration.hpp>
|
|
|
|
// TODO: REMOVE this...
|
|
using namespace ephysics;
|
|
|
|
TriangleShape::TriangleShape( Vector3f point1, Vector3f point2, Vector3f point3, float margin)
|
|
: ConvexShape(TRIANGLE, margin) {
|
|
this.points[0] = point1;
|
|
this.points[1] = point2;
|
|
this.points[2] = point3;
|
|
this.raycastTestType = FRONT;
|
|
}
|
|
|
|
boolean TriangleShape::raycast( Ray ray, RaycastInfo raycastInfo, ProxyShape* proxyShape) {
|
|
PROFILE("TriangleShape::raycast()");
|
|
Vector3f pq = ray.point2 - ray.point1;
|
|
Vector3f pa = this.points[0] - ray.point1;
|
|
Vector3f pb = this.points[1] - ray.point1;
|
|
Vector3f pc = this.points[2] - ray.point1;
|
|
// Test if the line PQ is inside the eges BC, CA and AB. We use the triple
|
|
// product for this test.
|
|
Vector3f m = pq.cross(pc);
|
|
float u = pb.dot(m);
|
|
if (this.raycastTestType == FRONT) {
|
|
if (u < 0.0f) {
|
|
return false;
|
|
}
|
|
} else if (this.raycastTestType == BACK) {
|
|
if (u > 0.0f) {
|
|
return false;
|
|
}
|
|
}
|
|
float v = -pa.dot(m);
|
|
if (this.raycastTestType == FRONT) {
|
|
if (v < 0.0f) {
|
|
return false;
|
|
}
|
|
} else if (this.raycastTestType == BACK) {
|
|
if (v > 0.0f) {
|
|
return false;
|
|
}
|
|
} else if (this.raycastTestType == FRONTANDBACK) {
|
|
if (!sameSign(u, v)) {
|
|
return false;
|
|
}
|
|
}
|
|
float w = pa.dot(pq.cross(pb));
|
|
if (this.raycastTestType == FRONT) {
|
|
if (w < 0.0f) {
|
|
return false;
|
|
}
|
|
} else if (this.raycastTestType == BACK) {
|
|
if (w > 0.0f) {
|
|
return false;
|
|
}
|
|
} else if (this.raycastTestType == FRONTANDBACK) {
|
|
if (!sameSign(u, w)) {
|
|
return false;
|
|
}
|
|
}
|
|
// If the line PQ is in the triangle plane (case where u=v=w=0)
|
|
if ( approxEqual(u, 0)
|
|
&& approxEqual(v, 0)
|
|
&& approxEqual(w, 0)) {
|
|
return false;
|
|
}
|
|
// Compute the barycentric coordinates (u, v, w) to determine the
|
|
// intersection point R, R = u * a + v * b + w * c
|
|
float denom = 1.0f / (u + v + w);
|
|
u *= denom;
|
|
v *= denom;
|
|
w *= denom;
|
|
// Compute the local hit point using the barycentric coordinates
|
|
Vector3f localHitPoint = u * this.points[0] + v * this.points[1] + w * this.points[2];
|
|
float hitFraction = (localHitPoint - ray.point1).length() / pq.length();
|
|
if ( hitFraction < 0.0f
|
|
|| hitFraction > ray.maxFraction) {
|
|
return false;
|
|
}
|
|
Vector3f localHitNormal = (this.points[1] - this.points[0]).cross(this.points[2] - this.points[0]);
|
|
if (localHitNormal.dot(pq) > 0.0f) {
|
|
localHitNormal = -localHitNormal;
|
|
}
|
|
raycastInfo.body = proxyShape.getBody();
|
|
raycastInfo.proxyShape = proxyShape;
|
|
raycastInfo.worldPoint = localHitPoint;
|
|
raycastInfo.hitFraction = hitFraction;
|
|
raycastInfo.worldNormal = localHitNormal;
|
|
return true;
|
|
}
|
|
|
|
long TriangleShape::getSizeInBytes() {
|
|
return sizeof(TriangleShape);
|
|
}
|
|
|
|
Vector3f TriangleShape::getLocalSupportPointWithoutMargin( Vector3f direction,
|
|
void** cachedCollisionData) {
|
|
Vector3f dotProducts(direction.dot(this.points[0]), direction.dot(this.points[1]), direction.dot(this.points[2]));
|
|
return this.points[dotProducts.getMaxAxis()];
|
|
}
|
|
|
|
void TriangleShape::getLocalBounds(Vector3f min, Vector3f max) {
|
|
Vector3f xAxis(this.points[0].x(), this.points[1].x(), this.points[2].x());
|
|
Vector3f yAxis(this.points[0].y(), this.points[1].y(), this.points[2].y());
|
|
Vector3f zAxis(this.points[0].z(), this.points[1].z(), this.points[2].z());
|
|
min.setValue(xAxis.getMin(), yAxis.getMin(), zAxis.getMin());
|
|
max.setValue(xAxis.getMax(), yAxis.getMax(), zAxis.getMax());
|
|
min -= Vector3f(this.margin, this.margin, this.margin);
|
|
max += Vector3f(this.margin, this.margin, this.margin);
|
|
}
|
|
|
|
void TriangleShape::setLocalScaling( Vector3f scaling) {
|
|
this.points[0] = (this.points[0] / this.scaling) * scaling;
|
|
this.points[1] = (this.points[1] / this.scaling) * scaling;
|
|
this.points[2] = (this.points[2] / this.scaling) * scaling;
|
|
CollisionShape::setLocalScaling(scaling);
|
|
}
|
|
|
|
void TriangleShape::computeLocalInertiaTensor(Matrix3f tensor, float mass) {
|
|
tensor.setZero();
|
|
}
|
|
|
|
void TriangleShape::computeAABB(AABB aabb, Transform3D transform) {
|
|
Vector3f worldPoint1 = transform * this.points[0];
|
|
Vector3f worldPoint2 = transform * this.points[1];
|
|
Vector3f worldPoint3 = transform * this.points[2];
|
|
Vector3f xAxis(worldPoint1.x(), worldPoint2.x(), worldPoint3.x());
|
|
Vector3f yAxis(worldPoint1.y(), worldPoint2.y(), worldPoint3.y());
|
|
Vector3f zAxis(worldPoint1.z(), worldPoint2.z(), worldPoint3.z());
|
|
aabb.setMin(Vector3f(xAxis.getMin(), yAxis.getMin(), zAxis.getMin()));
|
|
aabb.setMax(Vector3f(xAxis.getMax(), yAxis.getMax(), zAxis.getMax()));
|
|
}
|
|
|
|
boolean TriangleShape::testPointInside( Vector3f localPoint, ProxyShape* proxyShape) {
|
|
return false;
|
|
}
|
|
|
|
TriangleRaycastSide TriangleShape::getRaycastTestType() {
|
|
return this.raycastTestType;
|
|
}
|
|
|
|
|
|
void TriangleShape::setRaycastTestType(TriangleRaycastSide testType) {
|
|
this.raycastTestType = testType;
|
|
}
|
|
|
|
Vector3f TriangleShape::getVertex(int index) {
|
|
assert( index >= 0
|
|
&& index < 3);
|
|
return this.points[index];
|
|
}
|
|
|