aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/LowLevelParticles/src/PtCollisionMesh.cpp
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Source/LowLevelParticles/src/PtCollisionMesh.cpp
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'PhysX_3.4/Source/LowLevelParticles/src/PtCollisionMesh.cpp')
-rw-r--r--PhysX_3.4/Source/LowLevelParticles/src/PtCollisionMesh.cpp698
1 files changed, 698 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/LowLevelParticles/src/PtCollisionMesh.cpp b/PhysX_3.4/Source/LowLevelParticles/src/PtCollisionMesh.cpp
new file mode 100644
index 00000000..b9f96e3e
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevelParticles/src/PtCollisionMesh.cpp
@@ -0,0 +1,698 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "PtCollisionMethods.h"
+#if PX_USE_PARTICLE_SYSTEM_API
+
+#include "PtHeightFieldAabbTest.h"
+#include "GuTriangleVertexPointers.h"
+#include "PtConstants.h"
+#include "GuBox.h"
+#include "GuMidphaseInterface.h"
+
+using namespace physx;
+using namespace Pt;
+using namespace Gu;
+
+//
+// Collide particle against mesh triangle
+//
+// Project particle on triangle plane, check if projected particle is inside triangle
+// using barycentric coordinates.
+// //
+// q2 //
+// * //
+// / \ //
+// / \ //
+// / \ //
+// / \ //
+// q0 *--------------* q1 //
+//
+// Triangle with points q0, q1, q2.
+//
+// Point p on plane defined by triangle:
+//
+// p = q0 + (u * (q1 - q0)) + (v * (q2 - q0))
+// = q0 + (u * e0) + (v * e1)
+//
+// -> (p - q0) = (u * e0) + (v * e1) // Subtract q0 from both sides
+// e2 = (u * e0) + (v * e1)
+//
+// We have two unknowns (u and v) so we need two equations to solve for them. Dot both sides by e0 to get one and dot
+// both sides by
+// e1 to get a second.
+//
+// e2 . e0 = ((u * e0) + (v * e1)) . e0 (1)
+// e2 . e1 = ((u * e0) + (v * e1)) . e1 (2)
+//
+// Distribute e0 and e1
+//
+// e2 . e0 = u * (e0 . e0) + v * (e1 . e0) (1)
+// e2 . e1 = u * (e0 . e1) + v * (e1 . e1) (2)
+//
+// Solve vor u, v
+//
+// u = ((e1.e1)(e0.e2) - (e0.e1)(e1.e2)) / ((e0.e0)(e1.e1) - (e0.e1)(e0.e1))
+// v = ((e0.e0)(e1.e2) - (e0.e1)(e0.e2)) / ((e0.e0)(e1.e1) - (e0.e1)(e0.e1))
+//
+// Setting a = e0.e0, b = e0.e1, c = e1.e1, d = e0.(-e2), e = e1.(-e2) we can write
+//
+// u = (b*e - c*d) / (a*c - b*b)
+// v = (b*d - a*e) / (a*c - b*b)
+//
+// If (u >= 0) and (v >= 0) and (u + v <= 1) the point lies inside the triangle.
+//
+// Note that u and v do not need to be computed in full to do the test.
+// Lets define the following substitutions:
+// x = (b*e - c*d)
+// y = (b*d - a*e)
+// z = (a*c - b*b) // Always positive!
+//
+// If (x >= 0) and (y >= 0) and (x + y <= z) the point lies inside the triangle.
+//
+//
+
+namespace physx
+{
+PX_FORCE_INLINE PxU32 collideWithMeshTriangle(PxVec3& surfaceNormal, PxVec3& surfacePos, PxVec3& proxSurfaceNormal,
+ PxVec3& proxSurfacePos, PxReal& ccTime, PxReal& distOldToSurface,
+ const PxVec3& oldPos, const PxVec3& newPos, const PxVec3& origin,
+ const PxVec3& e0, const PxVec3& e1, bool hasCC, const PxReal& collRadius,
+ const PxReal& proxRadius)
+{
+ PxU32 flags = 0;
+
+ PxReal collisionRadius2 = collRadius * collRadius;
+ PxReal proximityRadius2 = proxRadius * proxRadius;
+
+ PxVec3 motion = newPos - oldPos;
+
+ // dc and proximity tests
+ PxVec3 tmpV = origin - newPos;
+
+ PxReal a = e0.dot(e0);
+ PxReal b = e0.dot(e1);
+ PxReal c = e1.dot(e1);
+ PxReal d = e0.dot(tmpV);
+ PxReal e = e1.dot(tmpV);
+ PxVec3 coords;
+ coords.x = b * e - c * d; // s * det
+ coords.y = b * d - a * e; // t * det
+ coords.z = a * c - b * b; // det
+
+ bool insideCase = false;
+ PxVec3 clampedCoords(PxVec3(0));
+ if(coords.x <= 0.0f)
+ {
+ c = PxMax(c, FLT_MIN);
+ clampedCoords.y = -e / c;
+ }
+ else if(coords.y <= 0.0f)
+ {
+ a = PxMax(a, FLT_MIN);
+ clampedCoords.x = -d / a;
+ }
+ else if(coords.x + coords.y > coords.z)
+ {
+ PxReal denominator = a + c - b - b;
+ PxReal numerator = c + e - b - d;
+ denominator = PxMax(denominator, FLT_MIN);
+ clampedCoords.x = numerator / denominator;
+ clampedCoords.y = 1.0f - clampedCoords.x;
+ }
+ else // all inside
+ {
+ PxReal tmpF = PxMax(coords.z, FLT_MIN);
+ tmpF = 1.0f / tmpF;
+ clampedCoords.x = coords.x * tmpF;
+ clampedCoords.y = coords.y * tmpF;
+ insideCase = true;
+ }
+ clampedCoords.x = PxMax(clampedCoords.x, 0.0f);
+ clampedCoords.y = PxMax(clampedCoords.y, 0.0f);
+ clampedCoords.x = PxMin(clampedCoords.x, 1.0f);
+ clampedCoords.y = PxMin(clampedCoords.y, 1.0f);
+
+ // Closest point to particle inside triangle
+ PxVec3 closest = origin + e0 * clampedCoords.x + e1 * clampedCoords.y;
+
+ PxVec3 triangleOffset = newPos - closest;
+ PxReal triangleDistance2 = triangleOffset.magnitudeSquared();
+
+ PxVec3 triangleNormal = e0.cross(e1);
+ PxReal e0e1Span = triangleNormal.magnitude();
+
+ bool isInFront = triangleOffset.dot(triangleNormal) > 0.0f;
+
+ // MS: Possible optimzation
+ /*
+ if (isInFront && (triangleDistance2 >= proximityRadius2))
+ return flags;
+ */
+
+ bool isInProximity = insideCase && (triangleDistance2 < proximityRadius2) && isInFront;
+ bool isInDiscrete = (triangleDistance2 < collisionRadius2) && isInFront;
+
+ if(!hasCC)
+ {
+ // Only apply discrete and proximity collisions if no continuous collisions was detected so far (for any
+ // colliding shape)
+
+ if(isInDiscrete)
+ {
+ if(triangleDistance2 > PT_COLL_TRI_DISTANCE)
+ {
+ surfaceNormal = triangleOffset * PxRecipSqrt(triangleDistance2);
+ }
+ else
+ {
+ surfaceNormal = triangleNormal * (1.0f / e0e1Span);
+ }
+ surfacePos = closest + (surfaceNormal * collRadius);
+ flags |= ParticleCollisionFlags::L_DC;
+ }
+
+ if(isInProximity)
+ {
+ proxSurfaceNormal = triangleNormal * (1.0f / e0e1Span);
+ proxSurfacePos = closest + (proxSurfaceNormal * collRadius);
+ flags |= ParticleCollisionFlags::L_PROX;
+
+ tmpV = (oldPos - origin); // this time it's not the newPosition offset.
+ distOldToSurface = proxSurfaceNormal.dot(tmpV); // Need to return the distance to decide which constraints
+ // should be thrown away
+ }
+ }
+
+ if(!isInDiscrete && !isInProximity)
+ {
+ // cc test (let's try only executing this if no discrete coll, or proximity happend).
+ tmpV = origin - oldPos; // this time it's not the newPosition offset.
+ PxReal pDistN = triangleNormal.dot(tmpV);
+ PxReal rLengthN = triangleNormal.dot(motion);
+
+ if(pDistN > 0.0f || rLengthN >= pDistN)
+ return flags;
+
+ // we are in the half closed interval [0.0f, 1.0)
+
+ PxReal t = pDistN / rLengthN;
+ PX_ASSERT((t >= 0.0f) && (t < 1.0f));
+
+ PxVec3 relativePOSITION = (motion * t);
+ PxVec3 testPoint = oldPos + relativePOSITION;
+
+ // a,b,c and coords.z don't depend on test point -> still valid
+ tmpV = origin - testPoint;
+ d = e0.dot(tmpV);
+ e = e1.dot(tmpV);
+ coords.x = b * e - c * d;
+ coords.y = b * d - a * e;
+
+ // maybe we don't need this for rare case leaking on triangle boundaries?
+ PxReal eps = coords.z * PT_COLL_RAY_EPSILON_FACTOR;
+
+ if((coords.x >= -eps) && (coords.y >= -eps) && (coords.x + coords.y <= coords.z + eps))
+ {
+ PxReal invLengthN = (1.0f / e0e1Span);
+ distOldToSurface = -pDistN * invLengthN; // Need to return the distance to decide which constraints should
+ // be thrown away
+ surfaceNormal = triangleNormal * invLengthN;
+ // surfacePos = testPoint + (surfaceNormal * collRadius);
+ computeContinuousTargetPosition(surfacePos, oldPos, relativePOSITION, surfaceNormal, collRadius);
+ ccTime = t;
+ flags |= ParticleCollisionFlags::L_CC;
+ }
+ }
+
+ return flags;
+}
+}
+
+PX_FORCE_INLINE void setConstraintData(ParticleCollData& collData, const PxReal& distToSurface, const PxVec3& normal,
+ const PxVec3& position, const PxTransform& shape2World)
+{
+ PxU32 i;
+
+ if(!(collData.particleFlags.low & InternalParticleFlag::eCONSTRAINT_0_VALID))
+ {
+ i = 0;
+ }
+ else if(!(collData.particleFlags.low & InternalParticleFlag::eCONSTRAINT_1_VALID))
+ {
+ i = 1;
+ }
+ else
+ {
+ PxVec3 oldWorldSurfacePos(shape2World.transform(collData.localOldPos));
+
+ PxReal dist0 = collData.c0->normal.dot(oldWorldSurfacePos) - collData.c0->d;
+ PxReal dist1 = collData.c1->normal.dot(oldWorldSurfacePos) - collData.c1->d;
+
+ if(dist0 < dist1)
+ {
+ if(distToSurface < dist1)
+ i = 1;
+ else
+ return;
+ }
+ else if(distToSurface < dist0)
+ {
+ i = 0;
+ }
+ else
+ return;
+ }
+
+ PxVec3 newSurfaceNormal(shape2World.rotate(normal));
+ PxVec3 newSurfacePos(shape2World.transform(position));
+ Constraint cN(newSurfaceNormal, newSurfacePos);
+
+ if(i == 0)
+ {
+ *collData.c0 = cN;
+ collData.particleFlags.low |= InternalParticleFlag::eCONSTRAINT_0_VALID;
+ collData.particleFlags.low &= PxU16(~InternalParticleFlag::eCONSTRAINT_0_DYNAMIC);
+ }
+ else
+ {
+ *collData.c1 = cN;
+ collData.particleFlags.low |= InternalParticleFlag::eCONSTRAINT_1_VALID;
+ collData.particleFlags.low &= PxU16(~InternalParticleFlag::eCONSTRAINT_1_DYNAMIC);
+ }
+}
+
+PX_FORCE_INLINE void updateCollShapeData(ParticleCollData& collData, bool& hasCC, PxU32 collFlags, PxReal ccTime,
+ PxReal distOldToSurface, const PxVec3& surfaceNormal, const PxVec3& surfacePos,
+ const PxVec3& proxSurfaceNormal, const PxVec3& proxSurfacePos,
+ const PxTransform& shape2World)
+{
+ if(collFlags & ParticleCollisionFlags::L_CC)
+ {
+ if(ccTime < collData.ccTime)
+ {
+ // We want the collision that happened first
+ collData.localSurfaceNormal = surfaceNormal;
+ collData.localSurfacePos = surfacePos;
+ collData.ccTime = ccTime;
+ collData.localFlags = ParticleCollisionFlags::L_CC; // Continuous collision should overwrite discrete
+ // collision (?)
+ }
+
+ setConstraintData(collData, distOldToSurface, surfaceNormal, surfacePos, shape2World);
+ hasCC = true;
+ }
+ else if(!hasCC)
+ {
+ if(collFlags & ParticleCollisionFlags::L_PROX)
+ {
+ setConstraintData(collData, distOldToSurface, proxSurfaceNormal, proxSurfacePos, shape2World);
+
+ collData.localFlags |= ParticleCollisionFlags::L_PROX;
+ }
+
+ if(collFlags & ParticleCollisionFlags::L_DC)
+ {
+ collData.localSurfaceNormal += surfaceNormal;
+ collData.localSurfacePos += surfacePos;
+ collData.localDcNum += 1.0f;
+ collData.localFlags |= ParticleCollisionFlags::L_DC;
+ }
+ }
+}
+
+void collideCellWithMeshTriangles(ParticleCollData* collData, const PxU32* collDataIndices, PxU32 numCollDataIndices,
+ const TriangleMesh& meshData, const Cm::FastVertex2ShapeScaling& scale,
+ const PxVec3* triangleVerts, PxU32 numTriangles, PxReal proxRadius,
+ const PxTransform& shape2World);
+
+struct PxcContactCellMeshCallback : MeshHitCallback<PxRaycastHit>
+{
+ ParticleCollData* collData;
+ const PxU32* collDataIndices;
+ PxU32 numCollDataIndices;
+ const TriangleMesh& meshData;
+ const Cm::FastVertex2ShapeScaling meshScaling;
+ PxReal proxRadius;
+ ParticleOpcodeCache* cache;
+ const PxTransform& shape2World;
+
+ PxcContactCellMeshCallback(ParticleCollData* collData_, const PxU32* collDataIndices_, PxU32 numCollDataIndices_,
+ const TriangleMesh& meshData_, const Cm::FastVertex2ShapeScaling& meshScaling_,
+ PxReal proxRadius_, ParticleOpcodeCache* cache_, const PxTransform& shape2World_)
+ : MeshHitCallback<PxRaycastHit>(CallbackMode::eMULTIPLE)
+ , collData(collData_)
+ , collDataIndices(collDataIndices_)
+ , numCollDataIndices(numCollDataIndices_)
+ , meshData(meshData_)
+ , meshScaling(meshScaling_)
+ , proxRadius(proxRadius_)
+ , cache(cache_)
+ , shape2World(shape2World_)
+ {
+ PX_ASSERT(collData);
+ PX_ASSERT(collDataIndices);
+ PX_ASSERT(numCollDataIndices > 0);
+
+ // init
+ const PxU32* collDataIndexIt = collDataIndices_;
+ for(PxU32 i = 0; i < numCollDataIndices_; ++i, ++collDataIndexIt)
+ {
+ ParticleCollData& collisionShapeData = collData_[*collDataIndexIt];
+ collisionShapeData.localDcNum = 0.0f;
+ collisionShapeData.localSurfaceNormal = PxVec3(0);
+ collisionShapeData.localSurfacePos = PxVec3(0);
+ }
+ }
+ virtual ~PxcContactCellMeshCallback()
+ {
+ }
+
+ virtual PxAgain processHit( // all reported coords are in mesh local space including hit.position
+ const PxRaycastHit& hit, const PxVec3& v0, const PxVec3& v1, const PxVec3& v2, PxReal&, const PxU32*)
+ {
+ PxVec3 verts[3] = { v0, v1, v2 };
+ collideCellWithMeshTriangles(collData, collDataIndices, numCollDataIndices, meshData, meshScaling, verts, 1,
+ proxRadius, shape2World);
+
+ if(cache)
+ cache->add(&hit.faceIndex, 1);
+
+ return true;
+ }
+
+ private:
+ PxcContactCellMeshCallback& operator=(const PxcContactCellMeshCallback&);
+};
+
+void testBoundsMesh(const TriangleMesh& meshData, const PxTransform& world2Shape,
+ const Cm::FastVertex2ShapeScaling& meshScaling, bool idtScaleMesh, const PxBounds3& worldBounds,
+ PxcContactCellMeshCallback& callback)
+{
+ // Find colliding triangles.
+ // Setup an OBB for the fluid particle cell (in local space of shape)
+ // assuming uniform scaling in most cases, using the pose as box rotation
+ // if scaling is non-uniform, the bounding box is conservative
+
+ Box vertexSpaceAABB;
+ computeVertexSpaceAABB(vertexSpaceAABB, worldBounds, world2Shape, meshScaling, idtScaleMesh);
+
+ Gu::intersectOBB_Particles(&meshData, vertexSpaceAABB, callback, true);
+}
+
+void collideWithMeshTriangles(ParticleCollData& collisionShapeData, const TriangleMesh& /*meshData*/,
+ const Cm::FastVertex2ShapeScaling& scale, const PxVec3* triangleVerts, PxU32 numTriangles,
+ PxReal proxRadius, const PxTransform& shape2World)
+{
+ bool hasCC = ((collisionShapeData.localFlags & ParticleCollisionFlags::CC) ||
+ (collisionShapeData.localFlags & ParticleCollisionFlags::L_CC));
+
+ PxVec3 tmpSurfaceNormal(0.0f);
+ PxVec3 tmpSurfacePos(0.0f);
+ PxVec3 tmpProxSurfaceNormal(0.0f);
+ PxVec3 tmpProxSurfacePos(0.0f);
+ PxReal tmpCCTime(0.0f);
+ PxReal tmpDistOldToSurface(0.0f);
+
+ for(PxU32 i = 0; i < numTriangles; ++i)
+ {
+ const PxI32 winding = scale.flipsNormal() ? 1 : 0;
+ PxVec3 v0 = scale * triangleVerts[i * 3];
+ PxVec3 v1 = scale * triangleVerts[i * 3 + 1 + winding];
+ PxVec3 v2 = scale * triangleVerts[i * 3 + 2 - winding];
+
+ PxU32 tmpFlags =
+ collideWithMeshTriangle(tmpSurfaceNormal, tmpSurfacePos, tmpProxSurfaceNormal, tmpProxSurfacePos, tmpCCTime,
+ tmpDistOldToSurface, collisionShapeData.localOldPos, collisionShapeData.localNewPos,
+ v0, v1 - v0, v2 - v0, hasCC, collisionShapeData.restOffset, proxRadius);
+
+ updateCollShapeData(collisionShapeData, hasCC, tmpFlags, tmpCCTime, tmpDistOldToSurface, tmpSurfaceNormal,
+ tmpSurfacePos, tmpProxSurfaceNormal, tmpProxSurfacePos, shape2World);
+ }
+}
+
+void collideCellWithMeshTriangles(ParticleCollData* collData, const PxU32* collDataIndices, PxU32 numCollDataIndices,
+ const TriangleMesh& meshData, const Cm::FastVertex2ShapeScaling& scale,
+ const PxVec3* triangleVerts, PxU32 numTriangles, PxReal proxRadius,
+ const PxTransform& shape2World)
+{
+ PX_ASSERT(collData);
+ PX_ASSERT(collDataIndices);
+ PX_ASSERT(numCollDataIndices > 0);
+ PX_ASSERT(triangleVerts);
+
+ const PxU32* collDataIndexIt = collDataIndices;
+ for(PxU32 i = 0; i < numCollDataIndices; ++i, ++collDataIndexIt)
+ {
+ ParticleCollData& collisionShapeData = collData[*collDataIndexIt];
+ collideWithMeshTriangles(collisionShapeData, meshData, scale, triangleVerts, numTriangles, proxRadius,
+ shape2World);
+ }
+}
+
+void physx::Pt::collideCellsWithStaticMesh(ParticleCollData* collData, const LocalCellHash& localCellHash,
+ const GeometryUnion& meshShape, const PxTransform& world2Shape,
+ const PxTransform& shape2World, PxReal /*cellSize*/,
+ PxReal /*collisionRange*/, PxReal proxRadius, const PxVec3& /*packetCorner*/)
+{
+ PX_ASSERT(collData);
+ PX_ASSERT(localCellHash.isHashValid);
+ PX_ASSERT(localCellHash.numParticles <= PT_SUBPACKET_PARTICLE_LIMIT_COLLISION);
+ PX_ASSERT(localCellHash.numHashEntries <= PT_LOCAL_HASH_SIZE_MESH_COLLISION);
+
+ const PxTriangleMeshGeometryLL& meshShapeData = meshShape.get<const PxTriangleMeshGeometryLL>();
+
+ const TriangleMesh* meshData = meshShapeData.meshData;
+ PX_ASSERT(meshData);
+
+ // mesh bounds in world space (conservative)
+ const PxBounds3 shapeBounds =
+ meshData->getLocalBoundsFast().transformSafe(world2Shape.getInverse() * meshShapeData.scale);
+
+ const bool idtScaleMesh = meshShapeData.scale.isIdentity();
+
+ Cm::FastVertex2ShapeScaling meshScaling;
+ if(!idtScaleMesh)
+ meshScaling.init(meshShapeData.scale);
+
+ // process the particle cells
+ for(PxU32 c = 0; c < localCellHash.numHashEntries; c++)
+ {
+ const ParticleCell& cell = localCellHash.hashEntries[c];
+
+ if(cell.numParticles == PX_INVALID_U32)
+ continue;
+
+ PxBounds3 cellBounds;
+
+ cellBounds.setEmpty();
+ PxBounds3 cellBoundsNew(PxBounds3::empty());
+
+ PxU32* it = localCellHash.particleIndices + cell.firstParticle;
+ const PxU32* end = it + cell.numParticles;
+ for(; it != end; it++)
+ {
+ const ParticleCollData& particle = collData[*it];
+ cellBounds.include(particle.oldPos);
+ cellBoundsNew.include(particle.newPos);
+ }
+ PX_ASSERT(!cellBoundsNew.isEmpty());
+ cellBoundsNew.fattenFast(proxRadius);
+ cellBounds.include(cellBoundsNew);
+
+ if(!cellBounds.intersects(shapeBounds))
+ continue; // early out if (inflated) cell doesn't intersect mesh bounds
+
+ // opcode query: cell bounds against shape bounds in unscaled mesh space
+ PxcContactCellMeshCallback callback(collData, &(localCellHash.particleIndices[cell.firstParticle]),
+ cell.numParticles, *meshData, meshScaling, proxRadius, NULL, shape2World);
+ testBoundsMesh(*meshData, world2Shape, meshScaling, idtScaleMesh, cellBounds, callback);
+ }
+}
+
+void physx::Pt::collideWithStaticMesh(PxU32 numParticles, ParticleCollData* collData, ParticleOpcodeCache* opcodeCaches,
+ const GeometryUnion& meshShape, const PxTransform& world2Shape,
+ const PxTransform& shape2World, PxReal /*cellSize*/, PxReal collisionRange,
+ PxReal proxRadius)
+{
+ PX_ASSERT(collData);
+ PX_ASSERT(opcodeCaches);
+
+ const PxTriangleMeshGeometryLL& meshShapeData = meshShape.get<const PxTriangleMeshGeometryLL>();
+
+ const bool idtScaleMesh = meshShapeData.scale.isIdentity();
+ Cm::FastVertex2ShapeScaling meshScaling;
+ if(!idtScaleMesh)
+ meshScaling.init(meshShapeData.scale);
+
+ const PxF32 maxCacheBoundsExtent = 4 * collisionRange + proxRadius;
+ const ParticleOpcodeCache::QuantizationParams quantizationParams =
+ ParticleOpcodeCache::getQuantizationParams(maxCacheBoundsExtent);
+
+ const TriangleMesh* meshData = meshShapeData.meshData;
+ PX_ASSERT(meshData);
+
+ bool isSmallMesh = meshData->has16BitIndices();
+ PxU32 cachedTriangleBuffer[ParticleOpcodeCache::sMaxCachedTriangles];
+
+ PxVec3 extent(proxRadius);
+
+ for(PxU32 i = 0; i < numParticles; ++i)
+ {
+ // had to make this non-const to be able to update cache bits
+ ParticleCollData& particle = collData[i];
+ ParticleOpcodeCache& cache = opcodeCaches[i];
+
+ PxBounds3 bounds;
+ {
+ bounds = PxBounds3(particle.newPos - extent, particle.newPos + extent);
+ bounds.include(particle.oldPos);
+ }
+
+ PxU32 numTriangles = 0;
+ const PxU32* triangles = NULL;
+ bool isCached = cache.read(particle.particleFlags.low, numTriangles, cachedTriangleBuffer, bounds,
+ quantizationParams, &meshShape, isSmallMesh);
+
+ if(isCached)
+ {
+ triangles = cachedTriangleBuffer;
+ if(numTriangles > 0)
+ {
+ PxVec3 triangleVerts[ParticleOpcodeCache::sMaxCachedTriangles * 3];
+ const PxU32* triangleIndexIt = triangles;
+ for(PxU32 j = 0; j < numTriangles; ++j, ++triangleIndexIt)
+ {
+ TriangleVertexPointers::getTriangleVerts(meshData, *triangleIndexIt, triangleVerts[j * 3],
+ triangleVerts[j * 3 + 1], triangleVerts[j * 3 + 2]);
+ }
+
+ collData[i].localDcNum = 0.0f;
+ collData[i].localSurfaceNormal = PxVec3(0);
+ collData[i].localSurfacePos = PxVec3(0);
+
+ collideWithMeshTriangles(collData[i], *meshData, meshScaling, triangleVerts, numTriangles, proxRadius,
+ shape2World);
+ }
+ }
+ else if((particle.particleFlags.low & InternalParticleFlag::eGEOM_CACHE_BIT_0) != 0 &&
+ (particle.particleFlags.low & InternalParticleFlag::eGEOM_CACHE_BIT_1) != 0)
+ {
+ // don't update the cache since it's already successfully in use
+ PxcContactCellMeshCallback callback(collData, &i, 1, *meshData, meshScaling, proxRadius, NULL, shape2World);
+
+ testBoundsMesh(*meshData, world2Shape, meshScaling, idtScaleMesh, bounds, callback);
+ }
+ else
+ {
+ // compute new conservative bounds for cache
+ PxBounds3 cachedBounds;
+ {
+ PxVec3 predictedExtent(proxRadius * 1.5f);
+
+ // add future newpos + extent
+ PxVec3 newPosPredicted = particle.newPos + 3.f * (particle.newPos - particle.oldPos);
+ cachedBounds = PxBounds3(newPosPredicted - predictedExtent, newPosPredicted + predictedExtent);
+
+ // add next oldpos + extent
+ cachedBounds.include(PxBounds3(particle.newPos - predictedExtent, particle.newPos + predictedExtent));
+
+ // add old pos
+ cachedBounds.include(particle.oldPos);
+ }
+
+ cache.init(cachedTriangleBuffer);
+
+ // the callback function will call collideWithMeshTriangles()
+ PxcContactCellMeshCallback callback(collData, &i, 1, *meshData, meshScaling, proxRadius, &cache, shape2World);
+
+ // opcode query: cache bounds against shape bounds in unscaled mesh space
+ testBoundsMesh(*meshData, world2Shape, meshScaling, idtScaleMesh, cachedBounds, callback);
+
+ // update cache
+ cache.write(particle.particleFlags.low, cachedBounds, quantizationParams, meshShape, isSmallMesh);
+ }
+ }
+}
+
+void physx::Pt::collideWithStaticHeightField(ParticleCollData* particleCollData, PxU32 numCollData,
+ const GeometryUnion& heightFieldShape, PxReal proxRadius,
+ const PxTransform& shape2World)
+{
+ PX_ASSERT(particleCollData);
+
+ const PxHeightFieldGeometryLL& hfGeom = heightFieldShape.get<const PxHeightFieldGeometryLL>();
+ const HeightFieldUtil hfUtil(hfGeom);
+
+ for(PxU32 p = 0; p < numCollData; p++)
+ {
+ ParticleCollData& collData = particleCollData[p];
+
+ PxBounds3 particleBounds = PxBounds3::boundsOfPoints(collData.localOldPos, collData.localNewPos);
+ PX_ASSERT(!particleBounds.isEmpty());
+ particleBounds.fattenFast(proxRadius);
+
+ HeightFieldAabbTest test(particleBounds, hfUtil);
+ HeightFieldAabbTest::Iterator itBegin = test.begin();
+ HeightFieldAabbTest::Iterator itEnd = test.end();
+ PxVec3 triangle[3];
+
+ collData.localDcNum = 0.0f;
+ collData.localSurfaceNormal = PxVec3(0);
+ collData.localSurfacePos = PxVec3(0);
+ bool hasCC = (collData.localFlags & ParticleCollisionFlags::CC) > 0;
+
+ PxVec3 tmpSurfaceNormal(0.0f);
+ PxVec3 tmpSurfacePos(0.0f);
+ PxVec3 tmpProxSurfaceNormal(0.0f);
+ PxVec3 tmpProxSurfacePos(0.0f);
+ PxReal tmpCCTime(collData.ccTime);
+ PxReal tmpDistOldToSurface(0.0f);
+
+ for(HeightFieldAabbTest::Iterator it = itBegin; it != itEnd; ++it)
+ {
+ it.getTriangleVertices(triangle);
+
+ const PxVec3& origin = triangle[0];
+ PxVec3 e0, e1;
+ e0 = triangle[1] - origin;
+ e1 = triangle[2] - origin;
+
+ PxU32 tmpFlags =
+ collideWithMeshTriangle(tmpSurfaceNormal, tmpSurfacePos, tmpProxSurfaceNormal, tmpProxSurfacePos,
+ tmpCCTime, tmpDistOldToSurface, collData.localOldPos, collData.localNewPos,
+ origin, e0, e1, hasCC, collData.restOffset, proxRadius);
+
+ updateCollShapeData(collData, hasCC, tmpFlags, tmpCCTime, tmpDistOldToSurface, tmpSurfaceNormal,
+ tmpSurfacePos, tmpProxSurfaceNormal, tmpProxSurfacePos, shape2World);
+ }
+ }
+}
+
+#endif // PX_USE_PARTICLE_SYSTEM_API