Wednesday 13 November 2013

PhysX with 64-bit using VS2008

This seems to be an important feature for some to have, so I wanted to see how difficult it would be to compile and run under a 64-bit architecture. At least for NVIDIA's PhysX (both 2.8.x, and 3.2.x) it was really really easy.

Recall we needed a few dll's, which are a direct swap for the ones already copied into the project folder. 

//PhysX 2.8.4
   cudart64_30_9.dll
   PhysXCore64.dll
   PhysXLoader64.dll

//PhysX 3.2.1
   PhysX3_64.dll
   PhysXCommon_x64.dll

Of course if you have a more advanced application you may also need other libraries, but for the most basicc rigid body simulation these are essential and demonstrate the pattern for the other libraries. If you are missing any of these dll's, then it may tell you when you run the debugger (PhysX 3.2.1), or you will likely get a Null return from 
NxCreatePhysicsSDK with error code NXCE_PHYSX_NOT_FOUND.

If you use premake like me to generate Visual Studio solutions then you need to indicate these changes as well in the .lua files and specify the target platform in the .bat file. Snippets of mine looks like this :

//HelloWorld-Premake.lua

   local physXSDK = 'C:/Program Files (x86)/NVIDIA Corporation/NVIDIA PhysX SDK/v3.2.1_win'

   includedirs { physXSDK .. '/Include/foundation' }
   includedirs { physXSDK .. '/Include' }
   includedirs { physXSDK .. '/Include/common' }
   includedirs { physXSDK .. '/Include/extensions' }

   links { physXSDK .. '/lib/win64/PhysX3_x64' }
   links { physXSDK .. '/lib/win64/PhysX3Extensions' }
   links { physXSDK .. '/lib/win64/PhysX3Common_x64' }
   links { physXSDK .. '/lib/win64/PhysXVisualDebugger' }

//CreateSolutions.bat

   ..\..\premake\Premake4 --file=HelloWorld-Premake.lua --platform=x64 vs2008

If you didn't do a complete install the first time, visual studio 2008 does not come with the x64 compiler by default and you will have to re-install, adding the x64 as a custom feature. This may prompt for the location of other files, I found this solution helpful.

*Remember that you will also need to get the correct rendering libraries, or else the program will build, but fail to execute properly. See Error : "The application was unable to start correctly (0xc000007b)".*

If there is more work to be done for custom allocators, I will update this posting to include those changes as well. Until then, Happy Coding!


Wednesday 25 September 2013

Getting Started : Newton


Newton Game Dynamics. An open source engine, claiming to be easy to use, but perhaps due to my inexperience this game me much more trouble than anticipated. Nevertheless, after manipulating and removing unnecessary elements from some of the simpler demos I was able to produce a working example.

0) Setting up the Environment

If you're using Premake then this is a relatively simple swap from an earlier posting. Otherwise you will need to be sure to include the following.

--Include Directories
   newtonSDK .. 'source/newton'
   newtonSDK .. 'source/core'
   newtonSDK .. 'source/physics'
   newtonSDK .. 'source/cuda'
--Libraries to Link
   newtonSDK .. 'windows/project_vs2008/Win32/newton/debug/newton_d'
   newtonSDK .. 'windows/project_vs2008/Win32/physics/debug/physics'
   newtonSDK .. 'windows/project_vs2008/Win32/core/debug/core'

This assumes that newtonSDK points to the appropriate ./newton-dynamics-2.33/coreLibrary_200/ folder.

1) Including the Headers

Even if you are using some of the "dg" prefixed classes like dgMatrix or dgVector, we can still get away with this one include.

   #include "NewtonClass.h"

2) Initialization

There is not much needed here but to set up the memory system

   NewtonSetMemorySystem (AllocMemory, FreeMemory);

However, these two functions will need to be defined by the user and can be as simple as this.

   void* AllocMemory (int size)
   {
      return malloc (size);
   }

   void FreeMemory (void *ptr, int size)
   {
      free (ptr);
   }


