Skip to content

Unstable contact on GPU using TGS solver type #467

Description

@ssmeadkv

Library and Version

PhysX 5.6.1

Operating System

Windows 11

Steps to Trigger Behavior

  1. Create 2 box colliders.
  2. Have box collider 1 rest on box collider 2. Rotate box collider 2.
  3. Use PxSolverType::eTGS on a GPU solve
  4. Observe box collider 1 have unstable behavior.

Code Snippet to Reproduce Behavior

Using the useGPU and useTGS parameters in the snippet below, the issue can be reproduced.
useGPU = true + useTGS = true produces unstable contact behavior.
useGPU = true + useTGS = false produces stable contact behavior.
useGPU = false + useTGS = false produces stable contact behavior.
useGPU = false + useTGS = true produces stable contact behavior.

Example stable:

stable.mp4

Example unstable:

unstable.mp4
#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;
}

Expected Behavior

Stable contact

Actual Behavior

Unstable contact

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions