#include "PxPhysicsAPI.h"
#include "../snippetutils/SnippetUtils.h"
#include "../snippetcommon/SnippetPrint.h"
#include "../snippetcommon/SnippetPVD.h"
using namespace physx;
static PxDefaultAllocator gAllocator;
static PxDefaultErrorCallback gErrorCallback;
static PxFoundation* gFoundation = NULL;
static PxPhysics* gPhysics = NULL;
static PxDefaultCpuDispatcher* gDispatcher = NULL;
static PxScene* gScene = NULL;
static PxMaterial* gMaterial = NULL;
static PxPvd* gPvd = NULL;
PxArray<PxVec3> gContactPositions;
PxArray<PxVec3> gContactImpulses;
PxRigidDynamic* floor1;
bool useGPU = true;
bool useTGS = true;
static PxFilterFlags contactReportFilterShader( PxFilterObjectAttributes attributes0, PxFilterData filterData0,
PxFilterObjectAttributes attributes1, PxFilterData filterData1,
PxPairFlags& pairFlags, const void* constantBlock, PxU32 constantBlockSize)
{
PX_UNUSED(attributes0);
PX_UNUSED(attributes1);
PX_UNUSED(filterData0);
PX_UNUSED(filterData1);
PX_UNUSED(constantBlockSize);
PX_UNUSED(constantBlock);
// all initial and persisting reports for everything, with per-point data
pairFlags = PxPairFlag::eSOLVE_CONTACT | PxPairFlag::eDETECT_DISCRETE_CONTACT
| PxPairFlag::eNOTIFY_TOUCH_FOUND
| PxPairFlag::eNOTIFY_TOUCH_PERSISTS
| PxPairFlag::eNOTIFY_CONTACT_POINTS;
return PxFilterFlag::eDEFAULT;
}
void initPhysics(bool /*interactive*/)
{
gFoundation = PxCreateFoundation(PX_PHYSICS_VERSION, gAllocator, gErrorCallback);
gPvd = PxCreatePvd(*gFoundation);
PxPvdTransport* transport = PxDefaultPvdSocketTransportCreate(PVD_HOST, 5425, 10);
gPvd->connect(*transport,PxPvdInstrumentationFlag::eALL);
gPhysics = PxCreatePhysics(PX_PHYSICS_VERSION, *gFoundation, PxTolerancesScale(), true, gPvd);
PxInitExtensions(*gPhysics,gPvd);
PxU32 numCores = SnippetUtils::getNbPhysicalCores();
gDispatcher = PxDefaultCpuDispatcherCreate(numCores == 0 ? 0 : numCores - 1);
PxSceneDesc sceneDesc(PxTolerancesScale(1.0f, 10.0f));
sceneDesc.cpuDispatcher = gDispatcher;
sceneDesc.gravity = PxVec3(0, -9.81f, 0);
sceneDesc.filterShader = contactReportFilterShader;
sceneDesc.bounceThresholdVelocity = 1e-6;
if (useGPU)
{
const PxCudaContextManagerDesc cudaContextManagerDesc;
auto mCudaContextManager =
PxCreateCudaContextManager(*gFoundation, cudaContextManagerDesc);
sceneDesc.cudaContextManager = mCudaContextManager;
sceneDesc.flags |= PxSceneFlag::eENABLE_GPU_DYNAMICS;
sceneDesc.flags |= PxSceneFlag::eENABLE_PCM;
sceneDesc.flags |= PxSceneFlag::eENABLE_ENHANCED_DETERMINISM;
sceneDesc.broadPhaseType = PxBroadPhaseType::eGPU;
sceneDesc.gpuMaxNumPartitions = 8;
}
if (useTGS)
{
sceneDesc.solverType = PxSolverType::eTGS;
}
else
{
sceneDesc.solverType = PxSolverType::ePGS;
}
gScene = gPhysics->createScene(sceneDesc);
PxPvdSceneClient* pvdClient = gScene->getScenePvdClient();
if(pvdClient)
{
pvdClient->setScenePvdFlag(PxPvdSceneFlag::eTRANSMIT_CONTACTS, true);
}
gMaterial = gPhysics->createMaterial(1.0f, 1.0f, 0.2f);
gMaterial->setRestitutionCombineMode(PxCombineMode::eMAX);
gMaterial->setFrictionCombineMode(PxCombineMode::eMAX);
// box collider 1
PxShape* shape = gPhysics->createShape(PxBoxGeometry(0.05967678129673004 / 2, 0.17804302275180817 / 2, 0.03580000251531601 / 2), *gMaterial);
PxTransform localTm(PxVec3(-0.4f, 0.17804302275180817 / 2 + 0.0002 + 0.005, 0));
PxRigidDynamic* body = gPhysics->createRigidDynamic(localTm);
body->attachShape(*shape);
body->setSolverIterationCounts(16, 3);
PxRigidBodyExt::setMassAndUpdateInertia(*body, 0.0189f);
gScene->addActor(*body);
shape->release();
// box collider 2
PxShape* floorShape = gPhysics->createShape(PxBoxGeometry(0.5, 0.005, 0.1), *gMaterial);
floor1 = gPhysics->createRigidDynamic(PxTransform(PxVec3(0.0f, 0.0f, 0.0f)));
floor1->attachShape(*floorShape);
floor1->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true);
floor1->setSolverIterationCounts(16, 3);
PxRigidBodyExt::setMassAndUpdateInertia(*floor1, 15.0f);
gScene->addActor(*floor1);
floorShape->release();
}
PxReal simTime = 0;
void stepPhysics(bool /*interactive*/)
{
const PxReal dt = 1e-3f;
gContactPositions.clear();
gContactImpulses.clear();
const PxReal speed = 2.0f * PxPi / 180.0;
PxTransform pose = floor1->getGlobalPose();
floor1->setKinematicTarget(PxTransform(pose.p, PxQuat(PxSin(simTime * speed), PxVec3(0, 0, -1))));
gScene->simulate(dt);
gScene->fetchResults(true);
simTime += dt;
}
void cleanupPhysics(bool /*interactive*/)
{
gContactPositions.reset();
gContactImpulses.reset();
PX_RELEASE(gScene);
PX_RELEASE(gDispatcher);
PxCloseExtensions();
PX_RELEASE(gPhysics);
if(gPvd)
{
PxPvdTransport* transport = gPvd->getTransport();
PX_RELEASE(gPvd);
PX_RELEASE(transport);
}
PX_RELEASE(gFoundation);
printf("SnippetContactReport done.\n");
}
int snippetMain(int, const char*const*)
{
initPhysics(false);
for (PxU32 i = 0; i < 10000; i++)
stepPhysics(false);
cleanupPhysics(false);
return 0;
}
Library and Version
PhysX 5.6.1
Operating System
Windows 11
Steps to Trigger Behavior
PxSolverType::eTGSon a GPU solveCode Snippet to Reproduce Behavior
Using the
useGPUanduseTGSparameters in the snippet below, the issue can be reproduced.useGPU = true+useTGS = trueproduces unstable contact behavior.useGPU = true+useTGS = falseproduces stable contact behavior.useGPU = false+useTGS = falseproduces stable contact behavior.useGPU = false+useTGS = trueproduces stable contact behavior.Example stable:
stable.mp4
Example unstable:
unstable.mp4
Expected Behavior
Stable contact
Actual Behavior
Unstable contact