3) Creating the World

   static NewtonWorld* sgpWorld = NewtonCreate();
   NewtonSetPlatformArchitecture (sgpWorld, 0);


   float pfMinSize[3] = {-50.0f,-50.0f,-50.0f};
   float pfMaxSize[3] = {50.0f, 50.0f, 50.0f};

   NewtonSetWorldSize (sgpWorld, &pfMinSize[0], &pfMaxSize[0]); 
   NewtonSetSolverModel (sgpWorld, 1);

4) Creating Newton Bodies and Collision Shapes

   NewtonBody* pCubeBody;
   NewtonCollision* pCubeShape;
   dgMatrix offset (dgQuaternion(),dgVector(0.0f, 0.0f, 5.0f, 1.0f));

The size of the box is given in its full dimensions, not the half height, or half extents like in other engines.

   pCubeShape = NewtonCreateBox (sgpWorld, 1.0,1.0,1.0, 0, NULL);

The shape offset matrix parameter may be left as Null for the NewtonCollision, defaulting to the local origin of the body, but the NewtonBody will result in an error without it.


   dgMatrix offset (dgQuaternion(),dgVector(0.0f, 5.0f ,0.0f, 1.0f));
   pCubeBody = NewtonCreateBody (sgpWorldpCubeShape, &offset[0][0]);

If we stop now, this NewtonBody will be a static member of the world. If we provide it with a mass then it will begin at rest, and respond only to collision from other bodies. This is not the same as sleeping, since it will become stationary again once a contact force is removed.

   dFloat fMass = 1.0f;
   dFloat fInertia = 1.0/6/0;
   NewtonBodySetMassMatrix(pCubeBody, fMass, fInertia, fInertia, fInertia);

The diagonal elements of the inertia matrix for a solid cube happen to be 1/6. Having this mass matrix is essential, but it is not sufficient even if we use NewtonBodySetForce. We will also need a callback for any forces applied. This is used mostly for applying gravity, but we must associate each NewtonBody with the desired callback.

    NewtonBodySetForceAndTorqueCallback(pCubeBody, ForceCallback);

Implementing this callback is not difficult, but the user must provide one.

   void  ForceCallback(const NewtonBody* pBody, dFloat fTimestep, int iThreadIndex)
   {
      dFloat Ixx;
      dFloat Iyy;
      dFloat Izz;
      dFloat fMass;

      NewtonBodyGetMassMatrix (pBody, &fMass, &Ixx, &Iyy, &Izz);
      dgVector force (0.0f, 0.0f, fMass* -9.8, 0.0f);
      NewtonBodySetForce (pBody, &force.m_x);
   }


Since NewtonBodySetForce is applied within the force callback there is no need to try setting the force again. This implementation of gravity will activate at the start of the simulation.

5) Simulation

   NewtonUpdate (sgpWorld, fTimestep); //fTimestep = 1/60

6) Shutdown

Once we are done applying a collision shape to any bodies we can release it without the body losing it's shape.

   NewtonReleaseCollision(sgpWorld, pCubeShape);

At the end of our simulation we can remove everything else we've created.

   NewtonDestroyAllBodies (sgpWorld);
   NewtonDestroy (sgpWorld);

In the end I don't despise Newton Dynamics. It makes sense once its working, but leaves much to be desired in terms of documentation, and co-operation with Visual Studio Intellisense (If you happen to use an Integrated Development Environment like me). This is partly because, like ODE, objects are manipulated through calling C-style functions instead of through member functions. Furthermore, the wiki system is mysteriously uninformative at some points, and unreadable inline code. In future evaluations, perhaps Newton will redeem itself with exceptional performance, or portability.

Happy Coding!

Saturday 31 August 2013

Getting Started : Bullet Physics



