// 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(rigidActor)->getGlobalPose().transform(localPose), 0.0f); attachment.mID0 = PxNodeIndex().getInd(); } else { // others use body space. PxRigidBody* rigid = static_cast(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(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(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(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(PX_ALLOC(sizeof(PxParticleVolumeMesh) * maxVolumes, "ParticleVolumeBuffersImpl::mParticleVolumeMeshes")); mTriangles = reinterpret_cast(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