Skip to content

Instantly share code, notes, and snippets.

@alanjfs
Last active February 4, 2019 09:21
Show Gist options
  • Save alanjfs/f5d2313962dfc87f231a03530f55c988 to your computer and use it in GitHub Desktop.
Save alanjfs/f5d2313962dfc87f231a03530f55c988 to your computer and use it in GitHub Desktop.
Snippet Load and Save Collection
<PhysXCollection version="4.0.0">
<UpVector>0 0 0</UpVector>
<Scale>
<Length>0</Length>
<Speed>0</Speed>
</Scale>
<PxMaterial>
<Id>1</Id>
<Name>MyName</Name>
<DynamicFriction>0.5</DynamicFriction>
<StaticFriction>0.5</StaticFriction>
<Restitution>0.6</Restitution>
<FrictionCombineMode>eAVERAGE</FrictionCombineMode>
<RestitutionCombineMode>eAVERAGE</RestitutionCombineMode>
</PxMaterial>
<PxShape>
<Id>2</Id>
<Geometry>
<PxPlaneGeometry/>
</Geometry>
<LocalPose>0 0 0 1 0 0 0</LocalPose>
<SimulationFilterData>0 0 0 0</SimulationFilterData>
<QueryFilterData>0 0 0 0</QueryFilterData>
<Materials>
<PxMaterialRef>1</PxMaterialRef>
</Materials>
<ContactOffset>0.02</ContactOffset>
<RestOffset>0</RestOffset>
<TorsionalPatchRadius>0</TorsionalPatchRadius>
<MinTorsionalPatchRadius>0</MinTorsionalPatchRadius>
<Flags>eSIMULATION_SHAPE|eSCENE_QUERY_SHAPE|eVISUALIZATION</Flags>
<Name/>
</PxShape>
<PxShape>
<Id>3</Id>
<Geometry>
<PxBoxGeometry>
<HalfExtents>2 2 2</HalfExtents>
</PxBoxGeometry>
</Geometry>
<LocalPose>0 0 0 1 0 0 0</LocalPose>
<SimulationFilterData>0 0 0 0</SimulationFilterData>
<QueryFilterData>0 0 0 0</QueryFilterData>
<Materials>
<PxMaterialRef>1</PxMaterialRef>
</Materials>
<ContactOffset>0.02</ContactOffset>
<RestOffset>0</RestOffset>
<TorsionalPatchRadius>0</TorsionalPatchRadius>
<MinTorsionalPatchRadius>0</MinTorsionalPatchRadius>
<Flags>eSIMULATION_SHAPE|eSCENE_QUERY_SHAPE|eVISUALIZATION</Flags>
<Name/>
</PxShape>
</PhysXCollection>
<PhysXCollection version="4.0.0" >
<UpVector >0 0 0</UpVector>
<Scale >
<Length >0</Length>
<Speed >0</Speed>
</Scale>
<PxMaterial >
<Id >1384972677664</Id>
<DynamicFriction >0.5</DynamicFriction>
<StaticFriction >0.5</StaticFriction>
<Restitution >0.6</Restitution>
<FrictionCombineMode >eAVERAGE</FrictionCombineMode>
<RestitutionCombineMode >eAVERAGE</RestitutionCombineMode>
</PxMaterial>
<PxShape >
<Id >1384972685968</Id>
<Geometry >
<PxPlaneGeometry />
</Geometry>
<LocalPose >0 0 0 1 0 0 0</LocalPose>
<SimulationFilterData >0 0 0 0</SimulationFilterData>
<QueryFilterData >0 0 0 0</QueryFilterData>
<Materials >
<PxMaterialRef >1384972677664</PxMaterialRef>
</Materials>
<ContactOffset >0.02</ContactOffset>
<RestOffset >0</RestOffset>
<TorsionalPatchRadius >0</TorsionalPatchRadius>
<MinTorsionalPatchRadius >0</MinTorsionalPatchRadius>
<Flags >eSIMULATION_SHAPE|eSCENE_QUERY_SHAPE|eVISUALIZATION</Flags>
<Name />
</PxShape>
<PxShape >
<Id >1384972686240</Id>
<Geometry >
<PxBoxGeometry >
<HalfExtents >2 2 2</HalfExtents>
</PxBoxGeometry>
</Geometry>
<LocalPose >0 0 0 1 0 0 0</LocalPose>
<SimulationFilterData >0 0 0 0</SimulationFilterData>
<QueryFilterData >0 0 0 0</QueryFilterData>
<Materials >
<PxMaterialRef >1384972677664</PxMaterialRef>
</Materials>
<ContactOffset >0.02</ContactOffset>
<RestOffset >0</RestOffset>
<TorsionalPatchRadius >0</TorsionalPatchRadius>
<MinTorsionalPatchRadius >0</MinTorsionalPatchRadius>
<Flags >eSIMULATION_SHAPE|eSCENE_QUERY_SHAPE|eVISUALIZATION</Flags>
<Name />
</PxShape>
</PhysXCollection>
//
// 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-2019 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 loading xml or binary serialized collections and instantiating the objects in a scene.
//
// It only compiles and runs on authoring platforms (windows, osx and linux).
// The snippet supports connecting to PVD in order to display the scene.
//
// It is a simple command-line tool supporting the following options::
// SnippetLoadCollection [--pvdhost=<ip address> ] [--pvdport=<ip port> ] [--pvdtimeout=<time ms> ] [--generateExampleFiles] <filename>...
//
// --pvdhost=<ip address> Defines ip address of PVD, default is 127.0.0.1
// --pvdport=<ip port> Defines ip port of PVD, default is 5425
// --pvdtimeout=<time ms> Defines time out of PVD, default is 10
// --generateExampleFiles Generates a set of example files
// <filename>... Input files containing serialized collections (either xml or binary)
//
// Multiple collection files can be specified. The snippet is currently restricted to load a list of collections which obey
// the following rule: The first collection needs to be complete. All following collections - if any - may only maintain
// dependencies to objects in the first collection.
//
// The set of example files that can be generated consists of
// collection.xml|collection.bin: Can be used individually.
// collectionA.xml|collectionA.bin: Can also be used individually but only contain materials and shapes without actors.
// collectionB.xml|collectionB.bin: Need to be used together with collectionA files. The actors contained in collectionB
// maintain references to objects in the collectionA.
//
// ****************************************************************************
#include "PxPhysicsAPI.h"
#include "extensions/PxCollectionExt.h"
#include <iostream>
#include <string>
#include "../snippetcommon/SnippetPrint.h"
#include "../snippetcommon/SnippetPVD.h"
#include "../snippetutils/SnippetUtils.h"
#define MAX_INPUT_FILES 16
using namespace physx;
PxDefaultAllocator gAllocator;
PxDefaultErrorCallback gErrorCallback;
PxFoundation* gFoundation = NULL;
PxPhysics* gPhysics = NULL;
PxCooking* gCooking = NULL;
PxSerializationRegistry* gSerializationRegistry = NULL;
PxDefaultCpuDispatcher* gDispatcher = NULL;
PxScene* gScene = NULL;
PxPvd* gPvd = NULL;
PxU8* gMemBlocks[MAX_INPUT_FILES];
PxU32 gNbMemBlocks = 0;
struct CmdLineParameters
{
const char* pvdhost;
PxU32 pvdport;
PxU32 pvdtimeout;
const char* inputFiles[MAX_INPUT_FILES];
PxU32 nbFiles;
bool generateExampleFiles;
CmdLineParameters() :
pvdhost(PVD_HOST)
, pvdport(5425)
, pvdtimeout(10)
, nbFiles(0)
, generateExampleFiles(false)
{}
} gParameters;
static bool match(const char* opt, const char* ref)
{
std::string s1(opt);
std::string s2(ref);
return !s1.compare(0, s2.length(), s2);
}
static void printHelpMsg()
{
printf("SnippetLoadCollection usage:\n"
"SnippetLoadCollection "
"[--pvdhost=<ip address> ] "
"[--pvdport=<ip port> ]"
"[--pvdtimeout=<time ms> ] "
"[--generateExampleFiles]"
"<filename>...\n\n"
"Load binary or xml serialized collections and instatiate the objects in a PhysX scene.\n");
printf("--pvdhost=<ip address> \n");
printf(" Defines ip address of PVD, default is 127.0.0.1 \n");
printf("--pvdport=<ip port> \n");
printf(" Defines ip port of PVD, default is 5425\n");
printf("--pvdtimeout=<time ms> \n");
printf(" Defines timeout of PVD, default is 10\n");
printf("--generateExampleFiles\n");
printf(" Generates a set of example files\n");
printf("<filename>...\n");
printf(" Input files (xml or binary), if a collection contains shared objects, it needs to be provided with the first file. \n\n");
}
static bool parseCommandLine(CmdLineParameters& result, int argc, const char *const*argv)
{
if( argc <= 1 )
{
printHelpMsg();
return false;
}
for(int i = 1; i < argc; ++i)
{
if(argv[i][0] != '-' || argv[i][1] != '-')
{
if (result.nbFiles < MAX_INPUT_FILES)
{
result.inputFiles[result.nbFiles++] = argv[i];
}
else
printf( "[WARNING] more input files are specified than supported (maximum %d). Ignoring the file %s\n", MAX_INPUT_FILES, argv[i] );
}
else if(match(argv[i], "--pvdhost="))
{
const char* hostStr = argv[i] + strlen("--pvdhost=");
if(hostStr)
result.pvdhost = hostStr;
}
else if(match(argv[i], "--pvdport="))
{
const char* portStr = argv[i] + strlen("--pvdport=");
if (portStr)
result.pvdport = PxU32(atoi(portStr));
}
else if(match(argv[i], "--pvdtimeout="))
{
const char* timeoutStr = argv[i] + strlen("--pvdtimeout=");
if (timeoutStr)
result.pvdtimeout = PxU32(atoi(timeoutStr));
}
else if(match(argv[i], "--generateExampleFiles"))
{
result.generateExampleFiles = true;
}
else
{
printf( "[ERROR] Unknown command line parameter \"%s\"\n", argv[i] );
printHelpMsg();
return false;
}
}
if(result.nbFiles == 0 && !result.generateExampleFiles)
{
printf( "[ERROR] parameter missing.\n" );
printHelpMsg();
return false;
}
return true;
}
static PxCollection* deserializeCollection(PxInputData& inputData, bool isBinary, PxCollection* sharedCollection, PxSerializationRegistry& sr)
{
PxCollection* collection = NULL;
if(isBinary)
{
PxU32 length = inputData.getLength();
PxU8* memBlock = static_cast<PxU8*>(malloc(length+PX_SERIAL_FILE_ALIGN-1));
gMemBlocks[gNbMemBlocks++] = memBlock;
void* alignedBlock = reinterpret_cast<void*>((size_t(memBlock)+PX_SERIAL_FILE_ALIGN-1)&~(PX_SERIAL_FILE_ALIGN-1));
inputData.read(alignedBlock, length);
collection = PxSerialization::createCollectionFromBinary(alignedBlock, sr, sharedCollection);
}
else
{
collection = PxSerialization::createCollectionFromXml(inputData, *gCooking, sr, sharedCollection);
}
return collection;
}
void initPhysics()
{
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);
PxSceneDesc sceneDesc(gPhysics->getTolerancesScale());
sceneDesc.gravity = PxVec3(0, -9.81f, 0);
gDispatcher = PxDefaultCpuDispatcherCreate(1);
sceneDesc.cpuDispatcher = gDispatcher;
sceneDesc.filterShader = PxDefaultSimulationFilterShader;
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);
}
gCooking = PxCreateCooking(PX_PHYSICS_VERSION, *gFoundation, PxCookingParams(PxTolerancesScale()));
gSerializationRegistry = PxSerialization::createSerializationRegistry(*gPhysics);
}
void cleanupPhysics()
{
gSerializationRegistry->release();
gScene->release();
gDispatcher->release();
PxCloseExtensions();
gPhysics->release(); // releases of all objects
gCooking->release();
for(PxU32 i=0; i<gNbMemBlocks; i++)
free(gMemBlocks[i]); // now that the objects have been released, it's safe to release the space they occupy
PxPvdTransport* transport = gPvd->getTransport();
gPvd->release();
transport->release();
gFoundation->release();
printf("SnippetLoadCollection done.\n");
}
static void serializeCollection(PxCollection& collection, PxCollection* externalRefs, const char* filename, bool toBinary)
{
PxDefaultFileOutputStream outputStream(filename);
if (!outputStream.isValid())
{
printf( "[ERROR] Could not open file %s!\n", filename);
return;
}
bool bret;
if (toBinary)
{
bret = PxSerialization::serializeCollectionToBinary(outputStream, collection, *gSerializationRegistry, externalRefs);
}
else
{
bret = PxSerialization::serializeCollectionToXml(outputStream, collection, *gSerializationRegistry, NULL, externalRefs);
}
if(bret)
printf( "Generated: \"%s\"\n", filename);
else
printf( "[ERROR] Failure when generating %s!\n", filename);
}
static void generateExampleFiles()
{
PxCollection* collection = PxCreateCollection();
PxCollection* collectionA = PxCreateCollection();
PxCollection* collectionB = PxCreateCollection();
PX_ASSERT( (collection != NULL) && (collectionA != NULL) && (collectionB != NULL) );
PxMaterial *material = gPhysics->createMaterial(0.5f, 0.5f, 0.6f);
PX_ASSERT( material );
PxShape* planeShape = gPhysics->createShape(PxPlaneGeometry(), *material);
PxShape* boxShape = gPhysics->createShape(PxBoxGeometry(2.f, 2.f, 2.f), *material);
PxRigidStatic* rigidStatic = PxCreateStatic(*gPhysics, PxTransform(PxVec3(0.f, 0.f, 0.f), PxQuat(PxHalfPi, PxVec3(0.f, 0.f, 1.f))), *planeShape);
PxRigidDynamic* rigidDynamic = PxCreateDynamic(*gPhysics, PxTransform(PxVec3(0.f, 2.f, 0.f)), *boxShape, 1.f);
collection->add(*material);
collection->add(*planeShape);
collection->add(*boxShape);
collection->add(*rigidStatic);
collection->add(*rigidDynamic);
PxSerialization::complete(*collection, *gSerializationRegistry);
PX_ASSERT(PxSerialization::isSerializable(*collection, *gSerializationRegistry));
collectionA->add(*material);
collectionA->add(*planeShape);
collectionA->add(*boxShape);
PxSerialization::complete(*collectionA, *gSerializationRegistry);
PxSerialization::createSerialObjectIds(*collectionA, PxSerialObjectId(1));
PX_ASSERT(PxSerialization::isSerializable(*collectionA, *gSerializationRegistry));
collectionB->add(*rigidStatic);
collectionB->add(*rigidDynamic);
PxSerialization::complete(*collectionB, *gSerializationRegistry, collectionA);
PX_ASSERT(PxSerialization::isSerializable(*collectionB, *gSerializationRegistry, collectionA));
serializeCollection(*collection, NULL, "collection.xml", false);
serializeCollection(*collectionA, NULL, "collectionA.xml", false);
serializeCollection(*collectionB, collectionA, "collectionB.xml", false);
serializeCollection(*collection, NULL, "collection.bin", true);
serializeCollection(*collectionA, NULL, "collectionA.bin", true);
serializeCollection(*collectionB, collectionA, "collectionB.bin", true);
collection->release();
collectionA->release();
collectionB->release();
}
static void serializeEverything(const char* filename, int i)
{
PxCollection* everythingCollection = PxCollectionExt::createCollection(*gPhysics);
PxCollection* collectionScene = PxCollectionExt::createCollection(*gScene);
everythingCollection->add(*collectionScene);
collectionScene->release();
PxSerialization::complete(*everythingCollection, *gSerializationRegistry);
auto name = filename + std::string("_") + std::to_string(i);
serializeCollection(*everythingCollection, NULL, name.c_str(), false);
everythingCollection->release();
}
void stepPhysics(bool interactive)
{
PX_UNUSED(interactive);
gScene->simulate(1.0f/60.0f);
gScene->fetchResults(true);
}
int snippetMain(int argc, const char *const* argv)
{
if(!parseCommandLine(gParameters, argc, argv))
return 1;
initPhysics();
if(gParameters.generateExampleFiles)
generateExampleFiles();
// collection that may have shared objects
PxCollection* firstCollection = NULL;
PxU32 i = 0;
const char* filename = gParameters.inputFiles[i];
bool isBinary = false;
PxDefaultFileInputData inputStream(filename);
PxCollection* collection = deserializeCollection(inputStream, isBinary, firstCollection, *gSerializationRegistry);
if (!collection)
{
printf( "[ERROR] deserialization failure! filename: %s\n", filename);
return 1;
}
else
{
printf( "Loaded: \"%s\"\n", filename);
}
gScene->addCollection(*collection);
if (i == 0)
{
firstCollection = collection;
}
else
{
collection->release();
}
if (firstCollection)
firstCollection->release();
static const PxU32 frameCount = 5;
for(int ii=0; ii<frameCount; ii++) {
stepPhysics(false);
serializeEverything(filename, ii);
}
printf("Cleaning up..\n");
cleanupPhysics();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment