aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/LowLevelParticles/src/PtCollision.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/PtCollision.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/PtCollision.cpp')
-rw-r--r--PhysX_3.4/Source/LowLevelParticles/src/PtCollision.cpp676
1 files changed, 676 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/LowLevelParticles/src/PtCollision.cpp b/PhysX_3.4/Source/LowLevelParticles/src/PtCollision.cpp
new file mode 100644
index 00000000..537c0112
--- /dev/null
+++ b/PhysX_3.4/Source/LowLevelParticles/src/PtCollision.cpp
@@ -0,0 +1,676 @@
+// 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 "PtCollision.h"
+#if PX_USE_PARTICLE_SYSTEM_API
+
+#include "PtConfig.h"
+#include "PtParticleSystemSimCpu.h"
+#include "PtParticleShapeCpu.h"
+#include "PtContext.h"
+#include "PtBodyTransformVault.h"
+#include "PtCollisionHelper.h"
+#include "PtParticleContactManagerStream.h"
+#include "GuConvexMeshData.h"
+#include "CmFlushPool.h"
+#include "PxvGeometry.h"
+
+using namespace physx;
+using namespace Pt;
+
+namespace physx
+{
+
+namespace Pt
+{
+
+class CollisionTask : public Cm::Task
+{
+ public:
+ CollisionTask(Collision& context, PxU32 taskDataIndex) : mCollisionContext(context), mTaskDataIndex(taskDataIndex)
+ {
+ }
+
+ virtual void runInternal()
+ {
+ mCollisionContext.processShapeListWithFilter(mTaskDataIndex);
+ }
+
+ virtual const char* getName() const
+ {
+ return "Collision.fluidCollision";
+ }
+
+ private:
+ CollisionTask& operator=(const CollisionTask&);
+ Collision& mCollisionContext;
+ PxU32 mTaskDataIndex;
+};
+
+} // namespace Pt
+} // namespace physx
+
+/*
+how to support dominance-driven one/two-way collision (search for 'todo dominance'):
+- add 2-bit flag to PxsBodyShapeRef which stores the dominance matrix values
+- store this flag when creating the shape ref in updateFluidBodyContactPair()
+- use this flag when copying impulse to collData.shapeImpulse
+*/
+Collision::Collision(ParticleSystemSimCpu& particleSystem)
+: mParticleSystem(particleSystem), mMergeTask(this, "Collision.mergeResults")
+{
+}
+
+Collision::~Collision()
+{
+}
+
+void PX_FORCE_INLINE Collision::addTempW2STransform(TaskData& taskData, const ParticleStreamContactManager& cm)
+{
+ W2STransformTemp& cmTemp = taskData.tempContactManagers.insert();
+
+ if(cm.isDynamic)
+ {
+ const PxsBodyCore* bodyCore = static_cast<const PxsBodyCore*>(cm.rigidCore);
+ cmTemp.w2sOld = cm.shapeCore->transform.transformInv(bodyCore->getBody2Actor()).transform(cm.w2sOld->getInverse());
+ cmTemp.w2sNew =
+ cm.shapeCore->transform.transformInv(bodyCore->getBody2Actor()).transform(bodyCore->body2World.getInverse());
+ }
+ else
+ {
+ const PxTransform tmp = cm.shapeCore->transform.getInverse() * cm.rigidCore->body2World.getInverse();
+ cmTemp.w2sOld = tmp;
+ cmTemp.w2sNew = tmp;
+ }
+}
+
+void Collision::updateCollision(const PxU8* contactManagerStream, physx::PxBaseTask& continuation)
+{
+ mMergeTask.setContinuation(&continuation);
+ PxU32 maxTasks = PT_NUM_PACKETS_PARALLEL_COLLISION;
+ PxU32 packetParticleIndicesCount = mParticleSystem.mNumPacketParticlesIndices;
+
+ // would be nice to get available thread count to decide on task decomposition
+ // mParticleSystem.getContext().getTaskManager().getCpuDispatcher();
+
+ // use number of particles for task decomposition
+
+ PxU32 targetParticleCountPerTask =
+ PxMax(PxU32(packetParticleIndicesCount / maxTasks), PxU32(PT_SUBPACKET_PARTICLE_LIMIT_COLLISION));
+ ParticleContactManagerStreamReader cmStreamReader(contactManagerStream);
+ ParticleContactManagerStreamIterator cmStreamEnd = cmStreamReader.getEnd();
+ ParticleContactManagerStreamIterator cmStream = cmStreamReader.getBegin();
+ ParticleContactManagerStreamIterator cmStreamLast;
+
+ PxU32 numTasks = 0;
+ for(PxU32 i = 0; i < PT_NUM_PACKETS_PARALLEL_COLLISION; ++i)
+ {
+ TaskData& taskData = mTaskData[i];
+ taskData.bounds.setEmpty();
+
+ // if this is the last interation, we need to gather all remaining packets
+ if(i == maxTasks - 1)
+ targetParticleCountPerTask = 0xffffffff;
+
+ cmStreamLast = cmStream;
+ PxU32 currentParticleCount = 0;
+
+ while(currentParticleCount < targetParticleCountPerTask && cmStream != cmStreamEnd)
+ {
+ ParticleStreamShape streamShape;
+ cmStream.getNext(streamShape);
+ const ParticleShapeCpu* particleShape = static_cast<const ParticleShapeCpu*>(streamShape.particleShape);
+ currentParticleCount += particleShape->getFluidPacket()->numParticles;
+ }
+
+ if(currentParticleCount > 0)
+ {
+ PX_ASSERT(cmStreamLast != cmStream);
+ taskData.packetBegin = cmStreamLast;
+ taskData.packetEnd = cmStream;
+ numTasks++;
+ }
+ }
+ PX_ASSERT(cmStream == cmStreamEnd);
+
+ // spawn tasks
+ for(PxU32 i = 0; i < numTasks; ++i)
+ {
+ void* ptr = mParticleSystem.getContext().getTaskPool().allocate(sizeof(CollisionTask));
+ CollisionTask* task = PX_PLACEMENT_NEW(ptr, CollisionTask)(*this, i);
+ task->setContinuation(&mMergeTask);
+ task->removeReference();
+ }
+
+ mMergeTask.removeReference();
+}
+
+void Collision::updateOverflowParticles()
+{
+ // if no particles are present, the hash shouldn't be accessed, as it hasn't been updated.
+ if(mParticleSystem.mParticleState->getValidParticleRange() > 0)
+ {
+ const Pt::ParticleCell& overflowCell =
+ mParticleSystem.mSpatialHash->getPackets()[PT_PARTICLE_SYSTEM_OVERFLOW_INDEX];
+ Pt::Particle* particles = mParticleSystem.mParticleState->getParticleBuffer();
+ PxU32* indices = mParticleSystem.mPacketParticlesIndices;
+ for(PxU32 i = overflowCell.firstParticle; i < overflowCell.firstParticle + overflowCell.numParticles; i++)
+ {
+ PxU32 index = indices[i];
+ Pt::Particle& particle = particles[index];
+ PX_ASSERT((particle.flags.api & PxParticleFlag::eSPATIAL_DATA_STRUCTURE_OVERFLOW) != 0);
+
+ // update velocity and position
+ // world bounds are not updated for overflow particles, to make it more consistent with GPU.
+ {
+ PxVec3 acceleration = mParams.externalAcceleration;
+ integrateParticleVelocity(particle, mParams.maxMotionDistance, acceleration, mParams.dampingDtComp,
+ mParams.timeStep);
+ particle.position = particle.position + particle.velocity * mParams.timeStep;
+
+ // adapted from updateParticle(...) in PxsFluidCollisionHelper.h
+ bool projection = (mParams.flags & PxParticleBaseFlag::ePROJECT_TO_PLANE) != 0;
+ if(projection)
+ {
+ const PxReal dist = mParams.projectionPlane.n.dot(particle.velocity);
+ particle.velocity = particle.velocity - (mParams.projectionPlane.n * dist);
+ particle.position = mParams.projectionPlane.project(particle.position);
+ }
+ PX_ASSERT(particle.position.isFinite());
+ }
+ }
+ }
+}
+
+void Collision::processShapeListWithFilter(PxU32 taskDataIndex, const PxU32 skipNum)
+{
+ TaskData& taskData = mTaskData[taskDataIndex];
+
+ ParticleContactManagerStreamIterator it = taskData.packetBegin;
+ while(it != taskData.packetEnd)
+ {
+ ParticleStreamShape streamShape;
+ it.getNext(streamShape);
+
+ if(streamShape.numContactManagers < skipNum)
+ continue;
+
+ const ParticleShapeCpu* particleShape = static_cast<const ParticleShapeCpu*>(streamShape.particleShape);
+ PX_ASSERT(particleShape);
+ PX_UNUSED(particleShape);
+
+ // Collect world to shape space transforms for all colliding rigid body shapes
+ taskData.tempContactManagers.clear();
+ for(PxU32 i = 0; i < streamShape.numContactManagers; i++)
+ {
+ const ParticleStreamContactManager& cm = streamShape.contactManagers[i];
+ addTempW2STransform(taskData, cm);
+ }
+
+ updateFluidShapeCollision(
+ mParticleSystem.mParticleState->getParticleBuffer(), mParticleSystem.mFluidTwoWayData,
+ mParticleSystem.mTransientBuffer, mParticleSystem.mCollisionVelocities, mParticleSystem.mConstraintBuffers,
+ mParticleSystem.mOpcodeCacheBuffer, taskData.bounds, mParticleSystem.mPacketParticlesIndices,
+ mParticleSystem.mParticleState->getRestOffsetBuffer(), taskData.tempContactManagers.begin(), streamShape);
+ }
+}
+
+void Collision::mergeResults(physx::PxBaseTask* /*continuation*/)
+{
+ PxBounds3& worldBounds = mParticleSystem.mParticleState->getWorldBounds();
+ for(PxU32 i = 0; i < PT_NUM_PACKETS_PARALLEL_COLLISION; ++i)
+ worldBounds.include(mTaskData[i].bounds);
+}
+
+void Collision::updateFluidShapeCollision(Particle* particles, TwoWayData* fluidTwoWayData, PxVec3* transientBuf,
+ PxVec3* collisionVelocities, ConstraintBuffers& constraintBufs,
+ ParticleOpcodeCache* opcodeCache, PxBounds3& worldBounds,
+ const PxU32* fluidShapeParticleIndices, const PxF32* restOffsets,
+ const W2STransformTemp* w2sTransforms, const ParticleStreamShape& streamShape)
+{
+ const ParticleShapeCpu& particleShape = *static_cast<const ParticleShapeCpu*>(streamShape.particleShape);
+ PX_ASSERT(particleShape.getFluidPacket());
+
+ const ParticleCell& packet = *particleShape.getFluidPacket();
+
+ PxU32 numParticles = packet.numParticles;
+ PxU32 firstParticleIndex = packet.firstParticle;
+ const PxU32* packetParticleIndices = fluidShapeParticleIndices + firstParticleIndex;
+ const PxU32 numParticlesPerSubpacket = PT_SUBPACKET_PARTICLE_LIMIT_COLLISION;
+
+ PX_ALLOCA(particlesSp, Particle, numParticlesPerSubpacket);
+ PxF32 restOffsetsSp[numParticlesPerSubpacket];
+
+ const PxU32 numHashBuckets = PT_LOCAL_HASH_SIZE_MESH_COLLISION;
+
+ PxU32 hashMemCount = numHashBuckets * sizeof(ParticleCell) + numParticlesPerSubpacket * sizeof(PxU32);
+ PxU32 cacheMemCount = numParticlesPerSubpacket * sizeof(ParticleOpcodeCache);
+ PX_ALLOCA(shareMem, PxU8, PxMax(hashMemCount, cacheMemCount));
+
+ ParticleOpcodeCache* perParticleCacheSp = NULL;
+ LocalCellHash localCellHash;
+ PxVec3 packetCorner;
+
+ if(opcodeCache)
+ perParticleCacheSp = reinterpret_cast<ParticleOpcodeCache*>(shareMem.mPointer);
+ else
+ {
+ // Make sure the number of hash buckets is a power of 2 (requirement for the used hash function)
+ PX_ASSERT((((numHashBuckets - 1) ^ numHashBuckets) + 1) == (2 * numHashBuckets));
+ PX_ASSERT(numHashBuckets > numParticlesPerSubpacket);
+ // Set the buffers for the local cell hash
+ localCellHash.particleIndices = reinterpret_cast<PxU32*>(shareMem.mPointer);
+ localCellHash.hashEntries =
+ reinterpret_cast<ParticleCell*>(shareMem.mPointer + numParticlesPerSubpacket * sizeof(PxU32));
+ packetCorner =
+ PxVec3(PxReal(packet.coords.x), PxReal(packet.coords.y), PxReal(packet.coords.z)) * mParams.packetSize;
+ }
+
+ // Divide the packet into subpackets that fit into local memory of processing unit.
+ PxU32 particlesRemainder = (numParticles - 1) % numParticlesPerSubpacket + 1;
+
+ PxU32 numProcessedParticles = 0;
+ PxU32 numParticlesSp = particlesRemainder; // We start with the smallest subpacket, i.e., the subpacket which does
+ // not reach its particle limit.
+ while(numProcessedParticles < numParticles)
+ {
+ const PxU32* particleIndicesSp = packetParticleIndices + numProcessedParticles;
+
+ // load particles (constraints are loaded on demand so far)
+ for(PxU32 p = 0; p < numParticlesSp; p++)
+ {
+ PxU32 particleIndex = particleIndicesSp[p];
+ particlesSp[p] = particles[particleIndex];
+ }
+
+ if(restOffsets)
+ {
+ for(PxU32 p = 0; p < numParticlesSp; p++)
+ {
+ PxU32 particleIndex = particleIndicesSp[p];
+ restOffsetsSp[p] = restOffsets[particleIndex];
+ }
+ }
+ else
+ {
+ for(PxU32 p = 0; p < numParticlesSp; p++)
+ restOffsetsSp[p] = mParams.restOffset;
+ }
+
+ updateSubPacket(particlesSp, fluidTwoWayData, transientBuf, collisionVelocities, constraintBufs,
+ perParticleCacheSp, opcodeCache, localCellHash, worldBounds, packetCorner, particleIndicesSp,
+ numParticlesSp, streamShape.contactManagers, w2sTransforms, streamShape.numContactManagers,
+ restOffsetsSp);
+
+ // store particles back
+ for(PxU32 p = 0; p < numParticlesSp; p++)
+ {
+ PxU32 particleIndex = particleIndicesSp[p];
+ particles[particleIndex] = particlesSp[p];
+ }
+
+ // Invalidate cached local cell hash
+ localCellHash.isHashValid = false;
+
+ numProcessedParticles += numParticlesSp;
+ numParticlesSp = numParticlesPerSubpacket;
+ }
+}
+
+PX_FORCE_INLINE void
+Collision::updateSubPacket(Particle* particlesSp, TwoWayData* fluidTwoWayData, PxVec3* transientBuf,
+ PxVec3* collisionVelocities, ConstraintBuffers& constraintBufs,
+ ParticleOpcodeCache* perParticleCacheLocal, ParticleOpcodeCache* perParticleCacheGlobal,
+ LocalCellHash& localCellHash, PxBounds3& worldBounds, const PxVec3& packetCorner,
+ const PxU32* particleIndicesSp, const PxU32 numParticlesSp,
+ const ParticleStreamContactManager* contactManagers, const W2STransformTemp* w2sTransforms,
+ const PxU32 numContactManagers, const PxF32* restOffsetsSp)
+{
+ ParticleCollData* collDataSp =
+ reinterpret_cast<ParticleCollData*>(PX_ALLOC(numParticlesSp * sizeof(ParticleCollData), "ParticleCollData"));
+ for(PxU32 p = 0; p < numParticlesSp; p++)
+ {
+ const PxU32 particleIndex = particleIndicesSp[p];
+ Particle& particle = particlesSp[p];
+ PX_ASSERT(particle.position.isFinite() && particle.velocity.isFinite());
+ ParticleCollData& collData = collDataSp[p];
+ Ps::prefetchLine(&collData);
+ collData.c0 = &constraintBufs.constraint0Buf[particleIndex];
+ collData.c1 = &constraintBufs.constraint1Buf[particleIndex];
+ Ps::prefetchLine(collData.c0);
+ Ps::prefetchLine(collData.c1);
+ const PxVec3 particleOldVel = particle.velocity;
+
+ // integrate velocity
+ {
+ PxVec3 acceleration = mParams.externalAcceleration;
+ if(mParams.flags & InternalParticleSystemFlag::eSPH)
+ acceleration += transientBuf[particleIndex];
+
+ integrateParticleVelocity(particle, mParams.maxMotionDistance, acceleration, mParams.dampingDtComp,
+ mParams.timeStep);
+ }
+
+ PxVec3 c0Velocity(0.0f);
+ PxVec3 c1Velocity(0.0f);
+ const PxsBodyCore* c0TwoWayBody = NULL;
+ const PxsBodyCore* c1TwoWayBody = NULL;
+ if(particle.flags.low & InternalParticleFlag::eCONSTRAINT_0_DYNAMIC)
+ {
+ c0Velocity = constraintBufs.constraint0DynamicBuf[particleIndex].velocity;
+ if(fluidTwoWayData)
+ c0TwoWayBody = constraintBufs.constraint0DynamicBuf[particleIndex].twoWayBody;
+ }
+
+ if(particle.flags.low & InternalParticleFlag::eCONSTRAINT_1_DYNAMIC)
+ {
+ c1Velocity = constraintBufs.constraint1DynamicBuf[particleIndex].velocity;
+ if(fluidTwoWayData)
+ c1TwoWayBody = constraintBufs.constraint1DynamicBuf[particleIndex].twoWayBody;
+ }
+
+ initCollDataAndApplyConstraints(collData, particle, particleOldVel, restOffsetsSp[p], c0Velocity, c1Velocity,
+ c0TwoWayBody, c1TwoWayBody, particleIndex, mParams);
+
+ collData.particleFlags.low &=
+ PxU16(~(InternalParticleFlag::eCONSTRAINT_0_VALID | InternalParticleFlag::eCONSTRAINT_1_VALID |
+ InternalParticleFlag::eCONSTRAINT_0_DYNAMIC | InternalParticleFlag::eCONSTRAINT_1_DYNAMIC));
+ }
+
+ //
+ // Collide with dynamic shapes
+
+ PxU32 numDynamicShapes = 0;
+ for(PxU32 i = 0; i < numContactManagers; i++)
+ {
+ const ParticleStreamContactManager& cm = contactManagers[i];
+ if(!cm.isDynamic)
+ continue;
+
+ updateFluidBodyContactPair(particlesSp, numParticlesSp, collDataSp, constraintBufs, perParticleCacheLocal,
+ localCellHash, packetCorner, cm, w2sTransforms[i]);
+
+ numDynamicShapes++;
+ }
+
+ PxF32 maxMotionDistanceSqr = mParams.maxMotionDistance * mParams.maxMotionDistance;
+
+ if(numDynamicShapes > 0)
+ {
+ bool isTwoWay = (mParams.flags & PxParticleBaseFlag::eCOLLISION_TWOWAY) != 0;
+ for(PxU32 p = 0; p < numParticlesSp; p++)
+ {
+ ParticleCollData& collData = collDataSp[p];
+ collisionResponse(collData, isTwoWay, false, mParams);
+ clampToMaxMotion(collData.newPos, collData.oldPos, mParams.maxMotionDistance, maxMotionDistanceSqr);
+ collData.flags &= ~ParticleCollisionFlags::CC;
+ collData.flags &= ~ParticleCollisionFlags::DC;
+ collData.flags |= ParticleCollisionFlags::RESET_SNORMAL;
+ collData.surfacePos = PxVec3(0);
+ // we need to keep the dynamic surface velocity for providing collision velocities in finalization
+ // collData.surfaceVel = PxVec3(0);
+ collData.ccTime = 1.0f;
+ }
+ }
+
+ //
+ // Collide with static shapes
+ // (Static shapes need to be processed after dynamic shapes to avoid that dynamic shapes push
+ // particles into static shapes)
+ //
+
+ bool loadedCache = false;
+ for(PxU32 i = 0; i < numContactManagers; i++)
+ {
+ const ParticleStreamContactManager& cm = contactManagers[i];
+ if(cm.isDynamic)
+ continue;
+
+ const Gu::GeometryUnion& shape = cm.shapeCore->geometry;
+ if(perParticleCacheLocal && (!loadedCache) && (shape.getType() == PxGeometryType::eTRIANGLEMESH))
+ {
+ for(PxU32 p = 0; p < numParticlesSp; p++)
+ {
+ PxU32 particleIndex = particleIndicesSp[p];
+ perParticleCacheLocal[p] = perParticleCacheGlobal[particleIndex];
+ }
+ loadedCache = true;
+ }
+
+ updateFluidBodyContactPair(particlesSp, numParticlesSp, collDataSp, constraintBufs, perParticleCacheLocal,
+ localCellHash, packetCorner, cm, w2sTransforms[i]);
+ }
+
+ if(loadedCache)
+ {
+ for(PxU32 p = 0; p < numParticlesSp; p++)
+ {
+ PxU32 particleIndex = particleIndicesSp[p];
+ perParticleCacheGlobal[particleIndex] = perParticleCacheLocal[p];
+ }
+ }
+
+ for(PxU32 p = 0; p < numParticlesSp; p++)
+ {
+ ParticleCollData& collData = collDataSp[p];
+ Particle& particle = particlesSp[p];
+
+ collisionResponse(collData, false, true, mParams);
+
+ // Clamp new particle position to maximum motion.
+ clampToMaxMotion(collData.newPos, collData.oldPos, mParams.maxMotionDistance, maxMotionDistanceSqr);
+
+ // Update particle
+ updateParticle(particle, collData, (mParams.flags & PxParticleBaseFlag::ePROJECT_TO_PLANE) != 0,
+ mParams.projectionPlane, worldBounds);
+ }
+
+ if(transientBuf)
+ {
+ for(PxU32 p = 0; p < numParticlesSp; p++)
+ {
+ ParticleCollData& collData = collDataSp[p];
+ transientBuf[collData.origParticleIndex] = collData.surfaceNormal;
+ }
+ }
+
+ if(collisionVelocities)
+ {
+ for(PxU32 p = 0; p < numParticlesSp; p++)
+ {
+ ParticleCollData& collData = collDataSp[p];
+ PxVec3 collisionVelocity = particlesSp[p].velocity - collData.surfaceVel;
+ collisionVelocities[collData.origParticleIndex] = collisionVelocity;
+ }
+ }
+
+ if(fluidTwoWayData)
+ {
+ for(PxU32 p = 0; p < numParticlesSp; p++)
+ {
+ ParticleCollData& collData = collDataSp[p];
+ PX_ASSERT(!collData.twoWayBody || (particlesSp[p].flags.api & PxParticleFlag::eCOLLISION_WITH_DYNAMIC));
+ fluidTwoWayData[collData.origParticleIndex].body = collData.twoWayBody;
+ fluidTwoWayData[collData.origParticleIndex].impulse = collData.twoWayImpulse;
+ }
+ }
+
+ PX_FREE(collDataSp);
+}
+
+void Collision::updateFluidBodyContactPair(const Particle* particles, PxU32 numParticles,
+ ParticleCollData* particleCollData, ConstraintBuffers& constraintBufs,
+ ParticleOpcodeCache* opcodeCacheLocal, LocalCellHash& localCellHash,
+ const PxVec3& packetCorner, const ParticleStreamContactManager& contactManager,
+ const W2STransformTemp& w2sTransform)
+{
+ PX_ASSERT(particles);
+ PX_ASSERT(particleCollData);
+
+ bool isStaticMeshType = false;
+
+ const Gu::GeometryUnion& shape = contactManager.shapeCore->geometry;
+ const PxsBodyCore* body = contactManager.isDynamic ? static_cast<const PxsBodyCore*>(contactManager.rigidCore) : NULL;
+
+ const PxTransform& world2Shape = w2sTransform.w2sNew;
+ const PxTransform& world2ShapeOld = w2sTransform.w2sOld;
+ const PxTransform shape2World = world2Shape.getInverse();
+
+ for(PxU32 p = 0; p < numParticles; p++)
+ {
+ ParticleCollData& collData = particleCollData[p];
+
+ collData.localFlags = (collData.flags & ParticleCollisionFlags::CC);
+ // Transform position from world to shape space
+ collData.localNewPos = world2Shape.transform(collData.newPos);
+ collData.localOldPos = world2ShapeOld.transform(collData.oldPos);
+ collData.c0 = constraintBufs.constraint0Buf + collData.origParticleIndex;
+ collData.c1 = constraintBufs.constraint1Buf + collData.origParticleIndex;
+ collData.localSurfaceNormal = PxVec3(0.0f);
+ collData.localSurfacePos = PxVec3(0.0f);
+ }
+
+ switch(shape.getType())
+ {
+ case PxGeometryType::eSPHERE:
+ {
+ collideWithSphere(particleCollData, numParticles, shape, mParams.contactOffset);
+ break;
+ }
+ case PxGeometryType::ePLANE:
+ {
+ collideWithPlane(particleCollData, numParticles, shape, mParams.contactOffset);
+ break;
+ }
+ case PxGeometryType::eCAPSULE:
+ {
+ collideWithCapsule(particleCollData, numParticles, shape, mParams.contactOffset);
+ break;
+ }
+ case PxGeometryType::eBOX:
+ {
+ collideWithBox(particleCollData, numParticles, shape, mParams.contactOffset);
+ break;
+ }
+ case PxGeometryType::eCONVEXMESH:
+ {
+ const PxConvexMeshGeometryLL& convexShapeData = shape.get<const PxConvexMeshGeometryLL>();
+ const Gu::ConvexHullData* convexHullData = convexShapeData.hullData;
+ PX_ASSERT(convexHullData);
+
+ PX_ALLOCA(scaledPlanesBuf, PxPlane, convexHullData->mNbPolygons);
+ collideWithConvex(scaledPlanesBuf, particleCollData, numParticles, shape, mParams.contactOffset);
+ break;
+ }
+ case PxGeometryType::eTRIANGLEMESH:
+ {
+ if(opcodeCacheLocal)
+ {
+ collideWithStaticMesh(numParticles, particleCollData, opcodeCacheLocal, shape, world2Shape, shape2World,
+ mParams.cellSize, mParams.collisionRange, mParams.contactOffset);
+ }
+ else
+ {
+ // Compute cell hash if needed
+ if(!localCellHash.isHashValid)
+ {
+ PX_ALLOCA(hashKeyArray, PxU16, numParticles * sizeof(PxU16)); // save the hashkey for reorder
+ PX_ASSERT(hashKeyArray);
+ computeLocalCellHash(localCellHash, hashKeyArray, particles, numParticles, packetCorner,
+ mParams.cellSizeInv);
+ }
+
+ collideCellsWithStaticMesh(particleCollData, localCellHash, shape, world2Shape, shape2World,
+ mParams.cellSize, mParams.collisionRange, mParams.contactOffset, packetCorner);
+ }
+ isStaticMeshType = true;
+ break;
+ }
+ case PxGeometryType::eHEIGHTFIELD:
+ {
+ collideWithStaticHeightField(particleCollData, numParticles, shape, mParams.contactOffset, shape2World);
+ isStaticMeshType = true;
+ break;
+ }
+ case PxGeometryType::eGEOMETRY_COUNT:
+ case PxGeometryType::eINVALID:
+ PX_ASSERT(0);
+ }
+
+ if(isStaticMeshType)
+ {
+ for(PxU32 p = 0; p < numParticles; p++)
+ {
+ ParticleCollData& collData = particleCollData[p];
+ updateCollDataStaticMesh(collData, shape2World, mParams.timeStep);
+ }
+ }
+ else if(body)
+ {
+ for(PxU32 p = 0; p < numParticles; p++)
+ {
+ ParticleCollData& collData = particleCollData[p];
+ ConstraintDynamic cdTemp;
+ ConstraintDynamic& c0Dynamic = constraintBufs.constraint0DynamicBuf
+ ? constraintBufs.constraint0DynamicBuf[collData.origParticleIndex]
+ : cdTemp;
+ ConstraintDynamic& c1Dynamic = constraintBufs.constraint1DynamicBuf
+ ? constraintBufs.constraint1DynamicBuf[collData.origParticleIndex]
+ : cdTemp;
+ c0Dynamic.setEmpty();
+ c1Dynamic.setEmpty();
+ updateCollDataDynamic(collData, body->body2World, body->linearVelocity, body->angularVelocity, body,
+ shape2World, mParams.timeStep, c0Dynamic, c1Dynamic);
+ }
+ }
+ else
+ {
+ for(PxU32 p = 0; p < numParticles; p++)
+ {
+ ParticleCollData& collData = particleCollData[p];
+
+ updateCollDataStatic(collData, shape2World, mParams.timeStep);
+ }
+ }
+
+ if(contactManager.isDrain)
+ {
+ for(PxU32 p = 0; p < numParticles; p++)
+ {
+ ParticleCollData& collData = particleCollData[p];
+
+ if((collData.localFlags & ParticleCollisionFlags::L_ANY) != 0)
+ {
+ collData.particleFlags.api |= PxParticleFlag::eCOLLISION_WITH_DRAIN;
+ }
+ }
+ }
+}
+
+#endif // PX_USE_PARTICLE_SYSTEM_API