Working with the Bullet engine has easily been the most straightforward. It was very easy to setup, and follow documentation to create an identical sample as the previous engines. In my case it was simply a dynamic box that falls and bounces off a static floor with a similar motion. It has been my experience so far, that default values can be very different (coefficient of friction, restitution, etc), and the calculation resolving the collision of two rigid bodies can lead to very different motion.

0) Setting up the Environment

As in the past I use Premake to generate my Visual Studio solution files and build from within the IDE. I am using 2.81-rev2613 version of the Bullet engine, and the lua file I feed to Premake will be differentiated from my other examples by these few lines.

   includedirs { bulletSDK }
   includedirs { bulletSDK .. '/src' }

   links { bulletSDK .. "/lib/BulletDynamics_vs2008_debug",
           bulletSDK .. "/lib/BulletCollision_vs2008_debug",
           bulletSDK .. "/lib/LinearMath_vs2008_debug"}

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

1) Including the Headers

Instead of trying to include any specific headers I thought I might need, I used the common header file.

    #include <btBulletDynamicsCommon.h>

which will get you everything from the rigid bodies to the constraints and solvers.

2) Initialization

Using default settings, we will need at least these four things.

    btDefaultCollisionConfiguration* gCollisionConfig  = new btDefaultCollisionConfiguration();
    btCollisionDispatcher* gDispatcher =  new btCollisionDispatcher(gCollisionConfig);
    btBroadphaseInterface* gOverlappingPairCache =  new btDbvtBroadphase();
    btSequentialImpulseConstraintSolver* gSolver =  new btSequentialImpulseConstraintSolver();

3) Creating the World

Again very straightforward if you try to fulfill the parameters of the constructor.

    static btDiscreteDynamicsWorld* gWorld = new btDiscreteDynamicsWorld(
        gDispatcher, gOverlappingPairCache, gSolver, gCollisionConfig);

    gWorld->setGravity(btVector3(0, 0, -9.8));

Many other physics engines have methods of partitioning the world, or collecting bodies into collision groups for better performance. If Bullet has something similar I will certainly highlight this fact in the future. 

4) Creating Bodies and Shapes

It will be important this time to create the necessary shapes first before creating the body. It would seem that the body cannot exist without any shapes.

    btVector3 kHalfExtent(0.5f, 0.5f, 0.5f);
    btConvexShape* pBoxShape = new btBoxShape(kHalfExtent);

A default, inertia tensor needs to be initialized first. This is, of course, only the diagonal elements of a tensor representing rotation about a regular axis. The actual tensor values will be recalculated based on the shape and mass provided.

    btScalar kMass = btScalar(1.0f);
    btVector3 kLocalInertia(0,0,0);
    pBoxShape->calculateLocalInertia(kMass , kLocalInertia);

    btTransform kBoxTform;
    kBoxTform.setIdentity();
    kBoxTform.setOrigin(btVector3(0,0,5));
    btDefaultMotionState* pMotionState = new btDefaultMotionState(kBoxTform);

All of the elements before are required to finally set the construction information for rigid body. It is important to note that a btRigidBody only takes one btCollisionShape pointer as an arguement. In order to have multiple shapes represent the collision geometry, one can use btCompoundShape. Also, there is only one transform for the position and orientation of the body, and not for the shape. Since the btCollisionShape is only used for geometry purposes, the same object can be re-used in different bodies (as long as the geometry is not changed).

    btRigidBody::btRigidBodyConstructionInfo kRBInfo(
        kMass, pMotionState, pBoxShape, kLocalInertia);

    btRigidBody* pBoxBody = new btRigidBody(kRBInfo);
    pBoxBody->setActivationState(ACTIVE_TAG);
    pBoxBody->setRestitution(0.5);

    gWorld->addRigidBody(pBoxBody);

5) Simulation Step

    int iMaxSubsteps = 10;
    m_world->stepSimulation(myTimestep, iMaxSubsteps);

6) Shutdown/Cleanup

