Files
XCEngine/engine/third_party/physx/source/physxextensions/src/ExtParticleExt.cpp

827 lines
29 KiB
C++

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2025 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 "PxParticleBuffer.h"
#include "extensions/PxCudaHelpersExt.h"
#include "extensions/PxParticleExt.h"
#include "foundation/PxUserAllocated.h"
#include "PxScene.h"
#include "PxPhysics.h"
#include "PxRigidBody.h"
#include "cudamanager/PxCudaContextManager.h"
#include "cudamanager/PxCudaContext.h"
namespace physx
{
namespace ExtGpu
{
void PxDmaDataToDevice(PxCudaContextManager* cudaContextManager, PxParticleBuffer* particleBuffer, const PxParticleBufferDesc& desc)
{
#if PX_SUPPORT_GPU_PHYSX
cudaContextManager->acquireContext();
PxVec4* posInvMass = particleBuffer->getPositionInvMasses();
PxVec4* velocities = particleBuffer->getVelocities();
PxU32* phases = particleBuffer->getPhases();
PxParticleVolume* volumes = particleBuffer->getParticleVolumes();
PxCudaContext* cudaContext = cudaContextManager->getCudaContext();
//KS - TODO - use an event to wait for this
cudaContext->memcpyHtoDAsync(CUdeviceptr(posInvMass), desc.positions, desc.numActiveParticles * sizeof(PxVec4), 0);
cudaContext->memcpyHtoDAsync(CUdeviceptr(velocities), desc.velocities, desc.numActiveParticles * sizeof(PxVec4), 0);
cudaContext->memcpyHtoDAsync(CUdeviceptr(phases), desc.phases, desc.numActiveParticles * sizeof(PxU32), 0);
cudaContext->memcpyHtoDAsync(CUdeviceptr(volumes), desc.volumes, desc.numVolumes * sizeof(PxParticleVolume), 0);
particleBuffer->setNbActiveParticles(desc.numActiveParticles);
particleBuffer->setNbParticleVolumes(desc.numVolumes);
cudaContext->streamSynchronize(0);
cudaContextManager->releaseContext();
#else
PX_UNUSED(cudaContextManager);
PX_UNUSED(particleBuffer);
PX_UNUSED(desc);
#endif
}
PxParticleBuffer* PxCreateAndPopulateParticleBuffer(const PxParticleBufferDesc& desc, PxCudaContextManager* cudaContextManager)
{
PxParticleBuffer* particleBuffer = PxGetPhysics().createParticleBuffer(desc.maxParticles, desc.maxVolumes, cudaContextManager);
PxDmaDataToDevice(cudaContextManager, particleBuffer, desc);
return particleBuffer;
}
PxParticleAndDiffuseBuffer* PxCreateAndPopulateParticleAndDiffuseBuffer(const PxParticleAndDiffuseBufferDesc& desc, PxCudaContextManager* cudaContextManager)
{
PxParticleAndDiffuseBuffer* particleBuffer = PxGetPhysics().createParticleAndDiffuseBuffer(desc.maxParticles, desc.maxVolumes, desc.maxDiffuseParticles, cudaContextManager);
PxDmaDataToDevice(cudaContextManager, particleBuffer, desc);
particleBuffer->setMaxActiveDiffuseParticles(desc.maxActiveDiffuseParticles);
return particleBuffer;
}
PxParticleClothBuffer* PxCreateAndPopulateParticleClothBuffer(const PxParticleBufferDesc& desc, const PxParticleClothDesc& clothDesc, PxPartitionedParticleCloth& output, PxCudaContextManager* cudaContextManager)
{
#if PX_SUPPORT_GPU_PHYSX
cudaContextManager->acquireContext();
PxParticleClothBuffer* clothBuffer = PxGetPhysics().createParticleClothBuffer(desc.maxParticles, desc.maxVolumes, clothDesc.nbCloths, clothDesc.nbTriangles, clothDesc.nbSprings, cudaContextManager);
PxVec4* posInvMass = clothBuffer->getPositionInvMasses();
PxVec4* velocities = clothBuffer->getVelocities();
PxU32* phases = clothBuffer->getPhases();
PxParticleVolume* volumes = clothBuffer->getParticleVolumes();
PxU32* triangles = clothBuffer->getTriangles();
PxVec4* restPositions = clothBuffer->getRestPositions();
PxCudaContext* cudaContext = cudaContextManager->getCudaContext();
cudaContext->memcpyHtoDAsync(CUdeviceptr(posInvMass), desc.positions, desc.numActiveParticles * sizeof(PxVec4), 0);
cudaContext->memcpyHtoDAsync(CUdeviceptr(velocities), desc.velocities, desc.numActiveParticles * sizeof(PxVec4), 0);
cudaContext->memcpyHtoDAsync(CUdeviceptr(phases), desc.phases, desc.numActiveParticles * sizeof(PxU32), 0);
cudaContext->memcpyHtoDAsync(CUdeviceptr(volumes), desc.volumes, desc.numVolumes * sizeof(PxParticleVolume), 0);
cudaContext->memcpyHtoDAsync(CUdeviceptr(triangles), clothDesc.triangles, clothDesc.nbTriangles * sizeof(PxU32) * 3, 0);
cudaContext->memcpyHtoDAsync(CUdeviceptr(restPositions), clothDesc.restPositions, desc.numActiveParticles * sizeof(PxVec4), 0);
clothBuffer->setNbActiveParticles(desc.numActiveParticles);
clothBuffer->setNbParticleVolumes(desc.numVolumes);
clothBuffer->setNbTriangles(clothDesc.nbTriangles);
clothBuffer->setCloths(output);
cudaContext->streamSynchronize(0);
cudaContextManager->releaseContext();
return clothBuffer;
#else
PX_UNUSED(desc);
PX_UNUSED(clothDesc);
PX_UNUSED(output);
PX_UNUSED(cudaContextManager);
return NULL;
#endif
}
PxParticleRigidBuffer* PxCreateAndPopulateParticleRigidBuffer(const PxParticleBufferDesc& desc, const PxParticleRigidDesc& rigidDesc, PxCudaContextManager* cudaContextManager)
{
#if PX_SUPPORT_GPU_PHYSX
cudaContextManager->acquireContext();
PxParticleRigidBuffer* rigidBuffer = PxGetPhysics().createParticleRigidBuffer(desc.maxParticles, desc.maxVolumes, rigidDesc.maxRigids, cudaContextManager);
PxVec4* posInvMassd = rigidBuffer->getPositionInvMasses();
PxVec4* velocitiesd = rigidBuffer->getVelocities();
PxU32* phasesd = rigidBuffer->getPhases();
PxParticleVolume* volumesd = rigidBuffer->getParticleVolumes();
PxU32* rigidOffsetsd = rigidBuffer->getRigidOffsets();
PxReal* rigidCoefficientsd = rigidBuffer->getRigidCoefficients();
PxVec4* rigidTranslationsd = rigidBuffer->getRigidTranslations();
PxVec4* rigidRotationsd = rigidBuffer->getRigidRotations();
PxVec4* rigidLocalPositionsd = rigidBuffer->getRigidLocalPositions();
PxVec4* rigidLocalNormalsd = rigidBuffer->getRigidLocalNormals();
PxCudaContext* cudaContext = cudaContextManager->getCudaContext();
const PxU32 numRigids = rigidDesc.numActiveRigids;
const PxU32 numActiveParticles = desc.numActiveParticles;
cudaContext->memcpyHtoDAsync(CUdeviceptr(posInvMassd), desc.positions, numActiveParticles * sizeof(PxVec4), 0);
cudaContext->memcpyHtoDAsync(CUdeviceptr(velocitiesd), desc.velocities, numActiveParticles * sizeof(PxVec4), 0);
cudaContext->memcpyHtoDAsync(CUdeviceptr(phasesd), desc.phases, numActiveParticles * sizeof(PxU32), 0);
cudaContext->memcpyHtoDAsync(CUdeviceptr(volumesd), desc.volumes, desc.numVolumes * sizeof(PxParticleVolume), 0);
cudaContext->memcpyHtoDAsync(CUdeviceptr(rigidOffsetsd), rigidDesc.rigidOffsets, sizeof(PxU32) * (numRigids + 1), 0);
cudaContext->memcpyHtoDAsync(CUdeviceptr(rigidCoefficientsd), rigidDesc.rigidCoefficients, sizeof(PxReal) * numRigids, 0);
cudaContext->memcpyHtoDAsync(CUdeviceptr(rigidTranslationsd), rigidDesc.rigidTranslations, sizeof(PxVec4) * numRigids, 0);
cudaContext->memcpyHtoDAsync(CUdeviceptr(rigidRotationsd), rigidDesc.rigidRotations, sizeof(PxQuat) * numRigids, 0);
cudaContext->memcpyHtoDAsync(CUdeviceptr(rigidLocalPositionsd), rigidDesc.rigidLocalPositions, sizeof(PxVec4) * desc.numActiveParticles, 0);
cudaContext->memcpyHtoDAsync(CUdeviceptr(rigidLocalNormalsd), rigidDesc.rigidLocalNormals, sizeof(PxVec4) * desc.numActiveParticles, 0);
rigidBuffer->setNbActiveParticles(numActiveParticles);
rigidBuffer->setNbRigids(numRigids);
rigidBuffer->setNbParticleVolumes(desc.numVolumes);
cudaContext->streamSynchronize(0);
cudaContextManager->releaseContext();
return rigidBuffer;
#else
PX_UNUSED(desc);
PX_UNUSED(rigidDesc);
PX_UNUSED(cudaContextManager);
return NULL;
#endif
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
PxParticleAttachmentBuffer::PxParticleAttachmentBuffer(PxParticleBuffer& particleBuffer, PxPBDParticleSystem& particleSystem) : mParticleBuffer(particleBuffer),
mDeviceAttachments(NULL), mDeviceFilters(NULL), mNumDeviceAttachments(0), mNumDeviceFilters(0), mCudaContextManager(particleSystem.getCudaContextManager()),
mParticleSystem(particleSystem), mDirty(false)
{
}
PxParticleAttachmentBuffer::~PxParticleAttachmentBuffer()
{
#if PX_SUPPORT_GPU_PHYSX
mCudaContextManager->acquireContext();
PxCudaContext* cudaContext = mCudaContextManager->getCudaContext();
if (mDeviceAttachments)
cudaContext->memFree((CUdeviceptr)mDeviceAttachments);
if (mDeviceFilters)
cudaContext->memFree((CUdeviceptr)mDeviceFilters);
mDeviceAttachments = NULL;
mDeviceFilters = NULL;
mCudaContextManager->releaseContext();
#endif
}
void PxParticleAttachmentBuffer::copyToDevice(CUstream stream)
{
#if PX_SUPPORT_GPU_PHYSX
mCudaContextManager->acquireContext();
PxCudaContext* cudaContext = mCudaContextManager->getCudaContext();
if (mAttachments.size() > mNumDeviceAttachments)
{
if (mDeviceAttachments)
cudaContext->memFree((CUdeviceptr)mDeviceAttachments);
cudaContext->memAlloc((CUdeviceptr*)&mDeviceAttachments, sizeof(PxParticleRigidAttachment)*mAttachments.size());
mNumDeviceAttachments = mAttachments.size();
}
if (mFilters.size() > mNumDeviceFilters)
{
if (mDeviceFilters)
cudaContext->memFree((CUdeviceptr)mDeviceFilters);
cudaContext->memAlloc((CUdeviceptr*)&mDeviceFilters, sizeof(PxParticleRigidFilterPair)*mFilters.size());
mNumDeviceFilters = mFilters.size();
}
if (mAttachments.size())
cudaContext->memcpyHtoDAsync((CUdeviceptr)mDeviceAttachments, mAttachments.begin(), sizeof(PxParticleRigidAttachment)*mAttachments.size(), stream);
if (mFilters.size())
cudaContext->memcpyHtoDAsync((CUdeviceptr)mDeviceFilters, mFilters.begin(), sizeof(PxParticleRigidFilterPair)*mFilters.size(), stream);
mParticleBuffer.setRigidAttachments(mDeviceAttachments, mAttachments.size());
mParticleBuffer.setRigidFilters(mDeviceFilters, mFilters.size());
mDirty = true;
for (PxU32 i = 0; i < mNewReferencedBodies.size(); ++i)
{
if (mReferencedBodies[mNewReferencedBodies[i]] > 0)
mParticleSystem.addRigidAttachment(mNewReferencedBodies[i]);
}
for (PxU32 i = 0; i < mDestroyedRefrencedBodies.size(); ++i)
{
if (mReferencedBodies[mDestroyedRefrencedBodies[i]] == 0)
mParticleSystem.removeRigidAttachment(mDestroyedRefrencedBodies[i]);
}
mNewReferencedBodies.resize(0);
mDestroyedRefrencedBodies.resize(0);
mCudaContextManager->releaseContext();
#else
PX_UNUSED(stream);
#endif
}
void PxParticleAttachmentBuffer::addRigidAttachment(PxRigidActor* rigidActor, const PxU32 particleID, const PxVec3& localPose, PxConeLimitedConstraint* coneLimit)
{
PX_CHECK_AND_RETURN(coneLimit == NULL || coneLimit->isValid(), "PxParticleAttachmentBuffer::addRigidAttachment: PxConeLimitedConstraint needs to be valid if specified.");
PX_ASSERT(particleID < mParticleBuffer.getNbActiveParticles());
PxParticleRigidAttachment attachment(PxConeLimitedConstraint(), PxVec4(0.0f));
if (rigidActor == NULL)
{
PxGetFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, PX_FL,
"PxParticleAttachmentBuffer::addRigidAttachment: rigidActor cannot be NULL.");
return;
}
if (coneLimit)
{
attachment.mConeLimitParams.axisAngle = PxVec4(coneLimit->mAxis, coneLimit->mAngle);
attachment.mConeLimitParams.lowHighLimits = PxVec4(coneLimit->mLowLimit, coneLimit->mHighLimit, 0.f, 0.f);
}
if (rigidActor->getType() == PxActorType::eRIGID_STATIC)
{
// attachments to rigid static work in global space
attachment.mLocalPose0 = PxVec4(static_cast<PxRigidBody*>(rigidActor)->getGlobalPose().transform(localPose), 0.0f);
attachment.mID0 = PxNodeIndex().getInd();
}
else
{
// others use body space.
PxRigidBody* rigid = static_cast<PxRigidBody*>(rigidActor);
PxTransform body2Actor = rigid->getCMassLocalPose();
attachment.mLocalPose0 = PxVec4(body2Actor.transformInv(localPose), 0.f);
attachment.mID0 = rigid->getInternalIslandNodeIndex().getInd();
}
attachment.mID1 = particleID;
//Insert in order...
PxU32 l = 0, r = PxU32(mAttachments.size());
while (l < r) //If difference is just 1, we've found an item...
{
PxU32 index = (l + r) / 2;
if (attachment < mAttachments[index])
r = index;
else if (attachment > mAttachments[index])
l = index + 1;
else
l = r = index; //This is a match so insert before l
}
mAttachments.insert();
for (PxU32 i = mAttachments.size()-1; i > l; --i)
{
mAttachments[i] = mAttachments[i - 1];
}
mAttachments[l] = attachment;
mDirty = true;
if (rigidActor)
{
PxU32& refCount = mReferencedBodies[rigidActor];
if (refCount == 0)
mNewReferencedBodies.pushBack(rigidActor);
refCount++;
}
}
bool PxParticleAttachmentBuffer::removeRigidAttachment(PxRigidActor* rigidActor, const PxU32 particleID)
{
PX_ASSERT(particleID < mParticleBuffer.getNbActiveParticles());
if (rigidActor == NULL)
{
PxGetFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, PX_FL,
"PxParticleAttachmentBuffer::removeRigidAttachment: rigidActor cannot be NULL.");
return false;
}
if (rigidActor)
{
PxU32& refCount = mReferencedBodies[rigidActor];
refCount--;
if (refCount == 0)
mDestroyedRefrencedBodies.pushBack(rigidActor);
}
PxParticleRigidFilterPair attachment;
attachment.mID0 = rigidActor->getType() != PxActorType::eRIGID_STATIC ? static_cast<PxRigidBody*>(rigidActor)->getInternalIslandNodeIndex().getInd() :
PxNodeIndex().getInd();
attachment.mID1 = particleID;
PxU32 l = 0, r = PxU32(mAttachments.size());
while (l < r) //If difference is just 1, we've found an item...
{
PxU32 index = (l + r) / 2;
if (attachment < mAttachments[index])
r = index;
else if (attachment > mAttachments[index])
l = index + 1;
else
l = r = index; //This is a match so insert before l
}
if (mAttachments[l] == attachment)
{
mDirty = true;
//Remove
mAttachments.remove(l);
return true;
}
return false;
}
void PxParticleAttachmentBuffer::addRigidFilter(PxRigidActor* rigidActor, const PxU32 particleID)
{
PX_ASSERT(particleID < mParticleBuffer.getNbActiveParticles());
PxParticleRigidFilterPair attachment;
attachment.mID0 = rigidActor->getType() != PxActorType::eRIGID_STATIC ? static_cast<PxRigidBody*>(rigidActor)->getInternalIslandNodeIndex().getInd() :
PxNodeIndex().getInd();
attachment.mID1 = particleID;
//Insert in order...
PxU32 l = 0, r = PxU32(mFilters.size());
while (l < r) //If difference is just 1, we've found an item...
{
PxU32 index = (l + r) / 2;
if (attachment < mFilters[index])
r = index;
else if (attachment > mFilters[index])
l = index + 1;
else
l = r = index; //This is a match so insert before l
}
mFilters.insert();
for (PxU32 i = mFilters.size() - 1; i > l; --i)
{
mFilters[i] = mFilters[i - 1];
}
mFilters[l] = attachment;
mDirty = true;
}
bool PxParticleAttachmentBuffer::removeRigidFilter(PxRigidActor* rigidActor, const PxU32 particleID)
{
PX_ASSERT(particleID < mParticleBuffer.getNbActiveParticles());
PxParticleRigidFilterPair attachment;
attachment.mID0 = rigidActor->getType() != PxActorType::eRIGID_STATIC ? static_cast<PxRigidBody*>(rigidActor)->getInternalIslandNodeIndex().getInd() :
PxNodeIndex().getInd();
attachment.mID1 = particleID;
PxU32 l = 0, r = PxU32(mFilters.size());
while (l < r) //If difference is just 1, we've found an item...
{
PxU32 index = (l + r) / 2;
if (attachment < mFilters[index])
r = index;
else if (attachment > mFilters[index])
l = index + 1;
else
l = r = index; //This is a match so insert before l
}
if (mFilters[l] == attachment)
{
mDirty = true;
//Remove
mFilters.remove(l);
return true;
}
return false;
}
PxParticleAttachmentBuffer* PxCreateParticleAttachmentBuffer(PxParticleBuffer& buffer, PxParticleSystem& particleSystem)
{
return PX_NEW(PxParticleAttachmentBuffer)(buffer, particleSystem);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct ParticleClothBuffersImpl : public PxParticleClothBufferHelper, public PxUserAllocated
{
ParticleClothBuffersImpl(const PxU32 maxCloths, const PxU32 maxTriangles, const PxU32 maxSprings, const PxU32 maxParticles, PxCudaContextManager* cudaContextManager)
: mCudaContextManager(cudaContextManager)
{
mMaxParticles = maxParticles;
mClothDesc.nbParticles = 0;
mMaxTriangles = maxTriangles;
mClothDesc.nbTriangles = 0;
mMaxSprings = maxSprings;
mClothDesc.nbSprings = 0;
mMaxCloths = maxCloths;
mClothDesc.nbCloths = 0;
#if PX_SUPPORT_GPU_PHYSX
mClothDesc.restPositions = PX_EXT_PINNED_MEMORY_ALLOC(PxVec4, *mCudaContextManager, maxParticles);
mClothDesc.triangles = PX_EXT_PINNED_MEMORY_ALLOC(PxU32, *mCudaContextManager, maxTriangles * 3);
mClothDesc.springs = PX_EXT_PINNED_MEMORY_ALLOC(PxParticleSpring, *mCudaContextManager, maxSprings);
mClothDesc.cloths = PX_EXT_PINNED_MEMORY_ALLOC(PxParticleCloth, *mCudaContextManager, maxCloths);
#endif
}
void release()
{
#if PX_SUPPORT_GPU_PHYSX
PX_EXT_PINNED_MEMORY_FREE(*mCudaContextManager, mClothDesc.cloths);
PX_EXT_PINNED_MEMORY_FREE(*mCudaContextManager, mClothDesc.restPositions);
PX_EXT_PINNED_MEMORY_FREE(*mCudaContextManager, mClothDesc.triangles);
PX_EXT_PINNED_MEMORY_FREE(*mCudaContextManager, mClothDesc.springs);
#endif
PX_DELETE_THIS;
}
PxU32 getMaxCloths() const { return mMaxCloths; }
PxU32 getNumCloths() const { return mClothDesc.nbCloths; }
PxU32 getMaxSprings() const { return mMaxSprings; }
PxU32 getNumSprings() const { return mClothDesc.nbSprings; }
PxU32 getMaxTriangles() const { return mMaxTriangles; }
PxU32 getNumTriangles() const { return mClothDesc.nbTriangles; }
PxU32 getMaxParticles() const { return mMaxParticles; }
PxU32 getNumParticles() const { return mClothDesc.nbParticles; }
void addCloth(const PxParticleCloth& particleCloth, const PxU32* triangles, const PxU32 numTriangles,
const PxParticleSpring* springs, const PxU32 numSprings, const PxVec4* restPositions, const PxU32 numParticles)
{
if (mClothDesc.nbCloths + 1 > mMaxCloths)
{
PxGetFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, PX_FL,
"PxParticleClothBufferHelper::addCloth: exceeding maximal number of cloths that can be added.");
return;
}
if (mClothDesc.nbSprings + numSprings > mMaxSprings)
{
PxGetFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, PX_FL,
"PxParticleClothBufferHelper::addCloth: exceeding maximal number of springs that can be added.");
return;
}
if (mClothDesc.nbTriangles + numTriangles > mMaxTriangles)
{
PxGetFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, PX_FL,
"PxParticleClothBufferHelper::addCloth: exceeding maximal number of triangles that can be added.");
return;
}
if (mClothDesc.nbParticles + numParticles > mMaxParticles)
{
PxGetFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, PX_FL,
"PxParticleClothBufferHelper::addCloth: exceeding maximal number of particles that can be added.");
return;
}
mClothDesc.cloths[mClothDesc.nbCloths] = particleCloth;
mClothDesc.nbCloths += 1;
for (PxU32 i = 0; i < numSprings; ++i)
{
PxParticleSpring& dst = mClothDesc.springs[mClothDesc.nbSprings + i];
dst = springs[i];
dst.ind0 += mClothDesc.nbParticles;
dst.ind1 += mClothDesc.nbParticles;
}
mClothDesc.nbSprings += numSprings;
for (PxU32 i = 0; i < numTriangles*3; ++i)
{
PxU32& dst = mClothDesc.triangles[mClothDesc.nbTriangles*3 + i];
dst = triangles[i] + mClothDesc.nbParticles;
}
mClothDesc.nbTriangles += numTriangles;
PxMemCopy(mClothDesc.restPositions + mClothDesc.nbParticles, restPositions, sizeof(PxVec4)*numParticles);
mClothDesc.nbParticles += numParticles;
}
void addCloth(const PxReal blendScale, const PxReal restVolume, const PxReal pressure, const PxU32* triangles, const PxU32 numTriangles,
const PxParticleSpring* springs, const PxU32 numSprings, const PxVec4* restPositions, const PxU32 numParticles)
{
PX_UNUSED(blendScale);
PxParticleCloth particleCloth;
//particleCloth.clothBlendScale = blendScale;
particleCloth.restVolume = restVolume;
particleCloth.pressure = pressure;
particleCloth.startVertexIndex = mClothDesc.nbParticles;
particleCloth.numVertices = numParticles;
particleCloth.startTriangleIndex = mClothDesc.nbTriangles * 3;
particleCloth.numTriangles = numTriangles;
addCloth(particleCloth, triangles, numTriangles, springs, numSprings, restPositions, numParticles);
}
PxParticleClothDesc& getParticleClothDesc()
{
return mClothDesc;
}
PxU32 mMaxCloths;
PxU32 mMaxSprings;
PxU32 mMaxTriangles;
PxU32 mMaxParticles;
PxParticleClothDesc mClothDesc;
PxCudaContextManager* mCudaContextManager;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct ParticleVolumeBuffersImpl : public PxParticleVolumeBufferHelper, public PxUserAllocated
{
ParticleVolumeBuffersImpl(PxU32 maxVolumes, PxU32 maxTriangles, PxCudaContextManager* cudaContextManager)
{
mMaxVolumes = maxVolumes;
mNumVolumes = 0;
mMaxTriangles = maxTriangles;
mNumTriangles = 0;
mParticleVolumeMeshes = reinterpret_cast<PxParticleVolumeMesh*>(PX_ALLOC(sizeof(PxParticleVolumeMesh) * maxVolumes, "ParticleVolumeBuffersImpl::mParticleVolumeMeshes"));
mTriangles = reinterpret_cast<PxU32*>(PX_ALLOC(sizeof(PxU32) * maxTriangles * 3, "ParticleVolumeBuffersImpl::mTriangles"));
#if PX_SUPPORT_GPU_PHYSX
mParticleVolumes = PX_EXT_PINNED_MEMORY_ALLOC(PxParticleVolume, *cudaContextManager, maxVolumes);
mCudaContextManager = cudaContextManager;
#else
PX_UNUSED(cudaContextManager);
#endif
}
void release()
{
#if PX_SUPPORT_GPU_PHYSX
PX_EXT_PINNED_MEMORY_FREE(*mCudaContextManager, mParticleVolumes);
#endif
PX_FREE(mParticleVolumeMeshes);
PX_FREE(mTriangles);
PX_DELETE_THIS;
}
virtual PxU32 getMaxVolumes() const
{
return mMaxVolumes;
}
virtual PxU32 getNumVolumes() const
{
return mNumVolumes;
}
virtual PxU32 getMaxTriangles() const
{
return mMaxTriangles;
}
virtual PxU32 getNumTriangles() const
{
return mNumTriangles;
}
virtual PxParticleVolume* getParticleVolumes()
{
return mParticleVolumes;
}
virtual PxParticleVolumeMesh* getParticleVolumeMeshes()
{
return mParticleVolumeMeshes;
}
virtual PxU32* getTriangles()
{
return mTriangles;
}
virtual void addVolume(const PxParticleVolume& volume, const PxParticleVolumeMesh& volumeMesh, const PxU32* triangles, const PxU32 numTriangles)
{
if (mNumVolumes < mMaxVolumes && mNumTriangles + numTriangles <= mMaxTriangles)
{
PX_ASSERT(volumeMesh.startIndex == mNumTriangles);
mParticleVolumes[mNumVolumes] = volume;
mParticleVolumeMeshes[mNumVolumes] = volumeMesh;
mNumVolumes++;
for (PxU32 i = 0; i < numTriangles*3; ++i)
{
mTriangles[mNumTriangles*3 + i] = triangles[i] + volumeMesh.startIndex;
}
mNumTriangles += numTriangles;
}
}
virtual void addVolume(const PxU32 particleOffset, const PxU32 numParticles, const PxU32* triangles, const PxU32 numTriangles)
{
if (mNumVolumes < mMaxVolumes && mNumTriangles + numTriangles <= mMaxTriangles)
{
PxParticleVolume particleVolume;
particleVolume.bound.setEmpty();
particleVolume.particleIndicesOffset = particleOffset;
particleVolume.numParticles = numParticles;
PxParticleVolumeMesh particleVolumeMesh;
particleVolumeMesh.startIndex = mNumTriangles;
particleVolumeMesh.count = numTriangles;
mParticleVolumes[mNumVolumes] = particleVolume;
mParticleVolumeMeshes[mNumVolumes] = particleVolumeMesh;
mNumVolumes++;
for (PxU32 i = 0; i < numTriangles*3; ++i)
{
mTriangles[mNumTriangles*3 + i] = triangles[i] + particleOffset;
}
mNumTriangles += numTriangles;
}
}
PxU32 mMaxVolumes;
PxU32 mNumVolumes;
PxU32 mMaxTriangles;
PxU32 mNumTriangles;
PxParticleVolume* mParticleVolumes;
PxParticleVolumeMesh* mParticleVolumeMeshes;
PxU32* mTriangles;
PxCudaContextManager* mCudaContextManager;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
struct ParticleRigidBuffersImpl : public PxParticleRigidBufferHelper, public PxUserAllocated
{
ParticleRigidBuffersImpl(PxU32 maxRigids, PxU32 maxParticles, PxCudaContextManager* cudaContextManager)
: mCudaContextManager(cudaContextManager)
{
mRigidDesc.maxRigids = maxRigids;
mRigidDesc.numActiveRigids = 0;
mMaxParticles = maxParticles;
mNumParticles = 0;
#if PX_SUPPORT_GPU_PHYSX
mRigidDesc.rigidOffsets = PX_EXT_PINNED_MEMORY_ALLOC(PxU32, *mCudaContextManager, maxRigids + 1);
mRigidDesc.rigidCoefficients = PX_EXT_PINNED_MEMORY_ALLOC(PxReal, *mCudaContextManager, maxRigids);
mRigidDesc.rigidTranslations = PX_EXT_PINNED_MEMORY_ALLOC(PxVec4, *mCudaContextManager, maxRigids);
mRigidDesc.rigidRotations = PX_EXT_PINNED_MEMORY_ALLOC(PxQuat, *mCudaContextManager, maxRigids);
mRigidDesc.rigidLocalPositions = PX_EXT_PINNED_MEMORY_ALLOC(PxVec4, *mCudaContextManager, maxParticles);
mRigidDesc.rigidLocalNormals = PX_EXT_PINNED_MEMORY_ALLOC(PxVec4, *mCudaContextManager, maxParticles);
#endif
}
void release()
{
#if PX_SUPPORT_GPU_PHYSX
PX_EXT_PINNED_MEMORY_FREE(*mCudaContextManager, mRigidDesc.rigidOffsets);
PX_EXT_PINNED_MEMORY_FREE(*mCudaContextManager, mRigidDesc.rigidCoefficients);
PX_EXT_PINNED_MEMORY_FREE(*mCudaContextManager, mRigidDesc.rigidTranslations);
PX_EXT_PINNED_MEMORY_FREE(*mCudaContextManager, mRigidDesc.rigidRotations);
PX_EXT_PINNED_MEMORY_FREE(*mCudaContextManager, mRigidDesc.rigidLocalPositions);
PX_EXT_PINNED_MEMORY_FREE(*mCudaContextManager, mRigidDesc.rigidLocalNormals);
#endif
PX_DELETE_THIS;
}
virtual PxU32 getMaxRigids() const { return mRigidDesc.maxRigids; }
virtual PxU32 getNumRigids() const { return mRigidDesc.numActiveRigids; }
virtual PxU32 getMaxParticles() const { return mMaxParticles; }
virtual PxU32 getNumParticles() const { return mNumParticles; }
void addRigid(const PxVec3& translation, const PxQuat& rotation, const PxReal coefficient,
const PxVec4* localPositions, const PxVec4* localNormals, PxU32 numParticles)
{
PX_ASSERT(numParticles > 0);
const PxU32 numRigids = mRigidDesc.numActiveRigids;
if (numParticles > 0 && numRigids < mRigidDesc.maxRigids && mNumParticles + numParticles <= mMaxParticles)
{
mRigidDesc.rigidOffsets[numRigids] = mNumParticles;
mRigidDesc.rigidOffsets[numRigids + 1] = mNumParticles + numParticles;
mRigidDesc.rigidTranslations[numRigids] = PxVec4(translation, 0.0f);
mRigidDesc.rigidRotations[numRigids] = rotation;
mRigidDesc.rigidCoefficients[numRigids] = coefficient;
PxMemCopy(mRigidDesc.rigidLocalPositions + mNumParticles, localPositions, numParticles * sizeof(PxVec4));
PxMemCopy(mRigidDesc.rigidLocalNormals + mNumParticles, localNormals, numParticles * sizeof(PxVec4));
mRigidDesc.numActiveRigids += 1;
mNumParticles += numParticles;
}
}
PxParticleRigidDesc& getParticleRigidDesc()
{
return mRigidDesc;
}
PxU32 mMaxParticles;
PxU32 mNumParticles;
PxParticleRigidDesc mRigidDesc;
PxCudaContextManager* mCudaContextManager;
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
PxParticleVolumeBufferHelper* PxCreateParticleVolumeBufferHelper(PxU32 maxVolumes, PxU32 maxTriangles, PxCudaContextManager* cudaContextManager)
{
PxParticleVolumeBufferHelper* ret = NULL;
#if PX_SUPPORT_GPU_PHYSX
ret = PX_NEW(ParticleVolumeBuffersImpl)(maxVolumes, maxTriangles, cudaContextManager);
#else
PX_UNUSED(maxVolumes);
PX_UNUSED(maxTriangles);
PX_UNUSED(cudaContextManager);
#endif
return ret;
}
PxParticleClothBufferHelper* PxCreateParticleClothBufferHelper(const PxU32 maxCloths, const PxU32 maxTriangles, const PxU32 maxSprings, const PxU32 maxParticles, PxCudaContextManager* cudaContextManager)
{
PxParticleClothBufferHelper* ret = NULL;
#if PX_SUPPORT_GPU_PHYSX
ret = PX_NEW(ParticleClothBuffersImpl)(maxCloths, maxTriangles, maxSprings, maxParticles, cudaContextManager);
#else
PX_UNUSED(maxCloths);
PX_UNUSED(maxTriangles);
PX_UNUSED(maxSprings);
PX_UNUSED(maxParticles);
PX_UNUSED(cudaContextManager);
#endif
return ret;
}
PxParticleRigidBufferHelper* PxCreateParticleRigidBufferHelper(const PxU32 maxRigids, const PxU32 maxParticles, PxCudaContextManager* cudaContextManager)
{
PxParticleRigidBufferHelper* ret = NULL;
#if PX_SUPPORT_GPU_PHYSX
ret = PX_NEW(ParticleRigidBuffersImpl)(maxRigids, maxParticles, cudaContextManager);
#else
PX_UNUSED(maxRigids);
PX_UNUSED(maxParticles);
PX_UNUSED(cudaContextManager);
#endif
return ret;
}
} //namespace ExtGpu
} //namespace physx