Saturday 13 July 2013

Getting Started : PhysX

I've using one of the most popular physics game engines, Nvidia PhysX, and it also appears to be one of the most popular, as reported by physxinfo. The versions I'm reasonably familiar with are the v2.8 and v3.2, but I will only discuss the use of v3.2 for now. When I was getting started myself, I found this other blog very helpful for both.


My goal is to show how to create a simple 2-body system - a bouncing box. As much as possible, the steps for other physics engines will remain the same. So moving between engines should look very similar. In the end this is what I would consider to be the essential steps for setting up any physics engine, so there may not be much information about the various settings available.

0) Setting up the environment

If you're using Visual Studio it may be helpful to use Premake as I've described previously. In any case, you'll need to provide the appropriate paths to some include directories as well as the full path to required library files.

Here I have already defined physXSDK to point to the v3.2.1_win folder and will have the following.
--Directories to Include
    physXSDK .. '/Include'
    physXSDK .. '/Include/common' 
    physXSDK .. '/Include/extensions'
    physXSDK .. '/Include/foundation'

--Libraries to Link
    physXSDK .. '/lib/win32/PhysX3_x86'
    physXSDK .. '/lib/win32/PhysX3Common_x86'
    physXSDK .. '/lib/win32/PhysX3Extensions'

Also, in the project configuration settings, be sure to set the correct platform defines. Or else you risk having run-time issues at initialization because of the wrong alignment.

    defines{ "WIN32" }


1) Including the Headers

To keep things simple you can include the two following header files.

    #include <PxPhysicsAPI.h>
    #include <PxExtensionsAPI.h>

You will see that they contain includes to nearly all the classes you'll need. The alternative it to include just the files you need, in which case PxPhysicsAPI could be replaced with four others.

    #include <PxPhysics.h>
    #include <PxScene.h>
    #include <PxRigidDynamic.h>
    #include <PxRigidStatic.h>

We need PxPhysics for initializing the SDK, PxScene for the world in which we will add both Rigid Dynamic and Rigid Static actors into. In exactly this way will we setup our methods, but before we begin we will also need the physx namespace, a change effective in the 3.x versions of PhysX.

2) Adding the namespace

    using namespace physx;

3) Initialization

There should only be one instance of the sdk created so I have chosen to make a static global variable.

    static PxPhysics* sgpPhysicsSDK = NULL;

In order to satisfy the PxPhysics constructor, we will need a few things. First we will need to also create the 'Foundation'. This requires an implementation of both an allocator and an error callback class. Thankfully there is a default implementation for both that we can use for now.

    PxFoundation* pkFoundation = PxCreateFoundation( PX_PHYSICS_VERSION, 
        *(new PxDefaultAllocator()), *(new PxDefaultErrorCallback()));

    sgpPhysicsSDK = PxCreatePhysics(PX_PHYSICS_VERSION, *pFoundation, PxTolerancesScale());

4) Creating the Scene

As with the initialization I will use the default implementations wherever required and only use the provided validity checks.

//Similar to the 2.8 version of PhysX, the PxScene is created

//by first filling the scene descriptor.
    PxSceneDesc kSceneDesc(sgpPhysicsSDK->getTolerancesScale());

//gravity is set to 0 by default.
    kSceneDesc.gravity = PxVec3(0.0f, -9.8f, 0.0f);

//This is for the number of threads it will have access to.
    PxDefaultCpuDispatcher* pkCpuDispatcher =     PxDefaultCpuDispatcherCreate(1);
    if(kCpuDispatcher)
        kSceneDesc.cpuDispatcher = pkCpuDispatcher;
    PxSimulationFilterShader kDefaultFilterShader =     PxDefaultSimulationFilterShader;
    kSceneDesc.filterShader = kDefaultFilterShader;
    if(kSceneDesc.isValid())
        sgScene = sgPhysicsSDK->createScene(kSceneDesc);



Finally, we can add the actor to the scene.

Nearly all shapes can be removed from actors, with a few exceptions. When releasing actors, all remaining shapes will be removed. We can then remove the actors from the scene, and scenes from the SDK. 



5) Creating Actors

Another important change from PhysX 2.8.x is that actor creation is now controlled by the SDK manager, PxPhysics, and not by the scene. This means that actors can be created and exist separate from the world, and can be added or removed without repeatedly destroying and recreating them later. Shapes, however, go with the actor and cannot be so seamlessly removed and re-added like the actors' relationship to the scene.

Things you will need: A material, appropriate geometry, mass/density, and a pose for the shape. You will also need a pose for the actor.
    PxReal kDensity = 1.0f;

    PxMaterial* pMaterial = sgpPhysicsSDK->createMaterial(0.0,0.0,1);