I believe there is a critical error in the demos provided in bullet which I hope is corrected in the following modified code. The problem is that the condition of the 'for' loop is dependent on the number of collision objects in the dynamics world, but as we iterate through the loop we remove each object from that world, reducing the wold size. If we are iterating upward, and the condition limit is moving downward we never properly clear about half of the collision objects.  Also, we are responsible for deleting everything we have created earlier, the destructor of any collision object will not properly clear any member pointers we provided earlier. In particular we created a btDefaultMotionState, and used one of the created btCollisionShapes in the btRigidBodyConstructionInfo. So both the motion state, and the collision shapes must be manually deleted.

If you have not created an array already to store the collision shapes. Recall that collision shapes may be reused between rigid bodies, and so we must create a non-degenerate list.

    btAlignedObjectArray<btCollisionShape*> collideShapes;

Since the number of collision objects in the world is going to decrease, we record the original number first.

    int numCollide = gWorld->getNumCollisionObjects();
    for(int i = numCollide-1; i >= 0; i--)
    {
        btCollisionObject *pObj = objArray.at(i);
        gWorld->removeCollisionObject(obj);
        btRigidBody* pBody = btRigidBody::upcast(pObj);
        if (pBody && pBody->getMotionState())
        {
            delete pBody->getMotionState();
        }
        btCollisionShape* pShape = pObj->getCollisionShape();
        
        if(pShape && (collideShapes.findLinearSearch(pShape) == collideShapes.size()))
        {
            collideShapes.push_back(pShape);
        }
        delete pObj;
     }

Similarly the size of the array will decrease as we remove shapes from it, but we could also write the loop this way to ensure all shapes are properly deleted.

    for(int i = collideShapes.size()-1; i >= 0; )
    {
        btCollisionShape* pShape = collideShapes.at(i);
        collideShapes.remove(pShape);
        delete pShape;
    }

Finally we can delete the remaining objects in the reverse order that they where constructed.

    delete gWorld;
    delete gSolver;
    delete gOverlappingPairCache;
    delete gDispatcher;
    delete gCollisionConfig;

Bullet has easily been the most straightforward in setting up a working demo. I am unsure of how it performs against other engines at the moment, but I am very excited to work with it again. Hopefully this has been helpful if the documentation and demos were not helpful enough. Happy Coding!

** the user manual is under the main folder, not under the 'docs' folder which contains the quick-start guide.**

Wednesday 21 August 2013

Getting Started : Open Dynamics Engine (ODE)

After spending considerable time trying to get a simple Newton Dynamics example working, I switched over to the Open Dynamics Engine with much more success. To start, ODE has a wiki page with a very informative manual even if you simply skim it. After generating the Visual Studio solutions as explained in the INSTALL file.

    >premake4.exe --with-tests --with-demos vs2008

Which is really more than necessary since the only project needed to be built is the 'ode'.  If you fail to build the correct configuration of ode you will get a link error like this:

    fatal error LNK1104: cannot open file 
        '..\..\..\..\ode-0.12\lib\DebugDoubleLib\ode_doubled.lib'

I intend to use the static library with high precision so I will build under the DebugDoubleLib configuration. Just like in other examples, I am currently using premake to generate my Visual Studio solutions, and so you will need a .lua file with these lines modified to match your own directory hierarchy.

0) Setting up the Environment

    includedirs { odeSDK .. '/include' }

    links { odeSDK .. '/lib/DebugDoubleLib/ode_doubled' }

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

1) Including the Headers

As recommended by the manual, this is all I added.

    #include <ode/ode.h>

2) Adding the namespace

No namespace necessary

3) Initialization

    dInitODE2(0);

Apparently dInitODE() is obsolete, and this initialization call can take a bitmask of flags which never seems to be used in any examples. 

4) Creating the World

We'll need two things to begin, a world and at least one space. Spaces are a way of controlling collision, by grouping together bodies that will collide, and separating sets of bodies that will never collide. At the very minimum we will need a world and some gravity.

    static dWorldID gWorldID = dWorldCreate();
    dWorldSetGravity(gWorldID,0.0f, 0.0f, -9.8f);

