Skip to content

Instantly share code, notes, and snippets.

@kermado
Created December 26, 2018 19:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kermado/e20e0743de919de9a4315012984fc5d2 to your computer and use it in GitHub Desktop.
Save kermado/e20e0743de919de9a4315012984fc5d2 to your computer and use it in GitHub Desktop.
//
// 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-2018 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
// ****************************************************************************
// This snippet illustrates simple use of physx
//
// It creates a number of box stacks on a plane, and if rendering, allows the
// user to create new stacks and fire a ball from the camera position
// ****************************************************************************
#include <ctype.h>
#include "PxPhysicsAPI.h"
#include "../snippetcommon/SnippetPrint.h"
#include "../snippetcommon/SnippetPVD.h"
#include "../snippetutils/SnippetUtils.h"
using namespace physx;
PxDefaultAllocator gAllocator;
PxDefaultErrorCallback gErrorCallback;
PxFoundation* gFoundation = NULL;
PxPhysics* gPhysics = NULL;
PxDefaultCpuDispatcher* gDispatcher = NULL;
PxScene* gScene = NULL;
PxMaterial* gMaterial = NULL;
PxPvd* gPvd = NULL;
PxReal stackZ = 10.0f;
PxRigidDynamic* createDynamic(const PxTransform& t, const PxGeometry& geometry, const PxVec3& velocity=PxVec3(0))
{
PxRigidDynamic* dynamic = PxCreateDynamic(*gPhysics, t, geometry, *gMaterial, 10.0f);
dynamic->setAngularDamping(0.5f);
dynamic->setLinearVelocity(velocity);
gScene->addActor(*dynamic);
return dynamic;
}
void createStack(const PxTransform& t, PxU32 size, PxReal halfExtent)
{
PxShape* shape = gPhysics->createShape(PxBoxGeometry(halfExtent, halfExtent, halfExtent), *gMaterial);
shape->setContactOffset(physx::PxReal(.001));
shape->setRestOffset(physx::PxReal(.0005)); // Change to zero and it is stable with PGS and TGS.
for(PxU32 i=0; i<size;i++)
{
PxTransform localTm(PxVec3(PxReal(0), PxReal(i * 2 + 1), 0) * halfExtent);
PxRigidDynamic* body = gPhysics->createRigidDynamic(t.transform(localTm));
body->attachShape(*shape);
PxRigidBodyExt::setMassAndUpdateInertia(*body, ((i % 2) == 0) ? 0.1f : 10.0f); // 100 : 1 mass ratios
body->setSolverIterationCounts(40, 10); // Stable with TGS if set to 40, 40.
gScene->addActor(*body);
}
shape->release();
}
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(), false, gPvd);
PxSceneDesc sceneDesc(gPhysics->getTolerancesScale());
sceneDesc.solverType = PxSolverType::eTGS; // Stable using PGS.
sceneDesc.gravity = PxVec3(0.0f, -9.81, 0.0f);
gDispatcher = PxDefaultCpuDispatcherCreate(20);
sceneDesc.cpuDispatcher = gDispatcher;
sceneDesc.filterShader = PxDefaultSimulationFilterShader;
sceneDesc.broadPhaseType = physx::PxBroadPhaseType::eABP;
sceneDesc.frictionOffsetThreshold = physx::PxReal(.001);
gScene = gPhysics->createScene(sceneDesc);
PxPvdSceneClient* pvdClient = gScene->getScenePvdClient();
if(pvdClient)
{
pvdClient->setScenePvdFlag(PxPvdSceneFlag::eTRANSMIT_CONSTRAINTS, true);
pvdClient->setScenePvdFlag(PxPvdSceneFlag::eTRANSMIT_CONTACTS, true);
pvdClient->setScenePvdFlag(PxPvdSceneFlag::eTRANSMIT_SCENEQUERIES, true);
}
gMaterial = gPhysics->createMaterial(0.3f, 0.3f, 0.0f);
gMaterial->setFrictionCombineMode(physx::PxCombineMode::eMULTIPLY);
gMaterial->setRestitutionCombineMode(physx::PxCombineMode::eMULTIPLY);
PxRigidStatic* groundPlane = PxCreatePlane(*gPhysics, PxPlane(0,1,0,0), *gMaterial);
gScene->addActor(*groundPlane);
createStack(PxTransform(PxVec3(0,0,stackZ-=10.0f)), 5, 0.2f);
if(!interactive)
createDynamic(PxTransform(PxVec3(0,40,100)), PxSphereGeometry(10), PxVec3(0,-50,-100));
}
void stepPhysics(bool interactive)
{
PX_UNUSED(interactive);
gScene->simulate(1.0f/100.0f);
gScene->fetchResults(true);
}
void cleanupPhysics(bool interactive)
{
PX_UNUSED(interactive);
gScene->release();
gDispatcher->release();
gPhysics->release();
PxPvdTransport* transport = gPvd->getTransport();
gPvd->release();
transport->release();
gFoundation->release();
printf("SnippetHelloWorld done.\n");
}
void keyPress(unsigned char key, const PxTransform& camera)
{
switch(toupper(key))
{
case 'B': createStack(PxTransform(PxVec3(0,0,stackZ-=1.0f)), 5, 0.2); break;
case ' ': createDynamic(camera, PxSphereGeometry(3.0f), camera.rotate(PxVec3(0,0,-1))*200); break;
}
}
int snippetMain(int, const char*const*)
{
#ifdef RENDER_SNIPPET
extern void renderLoop();
renderLoop();
#else
static const PxU32 frameCount = 100;
initPhysics(false);
for(PxU32 i=0; i<frameCount; i++)
stepPhysics(false);
cleanupPhysics(false);
#endif
return 0;
}
@kstorey-nvidia
Copy link

Thanks for the repro. This seems to just be a problem with the settings in your test. You have set contact offset to 0.001 and friction offset to 0.001. This means that contacts are only generated when the separations are less than 0.2mm (it sums the contact offsets of both shapes) and friction constraints are only enabled if the separation is less than 0.1mm. These values are very small and leave very little tolerance for error in the solver.

When you introduce a rest offset of 0.0005 to each shape (which is summed in the solver so produces a total rest offset of 0.1mm), this means that the boxes are held with the shapes separated by a distance of 0.1mm. This eats into your 0.2mm of contact offset, meaning you effectively now have a tolerance for contacts being generated of 0.1mm and a friction offset tolerance of exactly 0.

Given sufficient iterations, the PGS solver slightly undershoots and doesn't manage to remove all the error. However, PGS takes a lot of iterations to produce acceptable results. TGS converge in fewer iterations but it is far more aggressive correcting error and is prone to overshooting penetration depths slightly, so requires a slightly larger tolerance range to work within than PGS.

If you set the contact offset and friction offsets back to their default (0.02), this test case works fine with TGS and rest offset of 0.0005. You can also reduce the number of solver iterations significantly (TGS was able to handle this stack with 8 position iterations, 1 velocity iteration but the results were a bit jittery - a few more iterations produced smoother results).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment