Fix issue and modifications in HeightFieldShape

This commit is contained in:
Daniel Chappuis 2020-12-31 16:41:05 +01:00
parent a8d2478a7e
commit bacdf23f8b
3 changed files with 108 additions and 138 deletions

View File

@ -110,6 +110,9 @@ class TriangleShape : public ConvexPolyhedronShape {
TriangleShape(const Vector3* vertices, const Vector3* verticesNormals, uint shapeId, HalfEdgeStructure& triangleHalfEdgeStructure,
MemoryAllocator& allocator);
/// Constructor
TriangleShape(const Vector3* vertices, uint shapeId, HalfEdgeStructure& triangleHalfEdgeStructure, MemoryAllocator& allocator);
/// Destructor
virtual ~TriangleShape() override = default;
@ -262,6 +265,7 @@ RP3D_FORCE_INLINE Vector3 TriangleShape::getVertexPosition(uint vertexIndex) con
// Return the normal vector of a given face of the polyhedron
RP3D_FORCE_INLINE Vector3 TriangleShape::getFaceNormal(uint faceIndex) const {
assert(faceIndex < 2);
assert(mNormal.length() > decimal(0.0));
return faceIndex == 0 ? mNormal : -mNormal;
}
@ -311,6 +315,8 @@ RP3D_FORCE_INLINE decimal TriangleShape::getVolume() const {
/// middle of the triangle, we return the true triangle normal.
RP3D_FORCE_INLINE Vector3 TriangleShape::computeSmoothLocalContactNormalForTriangle(const Vector3& localContactPoint) const {
assert(mNormal.length() > decimal(0.0));
// Compute the barycentric coordinates of the point in the triangle
decimal u, v, w;
computeBarycentricCoordinatesInTriangle(mPoints[0], mPoints[1], mPoints[2], localContactPoint, u, v, w);

View File

@ -238,11 +238,12 @@ bool HeightFieldShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, Collide
const Vector3 inverseScale(decimal(1.0) / mScale.x, decimal(1.0) / mScale.y, decimal(1.0) / mScale.z);
Ray scaledRay(ray.point1 * inverseScale, ray.point2 * inverseScale, ray.maxFraction);
bool isHit = false;
// Compute the grid coordinates where the ray is entering the AABB of the height field
int i, j;
Vector3 outHitGridPoint;
bool isIntersecting = computeEnteringRayGridCoordinates(scaledRay, i, j, outHitGridPoint);
assert(isIntersecting);
if (computeEnteringRayGridCoordinates(scaledRay, i, j, outHitGridPoint)) {
const int nbCellsI = mNbColumns - 1;
const int nbCellsJ = mNbRows - 1;
@ -290,7 +291,6 @@ bool HeightFieldShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, Collide
break;
}
bool isHit = false;
decimal smallestHitFraction = ray.maxFraction;
while (i >= 0 && i < nbCellsI && j >= 0 && j < nbCellsJ) {
@ -323,46 +323,7 @@ bool HeightFieldShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, Collide
j += stepJ;
}
}
/*
// For each overlapping triangle
const uint32 nbShapeIds = shapeIds.size();
for (uint32 i=0; i < nbShapeIds; i++)
{
// Create a triangle collision shape
TriangleShape triangleShape(&(triangleVertices[i * 3]), &(triangleVerticesNormals[i * 3]), shapeIds[i], mTriangleHalfEdgeStructure, allocator);
triangleShape.setRaycastTestType(getRaycastTestType());
#ifdef IS_RP3D_PROFILING_ENABLED
// Set the profiler to the triangle shape
triangleShape.setProfiler(mProfiler);
#endif
// Ray casting test against the collision shape
RaycastInfo triangleRaycastInfo;
bool isTriangleHit = triangleShape.raycast(ray, triangleRaycastInfo, collider, allocator);
// If the ray hit the collision shape
if (isTriangleHit && triangleRaycastInfo.hitFraction <= smallestHitFraction) {
assert(triangleRaycastInfo.hitFraction >= decimal(0.0));
raycastInfo.body = triangleRaycastInfo.body;
raycastInfo.collider = triangleRaycastInfo.collider;
raycastInfo.hitFraction = triangleRaycastInfo.hitFraction;
raycastInfo.worldPoint = triangleRaycastInfo.worldPoint;
raycastInfo.worldNormal = triangleRaycastInfo.worldNormal;
raycastInfo.meshSubpart = -1;
raycastInfo.triangleIndex = -1;
smallestHitFraction = triangleRaycastInfo.hitFraction;
isHit = true;
}
}
*/
return isHit;
}
@ -374,20 +335,8 @@ bool HeightFieldShape::raycastTriangle(const Ray& ray, const Vector3& p1, const
// Generate the first triangle for the current grid rectangle
Vector3 triangleVertices[3] = {p1, p2, p3};
// Compute the triangle normal
Vector3 triangleNormal = (p2 - p1).cross(p3 - p1).getUnit();
// Use the triangle face normal as vertices normals (this is an aproximation. The correct
// solution would be to compute all the normals of the neighbor triangles and use their
// weighted average (with incident angle as weight) at the vertices. However, this solution
// seems too expensive (it requires to compute the normal of all neighbor triangles instead
// and compute the angle of incident edges with asin(). Maybe we could also precompute the
// vertices normal at the HeightFieldShape constructor but it will require extra memory to
// store them.
Vector3 triangleVerticesNormals[3] = {triangleNormal, triangleNormal, triangleNormal};
// Create a triangle collision shape
TriangleShape triangleShape(triangleVertices, triangleVerticesNormals, shapeId, mTriangleHalfEdgeStructure, allocator);
TriangleShape triangleShape(triangleVertices, shapeId, mTriangleHalfEdgeStructure, allocator);
triangleShape.setRaycastTestType(getRaycastTestType());
#ifdef IS_RP3D_PROFILING_ENABLED

View File

@ -37,15 +37,6 @@ using namespace reactphysics3d;
// Constructor
/**
* Do not use this constructor. It is supposed to be used internally only.
* Use a ConcaveMeshShape instead.
* @param point1 First point of the triangle
* @param point2 Second point of the triangle
* @param point3 Third point of the triangle
* @param verticesNormals The three vertices normals for smooth mesh collision
* @param margin The collision margin (in meters) around the collision shape
*/
TriangleShape::TriangleShape(const Vector3* vertices, const Vector3* verticesNormals, uint shapeId, HalfEdgeStructure& triangleHalfEdgeStructure, MemoryAllocator& allocator)
: ConvexPolyhedronShape(CollisionShapeName::TRIANGLE, allocator), mTriangleHalfEdgeStructure(triangleHalfEdgeStructure) {
@ -66,6 +57,27 @@ TriangleShape::TriangleShape(const Vector3* vertices, const Vector3* verticesNor
mId = shapeId;
}
// Constructor for raycasting
TriangleShape::TriangleShape(const Vector3* vertices, uint shapeId, HalfEdgeStructure& triangleHalfEdgeStructure, MemoryAllocator& allocator)
: ConvexPolyhedronShape(CollisionShapeName::TRIANGLE, allocator), mTriangleHalfEdgeStructure(triangleHalfEdgeStructure) {
mPoints[0] = vertices[0];
mPoints[1] = vertices[1];
mPoints[2] = vertices[2];
// The normal is not used when creating the triangle shape with this constructor (for raycasting for instance)
mNormal = Vector3(0, 0, 0);
// Interpolated normals are not used in this constructor (for raycasting for instance)
mVerticesNormals[0] = mNormal;
mVerticesNormals[1] = mNormal;
mVerticesNormals[2] = mNormal;
mRaycastTestType = TriangleRaycastSide::FRONT;
mId = shapeId;
}
// This method implements the technique described in Game Physics Pearl book
// by Gino van der Bergen and Dirk Gregorius to get smooth triangle mesh collision. The idea is
// to replace the contact normal of the triangle shape with the precomputed normal of the triangle
@ -182,13 +194,16 @@ bool TriangleShape::raycast(const Ray& ray, RaycastInfo& raycastInfo, Collider*
if (hitFraction < decimal(0.0) || hitFraction > ray.maxFraction) return false;
Vector3 localHitNormal = mNormal.dot(pq) > decimal(0.0) ? -mNormal : mNormal;
// Compute the triangle face normal
Vector3 normal = (mPoints[1] - mPoints[0]).cross(mPoints[2] - mPoints[0]);
normal.normalize();
normal = normal.dot(pq) > decimal(0.0) ? -normal : normal;
raycastInfo.body = collider->getBody();
raycastInfo.collider = collider;
raycastInfo.worldPoint = localHitPoint;
raycastInfo.hitFraction = hitFraction;
raycastInfo.worldNormal = localHitNormal;
raycastInfo.worldNormal = normal;
return true;
}