4i) Creating the Space

    static dSpaceID gSpaceID = dSimpleSpaceCreate(0);

With that we are ready to get started adding some shapes to the space. There are, of course, some nice world settings to improve the quality of the simulation which I will include in any code samples provided.

5) Creating Bodies and Geometry

Similar to any other physics engine, there is a larger 'body' which can contain multiple shapes with their corresponding geometry. There are a few exceptions here: plane shapes are not allowed to have a body.

    dGeomID kFloor = dCreatePlane(gSpaceID, 0,0,1,0);

all the other fundamental shapes are created in a similar way.

    dGeomID kBoxGeom = dCreateBox(gSpaceID, 1, 1, 1);
    dGeomSetPosition(kBoxGeom, 0, 0, 0);

I center the box at the origin because this will become the origin of the body containing the box, and not the origin of the world.

We can now see the connection between everything so far, that the shapes are what is used for collision detection so they are created in the space, but bodies are only containers for the shapes and are created in the world.

    dBodyID kBoxBody = dBodyCreate(worldID);
    dBodySetPosition(kBoxBody, 0, 0, 5);

    dGeomSetBody(kBoxGeom, kBoxBody );

Also the mass is optional of this is to be a kinematic/static body, but adding mass will make it's default setting dynamic. Although the geometry is only a single box, the mass distribution may be of a different shape or even different dimensions.

    dMass kMass
    dReal density = 1.0;
    dMassSetBox(&kMass, density, 1, 1, 1);


    dBodySetMass(kBoxBody , &kMass);

6) Simulation

Everything until now has been relatively simple, despite the 'C' style interface where everything is a function call and pointers are masked as 'IDs'. However, the simulation step can be a little tricky but looks like this:

    static dJointGroupID gJointGroup = dJointGroupCreate(0); //done at initilization

    dSpaceCollide(gSpaceID, 0, &NearCallback);
    dWorldQuickStep(gWorldID, myTimestep); 
    dJointGroupEmpty(gJointGroup);

First we check for any collisions, or even near collisions in any spaces we have. The results of which will be collected and organized using a user-implemented 'NearCallback'. The purpose of which is to take for every colliding geometry pair determine if the need to be resolved and then associate them together in pairs through the global joint group. I strongly recommend using the dWorldQuickStep, to avoid any run-time failures when bodies collide too quickly resulting in a normalization failure. Lastly, the joint group will necessarily need to be emptied before the next step takes place. 

void NearCallback(void *data, dGeomID geom1, dGeomID geom2)
{
   dBodyID body1 = dGeomGetBody(geom1);
   dBodyID body2 = dGeomGetBody(geom2);
   if (body1 && body2) //only shapes with a body may collide.
   {
      const int maxPts = 4;
      dContact kContact[maxPts]
      nbPts = dCollide (geom1,geom2, maxPts, &kContact[0].geom, sizeof(dContact));
      if (nbPts  > 0)
      {
         for (int i=0; i<nbPts ; i++)
         {
            kContact[i].surface.mode = dContactBounce;
            kContact[i].surface.mu = 0.5; //friction
            kContact[i].surface.bounce = 0.5; //restitution
            kContact[i].surface.bounce_vel = 1.0; //minimum speed to incur bounce
            dJointID kJoint = dJointCreateContact (gWorldID, gJointGroup, &kContact[i]);
            dJointAttach (kJoint, body1, body2);
         }
      }
   }
}

7) Shutdown/Cleanup

    dBodyDestroy(kBoxBody);
    dJointGroupDestroy(gJointGroup);
    dSpaceDestroy(gSpaceID);
    dWorldDestroy(gWorldID);
    dCloseODE();

