triangle mesh collision with particles-cloth on GPU #34
-
Hi, thanks for your great work, I'm trying to combine "snippethelloworld" , "snippetimmediatemode" and "snippetpbdcloth" into a new demo, but "Cloth" seems doesn't has the collision with the triangles mesh, does PhysX support collision between these objetcs or how can I set flags for coolision. and the code are list here: #include "../snippetrender/SnippetCamera.h"
#include "../snippetrender/SnippetRender.h"
#include "../snippetutils/SnippetUtils.h"
#include "PxPhysicsAPI.h"
#include "cudamanager/PxCudaContext.h"
#include "cudamanager/PxCudaContextManager.h"
#include "extensions/PxParticleExt.h"
#include <iostream>
#include <vector>
using namespace physx;
using namespace ExtGpu;
static PxDefaultAllocator gAllocator;
static PxDefaultErrorCallback gErrorCallback;
static PxFoundation* gFoundation = nullptr;
static PxPhysics* gPhysics = nullptr;
static PxDefaultCpuDispatcher* gDispatcher = nullptr;
static PxScene* gScene = nullptr;
static PxMaterial* gMaterial = nullptr;
static PxPBDParticleSystem* gParticleSystem = nullptr;
static PxParticleClothBuffer* gClothBuffer = nullptr;
static bool gIsRunning = false;
Snippets::Camera* sCamera = nullptr;
PxReal simTime = 0;
Snippets::SharedGLBuffer sPosBuffer;
void keyCallback(unsigned char key, const PxTransform&) {
switch (toupper(key)) {
case ' ':
gIsRunning = !gIsRunning;
break;
default:
break;
}
}
void stepPhysics(bool) {
if (gIsRunning) {
const PxReal dt = 1.0f / 60.0f;
gScene->simulate(dt);
gScene->fetchResults(true);
gScene->fetchResultsParticleSystem();
simTime = simTime + dt;
}
}
void onBeforeRenderParticles() {
if (gParticleSystem) {
PxVec4* positions = gClothBuffer->getPositionInvMasses();
const PxU32 numParticles = gClothBuffer->getNbActiveParticles();
PxCudaContextManager* cudaContextManager = gScene->getCudaContextManager();
cudaContextManager->acquireContext();
PxCudaContext* cudaContext = cudaContextManager->getCudaContext();
cudaContext->memcpyDtoH(sPosBuffer.map(), CUdeviceptr(positions), sizeof(PxVec4) * numParticles);
cudaContextManager->releaseContext();
// #if SHOW_SOLID_SDF_SLICE
// particleSystem->copySparseGridData(sSparseGridSolidSDFBufferD, PxSparseGridDataFlag::eGRIDCELL_SOLID_GRADIENT_AND_SDF);
// #endif
}
}
void renderParticles() {
sPosBuffer.unmap();
PxVec3 color(1.0f, 0.3f, 0.5);
Snippets::DrawPoints(sPosBuffer.vbo, sPosBuffer.size / sizeof(PxVec4), color, 2.0f);
Snippets::DrawFrame(PxVec3(0, 0, 0));
}
void renderCallback() {
onBeforeRenderParticles();
stepPhysics(true); // all render/ simulate in this function.
Snippets::startRender(sCamera);
PxU32 nbActors = gScene->getNbActors(PxActorTypeFlag::eRIGID_DYNAMIC | PxActorTypeFlag::eRIGID_STATIC);
if (nbActors) {
std::vector<PxRigidActor*> actors(nbActors);
gScene->getActors(PxActorTypeFlag::eRIGID_DYNAMIC | PxActorTypeFlag::eRIGID_STATIC, reinterpret_cast<PxActor**>(&actors[0]), nbActors);
Snippets::renderActors(&actors[0], static_cast<PxU32>(actors.size()), false);
}
renderParticles();
Snippets::finishRender();
}
void cleanupPhysics() {
PX_RELEASE(gScene);
PX_RELEASE(gDispatcher);
PX_RELEASE(gFoundation);
}
void exitCallback() {
delete sCamera;
}
static PX_FORCE_INLINE PxU32 id(PxU32 x, PxU32 y, PxU32 numY) {
return x * numY + y;
}
void initCloth(const PxU32 numX, const PxU32 numZ, const PxVec3& position = PxVec3(0, 0, 0), const PxReal spacing = 0.2f, const PxReal totalClothMass = 10.0f) {
PxCudaContextManager* cudaContextManager = gScene->getCudaContextManager();
if (cudaContextManager == NULL) {
std::cout << "No cuda manager." << std::endl;
}
const PxU32 numParticles = numX * numZ;
const PxU32 numSprings = (numX - 1) * (numZ - 1) * 4 + (numX - 1) + (numZ - 1);
const PxU32 numTrianges = (numX - 1) * (numZ - 1) * 2;
const PxReal resetOffset = spacing;
const PxReal stretchStiffness = 10000.0f;
const PxReal shearStiffness = 100.0f;
const PxReal springDamping = 0.001f;
// create PBDmaterial for cloth.
PxPBDMaterial* defaultMat = gPhysics->createPBDMaterial(0.8f, 0.05f, 1e+6f, 0.001f, 0.5f, 0.005f, 0.05f, 0.0f, 0.0f);
PxPBDParticleSystem* particleSystem = gPhysics->createPBDParticleSystem(*cudaContextManager);
gParticleSystem = particleSystem;
// set particle settings.
const PxReal particleMass = totalClothMass / numParticles;
particleSystem->setRestOffset(resetOffset);
particleSystem->setContactOffset(resetOffset + 0.02f);
particleSystem->setParticleContactOffset(resetOffset + 0.02f);
particleSystem->setSolidRestOffset(resetOffset);
particleSystem->setFluidRestOffset(0.0f);
gScene->addActor(*particleSystem);
PxU32 particlePhase = gParticleSystem->createPhase(defaultMat, PxParticlePhaseFlags(PxParticlePhaseFlag::eParticlePhaseSelfCollideFilter | PxParticlePhaseFlag::eParticlePhaseSelfCollide));
PxParticleClothBufferHelper* clothBuffers = PxCreateParticleClothBufferHelper(1, numTrianges, numSprings, numParticles, cudaContextManager);
PxU32* phase = cudaContextManager->allocPinnedHostBuffer<PxU32>(numParticles);
PxVec4* positionInvMass = cudaContextManager->allocPinnedHostBuffer<PxVec4>(numParticles);
PxVec4* velocity = cudaContextManager->allocPinnedHostBuffer<PxVec4>(numParticles);
PxReal x = position.x;
PxReal y = position.y;
PxReal z = position.z;
PxReal maxZ = z;
// define springs and triangles.
PxArray<PxParticleSpring> springs; // springs.
PxArray<PxU32> triangels; // triangles vertexs.
springs.reserve(numSprings);
triangels.reserve(numTrianges * 3);
// --j0,1,2------
// i0------------
// i1------------
// i2------------
for (PxU32 i = 0; i < numX; i++) {
for (PxU32 j = 0; j < numZ; j++) {
const PxU32 index = i * numZ + j;
PxVec4 pos(x, y, z, 1.0f / particleMass); // x,y,z,invMass
phase[index] = particlePhase;
velocity[index] = PxVec4(0.0f);
positionInvMass[index] = pos;
// vertical
if (i > 0) {
PxParticleSpring spring = {id(i - 1, j, numZ), id(i, j, numZ), spacing, stretchStiffness, springDamping, 0};
springs.pushBack(spring);
}
// horizontal
if (j > 0) {
PxParticleSpring spring = {id(i, j - 1, numZ), id(i, j, numZ), spacing, stretchStiffness, springDamping, 0};
springs.pushBack(spring);
}
// duijiao
if (i > 0 && j > 0) {
PxParticleSpring spring0 = {id(i - 1, j - 1, numZ), id(i, j, numZ), PxSqrt(2.0f) * spacing, shearStiffness, springDamping, 0};
PxParticleSpring spring1 = {id(i - 1, j, numZ), id(i, j - 1, numZ), PxSqrt(2.0f) * spacing, shearStiffness, springDamping, 0};
springs.pushBack(spring0);
springs.pushBack(spring1);
// ============================================
// (i-1,j-1)0---3(i-1,j)
// | / |
// (i ,j-1)1---2(i ,j)
// ============================================
// triangle: [0, 3, 1]
triangels.pushBack(id(i - 1, j - 1, numZ));
triangels.pushBack(id(i - 1, j, numZ));
triangels.pushBack(id(i, j - 1, numZ));
// triangle: [3, 1, 2]
triangels.pushBack(id(i - 1, j, numZ));
triangels.pushBack(id(i, j - 1, numZ));
triangels.pushBack(id(i, j, numZ));
}
z = z + spacing;
}
maxZ = z - spacing;
z = position.z;
x = x + spacing;
}
PX_ASSERT(numSprings == springs.size());
PX_ASSERT(numTrianges == triangels.size() / 3);
clothBuffers->addCloth(0.0f, 0.0f, 0.0f, triangels.begin(), numTrianges, springs.begin(), numSprings, positionInvMass, numParticles);
ExtGpu::PxParticleBufferDesc bufferDesc;
bufferDesc.maxParticles = numParticles;
bufferDesc.numActiveParticles = numParticles;
bufferDesc.positions = positionInvMass;
bufferDesc.velocities = velocity;
bufferDesc.phases = phase;
const PxParticleClothDesc& clothDesc = clothBuffers->getParticleClothDesc();
PxParticleClothPreProcessor* clothPreProcessor = PxCreateParticleClothPreProcessor(cudaContextManager);
PxPartitionedParticleCloth output;
clothPreProcessor->partitionSprings(clothDesc, output);
clothPreProcessor->release();
gClothBuffer = ExtGpu::PxCreateAndPopulateParticleClothBuffer(bufferDesc, clothDesc, output, cudaContextManager);
gParticleSystem->addParticleBuffer(gClothBuffer);
clothBuffers->release();
cudaContextManager->freePinnedHostBuffer(positionInvMass);
cudaContextManager->freePinnedHostBuffer(velocity);
cudaContextManager->freePinnedHostBuffer(phase);
}
struct Triangle {
PxU32 ind0;
PxU32 ind1;
PxU32 ind2;
};
PxTriangleMesh* initMesh() {
const PxU32 gridSize = 8;
const PxReal groudSize = 100.0f;
const PxReal gridStep = groudSize / (gridSize - 1);
const PxU32 numTriangles = (gridSize - 1) * (gridSize - 1) * 2;
PxVec3 verts[gridSize * gridSize];
Triangle indices[numTriangles];
for (PxU32 z = 0; z < gridSize; ++z) { // z-axis
for (PxU32 x = 0; x < gridSize; ++x) { // x-axis
verts[z * gridSize + x] = PxVec3(-groudSize * 0.5f + x * gridStep, 0.0f, -groudSize * 0.5f + z * gridStep);
}
}
for (PxU32 z = 0; z < (gridSize - 1); ++z) {
for (PxU32 x = 0; x < (gridSize - 1); ++x) {
Triangle& tri0 = indices[(z * (gridSize - 1) + x) * 2];
Triangle& tri1 = indices[(z * (gridSize - 1) + x) * 2 + 1];
// 0-----1
// | \ |
// 3-----2
// [0, 1, 2]
tri0.ind0 = z * gridSize + x + 1;
tri0.ind1 = z * gridSize + x;
tri0.ind2 = (z + 1) * gridSize + x + 1;
// [0, 2, 3]
tri1.ind0 = (z + 1) * gridSize + x + 1;
tri1.ind1 = z * gridSize + x;
tri1.ind2 = (z + 1) * gridSize + x;
}
}
PxTriangleMeshDesc meshDesc;
meshDesc.points.data = verts;
meshDesc.points.count = gridSize * gridSize;
meshDesc.points.stride = sizeof(PxVec3);
meshDesc.triangles.data = indices;
meshDesc.triangles.count = numTriangles;
meshDesc.triangles.stride = sizeof(Triangle);
PxCookingParams cookingParams(gPhysics->getTolerancesScale());
PxTriangleMesh* mesh = PxCreateTriangleMesh(cookingParams, meshDesc, gPhysics->getPhysicsInsertionCallback());
return mesh;
}
void initPhysics() {
gFoundation = PxCreateFoundation(PX_PHYSICS_VERSION, gAllocator, gErrorCallback);
gPhysics = PxCreatePhysics(PX_PHYSICS_VERSION, *gFoundation, PxTolerancesScale(), true); // no pvd
gDispatcher = PxDefaultCpuDispatcherCreate(2);
gMaterial = gPhysics->createMaterial(0.5f, 0.5f, 0.6f);
// cuda environment.
PxCudaContextManager* cudaContextManager = NULL;
if (PxGetSuggestedCudaDeviceOrdinal(gFoundation->getErrorCallback()) >= 0) {
PxCudaContextManagerDesc cudaContextManagerDesc;
cudaContextManager = PxCreateCudaContextManager(*gFoundation, cudaContextManagerDesc, PxGetProfilerCallback());
if (cudaContextManager && !cudaContextManager->contextIsValid()) {
cudaContextManager->release();
cudaContextManager = NULL;
}
}
if (cudaContextManager == NULL) {
PxGetFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Failed to initialize CUD!\n");
}
// create scene description.
PxSceneDesc sceneDesc(gPhysics->getTolerancesScale());
sceneDesc.gravity = PxVec3(0.0f, -9.8f, 0.0f);
sceneDesc.cpuDispatcher = gDispatcher;
sceneDesc.filterShader = PxDefaultSimulationFilterShader;
sceneDesc.cudaContextManager = cudaContextManager;
sceneDesc.staticStructure = PxPruningStructureType::eDYNAMIC_AABB_TREE;
sceneDesc.flags |= PxSceneFlag::eENABLE_PCM;
sceneDesc.flags |= PxSceneFlag::eENABLE_GPU_DYNAMICS;
sceneDesc.broadPhaseType = PxBroadPhaseType::eGPU;
sceneDesc.solverType = PxSolverType::eTGS;
gScene = gPhysics->createScene(sceneDesc);
// create background
// PxRigidStatic* groundPlane = PxCreatePlane(*gPhysics, PxPlane(0, 1, 0, 0), *gMaterial);
// gScene->addActor(*groundPlane);
// create groundMesh
PxTriangleMesh* mesh = initMesh();
PxTriangleMeshGeometry geom(mesh);
PxRigidStatic* groundMesh = gPhysics->createRigidStatic(PxTransform(PxVec3(0, -1, 0)));
PxRigidActorExt::createExclusiveShape(*groundMesh, geom, *gMaterial);
gScene->addActor(*groundMesh);
// create rigid body.
const PxReal size = PxReal(0.5);
const PxReal mass = PxReal(1.0);
PxShape* box_shape = gPhysics->createShape(PxBoxGeometry(size, size, size), *gMaterial);
for (size_t k = 0; k < 3; k++) {
for (size_t j = 0; j < 3; j++) {
for (size_t i = 0; i < 10; i++) {
if (k == 1 & j == 1) {
continue;
}
PxTransform localTm = PxTransform(PxVec3(3.0f * j, size * (2 * i + 1), 3.0f * k) - PxVec3(1, 0, 1));
PxRigidDynamic* body = gPhysics->createRigidDynamic(localTm);
PxRigidBodyExt::updateMassAndInertia(*body, mass);
body->attachShape(*box_shape);
gScene->addActor(*body);
}
}
}
box_shape->release();
// create shpere.
const PxReal radius = PxReal(1.0);
PxShape* sphere_shape = gPhysics->createShape(PxSphereGeometry(radius), *gMaterial);
for (size_t i = 0; i < 30; i++) {
PxTransform localTm = PxTransform(PxVec3(0.0f, radius * (2 * i + 1) + 8, 0.0f) * radius);
PxRigidDynamic* body = gPhysics->createRigidDynamic(localTm);
PxRigidBodyExt::updateMassAndInertia(*body, mass);
body->attachShape(*sphere_shape);
gScene->addActor(*body);
}
sphere_shape->release();
// create cloth shape.
const PxReal totalClothMass = 10.0f;
PxU32 numX = 250;
PxU32 numZ = 250;
PxReal spacing = 0.06f;
PxVec3 position = PxVec3(-0.5f * numX * spacing, 8.0f, -0.5f * numZ * spacing);
initCloth(numX, numZ, position, spacing, totalClothMass);
}
void allocParticleBuffers() {
PxCudaContextManager* cudaContextManager = gScene->getCudaContextManager();
PxU32 maxParticles = gClothBuffer->getMaxParticles();
sPosBuffer.initialize(cudaContextManager);
sPosBuffer.allocate(maxParticles * sizeof(PxVec4));
}
void renderLoop() {
sCamera = new Snippets::Camera(PxVec3(10.0f, 10.0f, 10.0f), PxVec3(-0.6f, -0.2f, -0.7f));
Snippets::setupDefault("SimpleDemo", sCamera, keyCallback, renderCallback, exitCallback);
initPhysics(); // init all physics variables and environment.
allocParticleBuffers(); // alloc memory for cloth render.
glutMainLoop(); // enetr the render loop.
}
int snippetMain(int, const char* const*) {
renderLoop(); // call the renderloop
cleanupPhysics();
return 0;
}
Thanks very much! |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
Hi there! I'm converting this to a discussion item. The error message indicates that you need to set buildGPUData in the PxCookingParams used in Cloth processes collision on the GPU, so the colliders must compute GPU data in the cooking step. |
Beta Was this translation helpful? Give feedback.
Hi there! I'm converting this to a discussion item.
The error message indicates that you need to set buildGPUData in the PxCookingParams used in
initMesh
.Cloth processes collision on the GPU, so the colliders must compute GPU data in the cooking step.