827 lines
29 KiB
C++
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
|