Looking through the demo code was very helpful for me to understand how collision detection, and then collision resolution worked in ODE. Also, the manual is very good at times, but mostly at supplementing the documentation in the code. All the function style calls make for more book-work, but very interesting otherwise, and not terribly difficult to setup. Best of luck and Happy Coding.


Tuesday 23 July 2013

Getting Started : Havok



Another very popular physics engine is Havok, and although I have not worked with professionally, here is how I went about getting a sample running.

0) Setting up the environment

In this case I will be using the hk2011_3_1_r1 version of Havok. Using Premake to generate the Visual Studio solution. Here I have also set havokSDK to point to the  hk2011_3_1_r1 directory, and we will need to include the following libraries. I have omitted some of the recommended ones for animation simply because they will not be necessary for this example.

--Common Libraries (hk)
   links { havokSDK .. '/Lib/win32_net_9-0/debug_multithreaded_dll/hkBase' }
   links { havokSDK .. '/Lib/win32_net_9-0/debug_multithreaded_dll/hkSerialize' }
   links { havokSDK .. '/Lib/win32_net_9-0/debug_multithreaded_dll/hkSceneData' }
   links { havokSDK .. '/Lib/win32_net_9-0/debug_multithreaded_dll/hkInternal' }
   links { havokSDK .. '/Lib/win32_net_9-0/debug_multithreaded_dll/hkGeometryUtilities' }
   links { havokSDK .. '/Lib/win32_net_9-0/debug_multithreaded_dll/hkVisualize' }
   links { havokSDK .. '/Lib/win32_net_9-0/debug_multithreaded_dll/hkCompat' }

--Physics Libraries (hkp)
   links { havokSDK .. '/Lib/win32_net_9-0/debug_multithreaded_dll/hkpCollide' }
   links { havokSDK .. '/Lib/win32_net_9-0/debug_multithreaded_dll/hkpConstraintSolver' }
   links { havokSDK .. '/Lib/win32_net_9-0/debug_multithreaded_dll/hkpDynamics' }
   links { havokSDK .. '/Lib/win32_net_9-0/debug_multithreaded_dll/hkpInternal' }
   links { havokSDK .. '/Lib/win32_net_9-0/debug_multithreaded_dll/hkpUtilities' }
   links { havokSDK .. '/Lib/win32_net_9-0/debug_multithreaded_dll/hkpVehicle' }

-- Collision Libraries (hkcd)
   links { havokSDK .. '/Lib/win32_net_9-0/debug_multithreaded_dll/hkcdInternal' }
   links { havokSDK .. '/Lib/win32_net_9-0/debug_multithreaded_dll/hkcdCollide' }

    configuration "Debug"
      flags { "Symbols" }
      defines { "WIN32", "_DEBUG", "HK_DEBUG", "_CONSOLE", "HK_CONFIG_SIMD=2" }

1) Including the Headers

There may be some alternative to include list, but it will become relatively obvious why we include each of these as we use classes and methods from each.

// Base
    #include <Common/Base/hkBase.h>
    #include <Common/Base/Memory/System/Util/hkMemoryInitUtil.h>
    #include <Common/Base/Memory/Allocator/Malloc/hkMallocAllocator.h>
    #include <Common/Base/Fwd/hkcstdio.h>

// Physics
    #include <Physics/Collide/Dispatch/hkpAgentRegisterUtil.h>
    #include <Physics/Dynamics/World/hkpWorld.h>
    #include <Physics/Dynamics/Entity/hkpRigidBody.h>
    #include <Physics/Collide/Shape/Convex/Box/hkpBoxShape.h>
    #include <Physics/Collide/Shape/Convex/Sphere/hkpSphereShape.h>
    #include <Physics/Utilities/Dynamics/Inertia/hkpInertiaTensorComputer.h>

    #include <Common/Base/System/Init/PlatformInit.cxx>

// Visual Debugger includes
    #include <Common/Visualize/hkVisualDebugger.h>
    #include <Physics/Utilities/VisualDebugger/hkpPhysicsContext.h>