//Material is the static friction, dynamic friction, and restitution respectively.
    PxBoxGeometry kBoxGeometry;
    kBoxGeometry.halfExtents = PxVec3(0.5f,0.5f,0.5f);
    PxTransform kLocalPose = PxTransform::createIdentity();

    PxVec3 kPosition(0,0,5.0f);

    PxQuat kOrientation = PxQuat::createIdentity();
    PxTransform kGlobalPose(kPosition, kOrientation);

There are two ways to go about creating Actors and Shapes, it all depends on how much information you have.

A - There are static calls you can make, which are especially good if you have all the information and only intend to add one shape to the actor.

    PxRigidDynamic* pDynamicActor = PxCreateDynamic(sgpPhysicsSDK, kGlobalPose, kBoxGeometry,
        *pMaterial, kDensity, kLocalPose);

B - The alternative is to create the unfilled actor from the SDK, and add all this same information in a series of steps.

    PxRigidDynamic* pDynamicActor = sgPhysicsSDK->createRigidDynamic(kGlobalPose);
    pDynamicActor->createShape(kBoxGeometry, *pMaterial, kLocalPose);
    PxRigidBodyExt::updateMassAndInertia(pDynamicActor, kDensity);

In either case, if you continue to add shapes to the actor, then you should call updateMassAndInertia with a list of densities for each shape flagged for simulation, PxShapeFlag::eSIMULATION_SHAPE

    sgScene->addActor(*pDynamicActor);

6) Simulation

The simulation step is straight forward. We can pick a reasonable time step, or a division of our predicted timestep and call simulate and fetchResults one after another.

    PxReal fTimestep 1.0/60.0f;
    PxU32 uiErrorState = 0;
    bool bBlock = true;

    sgScene->simulate(fTimestep);
    sgScene->fetchResults(bBlock, &uiErrorState);

In some examples Nvidia separates the simulate and fetch into pre and post rendering steps, but it would seem fine to perform rending after calling a simulate/fetch pair. The blocking parameter in fetchResults is typically set to true, otherwise fetchResults may return false because the results are not yet ready. It is acceptable to call fetchResults multiple times in this case. Which you could write as:

    sgScene->simulate(fTimestep);
    while(!sgScene->fetchResults(false, &uiErrorState){}

This gives control to the user to do something else useful in the meantime. Similarly the timestep can be subdivided and the pairing called multiple times, which may be necessary for stability or synchronization.

7) Shutdown/Cleanup

    PxU32 uiActorCount = sgScene->getNbActors(     PxActorTypeSelectionFlag::eRIGID_STATIC | PxActorTypeSelectionFlag::eRIGID_DYNAMIC);
    PxActor** pActorBuffer = (PxActor**)malloc(uiActorCount*sizeof(PxActor*));
    for(PxU32 ui =0; ui<uiActorCount; ui++)
    {
        sgScene->removeActor(*pActorBuffer[ui]);
        pActorBuffer[ui]->release();
    }
    sgpPhysicsSDK->release();
//all instances of the sdk need to be released before the next two
    delete sgpDefaultErrorCallback;
    delete sgpDefaultAllocatorCallback;

This should be good enough to get started. I'll try to cover other rigid-body topics like joints at a later time. 
Happy Coding.






Wednesday 10 July 2013

Getting Started : Premake

Visual Studio is a common IDE to work with, but constantly adding library dependencies can create conflicts and has not been very helpful for keeping things organized. Premake is a useful tool for generating solution and project files with the necessary dependencies. This is the method I learned, but may by no means be the best method depending on the size of complexity of project.

I have a single line batch file that creates the solution by calling Premake4.exe with a lua-script file argument. 

//CreateSolution.bat

..\..\premake\Premake4 --file=ScriptFile.lua --platform=x32 vs2008

and the associated script file contains the information for the solution as well as the project.

//ScriptFile.lua

solution "MySolution"
   configurations { "Debug" }

project "MyProject"
   kind "ConsoleApp"
   language "C++"

   local sampleSDK = 'C:/Users/Alex/Documents/sampleSDK'

   files {"**.h", "**.cpp" }
   includedirs { "include" }

   links { sampleSDK .. '/lib/sample' }

    configuration "Debug"
      flags { "Symbols" }
      defines { "WIN32", "_DEBUG" }

This is the basic structure if you are only creating one project for this solution and all the files are located in immediate subfolders. Alternatively you could create a Solution lua script file, and corresponding Project scripts that would look something like this:

//SolutionFile.lua

solution "MySolution"
   configurations { "Debug" }

   dofile('./Project0/Project0-premake.lua')
   dofile('./Project1/Project1-premake.lua')


//Project0-premake.lua

project "MyProject0"
   kind "ConsoleApp"
   language "C++"
.
.
.

In this way you can continue to use **.h and **.cpp because  all the files are in their corresponding folders. Otherwise you would have to specify which files to include in each project, which is not very practical for anything larger than a couple files. 

This is just how I'm currently doing things with my current setup, other minor tweaking for your particular setup should be evident.