2) Adding the namespace

No namespace necessary.

3) Initialization

Initialization is relatively simple, but we will need to define an error reporting method, usually written as follows.
    
    static void HK_CALL errorReport(const char* msg, void* userContext)
    {
        using namespace std;
        printf("%s", msg);
    }

Then we can proceed as normal, initializing the memory utility and the base system using the default memory allocator.

    hkMemoryRouter* pMemoryRouter = hkMemoryInitUtil::initDefault(
        hkMallocAllocator::m_defaultMallocAllocator, hkMemorySystem::FrameInfo( 500*1024));
    
    hkBaseSystem::init( pMemoryRouter, errorReport );

4) Creating the Scene
    
Havok varies from other physics engines in terminology by creating a physics 'world' instead of a 'scene' in which all actors, shapes, etc are placed. The world is created by first filling a descriptor class. Here we will keep the world as a global static pointer because it will be used frequently elsewhere.

    static hkpWorld* sgpWorld = NULL;

    hkpWorldCinfo kWorldInfo;
    kWorldInfo.m_gravity.set( 0, -9.81, 0.0);
    kWorldInfo.setBroadPhaseWorldSize( 150.0f );
    kWorldInfo.m_collisionTolerance = 0.01;
    kWorldInfo.setupSolverInfo( hkpWorldCinfo::SOLVER_TYPE_4ITERS_MEDIUM );
    sgpWorld = new hkpWorld( kWorldInfo);
    
    hkpAgentRegisterUtil::registerAllAgents(sgpWorld->getCollisionDispatcher());

5) Creating Actors

Rigid body actors, known as 'entities', are created in a manner similar to the world: first by filling a descriptor class used for the entity's constructor. A single entity can only contain a single shape

    hkVector4 halfExtent(1.0f, 1.0f, 1.0f);
    hkpShape* pBoxShape = new hkpBoxShape(halfExtent);

    hkpRigidBodyCinfo kRigidBoxInfo;
    kRigidBoxInfo.m_shape = pBoxShape;
    kRigidBoxInfo.m_mass = 1.0f;

This shape only represents the collision volume, and can have an alternative center of mass, and inertia tensor specified.

    void hkpRigid BodyCinfo::setMassProperties(const struct hkpMassProperties& mp);

The motion type for the rigid body is either fixed, MOTION_FIXEDor dynamic. Fixed motion the equivalent to static/kinematic in PhysX.

    kRigidBoxInfo.m_motionType = hkpMotion::MOTION_DYNAMIC;
    kRigidBoxInfo.m_position = hkVector4(0.0f, 10.0f,0.0f, 0.0f);
    kRigidBoxInfo.m_friction = 0.0;
    kRigidBoxInfo.m_restitution = 1.0;

Once the descriptor is filled the actor is created through its constructor. 

    hkpRigidBody* pRigidBox = new hkpRigidBody(kRigidBoxInfo);

The entity exists independently and can be added or removed from the the world without re-creation.

    sgpWorld->addEntity(pRigidBox);

The shape and entity are now also referenced by the world, so we decrement their internal reference counter.

    pRigidBox->removeReference();
    pBoxShape->removeReference();


6) Simulation

The simulation step is straightforward in this case. Just a single call to step a particular world forward some amount of time.
    
    sgpWorld->stepDeltaTime(fTimestep);

7) Shutdown/Cleanup

Keeping a list of the entities created, and removing them from the world when finished. 

    //hkArray<hkpRigidBody*> aEntityList;

    for(int i=0;i<aEntityList.getSize();i++)
    {
        sgpWorld->removeEntity(aEntityList[i]);
    }

Lastly, the base system and memory utility that where initialized at the start have their own static calls.

    hkBaseSystem::quit();
    hkMemoryInitUtil::quit();

This is fairly basic, but is copied from a working sample. I plan to provide those source files at a later time.
Until then, happy coding.

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.