Friday 11 July 2014

PhysX - Distance Joint

Introduction to Joint Springs

Just like Fixed Jointswe need a couple rigid actors.
    PxRigidActor* pRA1,* pRA2;

I'll give them box shapes of unit length.
    PxBoxGeometry geo(PxVec3(0.5,0.5,0.5));

    PxTransform pform = PxTransform::createIdentity();

In our example one will be kinematic, to hold up the other.
    pform.p = PxVec3(0,5,0);
    pRA1 = PxCreateDynamic(*gPhysicsSDK, pform,geo,*defaultMaterial, 1.0);
    pRA1->isRigidDynamic()->setRigidDynamicFlag(PxRigidDynamicFlag::eKINEMATIC,true);

    pform.p = PxVec3(2,5,2);
    pRA2 = PxCreateDynamic(*gPhysicsSDK, pform,geo,*defaultMaterial, 1.0);
 
Add them to the scene.
    gScene->addActor(*pRA1);
    gScene->addActor(*pRA2);

We will also need a couple transforms to represent the where the joint attaches to the two actors.
    PxTransform local1 = PxTransform::createIdentity(), local2= PxTransform::createIdentity();

Creating the joint is done as before.
    PxDistanceJoint* pJoint = PxDistanceJointCreate(*gPhysicsSDK, pRA1, local1 ,pRA2, local2);

and although not necessary this time we can set the collision flag.
    pJoint->setConstraintFlag(PxConstraintFlag::eCOLLISION_ENABLED,true);

The distance joint may act as a string or a spring, connecting the two actors. There are three flags available for the distance joint.

    PxDistanceJointFlag::
        eSPRING_ENABLED
        eMAX_DISTANCE_ENABLED
        eMIN_DISTANCE_ENABLED

by default only the eMAX_DISTANCE_ENABLED is active. With the spring flag disabled the max distance is a hard limit for the joint. However if the spring flag is enabled then this becomes the distance at which the spring force becomes active.



Similarly a minimum distance can be set, but cannot exceed the maximum distance, the spring force will pull the actors to remain between the min and max distance limits.

Recall the Force equation for a spring:

    F_spring = - k * x

where 'k' is the spring constant, and 'x' is the distance from the natural length, or in our case, the distance from the min or max limits.

The force experienced by the actors will need to be adjusted by a damping force

    F_damping = - c * x'

where 'c' is the damping coefficient, and x' is the first derivative with respect to time of the distance from the natural length (the speed)

    F_net = F_spring + F_damping - F_gravity

A spring experiencing a damping force will eventually stop at an equilibrium length (not necessarily the same as the natural length)

The magnitude of the damping coefficient should be chosen to fall into one of four categories. These categories are decided by the ability of the damping to stop the oscillation.

let z = c/sqrt(4mk);

  • Un-Damped ( z == 0, so c must be 0)
    Choose Un-Damped if you want the spring to oscillate back and forth forever.
  • Under-Damped ( 0 < z < 1)
    Choose under damped if you want some resemblance of a spring effect where it may oscillate back and forth a few times before coming to rest at an equilibrium state. 
  • Critically-Damped ( z ==1 )
    Choose critically damped if you want the spring to slow perfectly to it's equilibrium.
  • Over-Damped ( z > 1 )
    Choose over damped if you want the spring to slow down a lot to start and very gradually approach equilibrium. 



From left to right we have No Spring, Un-damped, Under-damped, Critically-damped, and Over-damped. The distance joint without a spring stops immediately at its maximum distance. For the rest, the spring does not begin applying a tension until they pass that maximum distance.

Notice that although critically-damped, the box overshoots it's equilibrium position anyway. This is because of the extra momentum generated before the spring was active. I will explain this further in a future post.

Setting the values are straight forward,

    pJoint->setSpring(15.0f);
  pJoint->setMaxDistance(3.0f);
    pJoint->setMinDistance(1.0f);
    pJoint->setDamping(0.5);

but are meaningless without the corresponding flag set.

    pJoint->setDistanceJointFlag(PxDistanceJointFlag::eSPRING_ENABLED,true);


Hopefully this gives an preview of how distance joints are created and how the spring feature works.
Happy Coding!


Thursday 3 July 2014

Getting Started : PhysX - Fixed Joints

Introduction to PhysX Joints

PhysX provides a number of options for the types of joints which may be created. I will work through the creation of each pointing out aspects which might be of interest.

The basic formula for creating any joint is the same. We need access to the PxPhysics singleton factory, at least one rigid actor, and the transform from each actor to the point where the joint is formed.

    Px[Type]Joint* Px[Type]JointCreate(
        PxPhysics& physics,
        PxRigidActor* actor0, const PxTransform& localFrame0,
        PxRigidActor* actor1, const PxTransform& localFrame1);

As mentioned, only one of the two actors needs to be defined. It is possible to create a joint by attaching one side to a point in world space (in which case a NULL pointer may be passed for the actor).

Fixed Joint

Arguably the simplest case, and perhaps the most unused, a fixed joint provides no freedom of movement. It's most useful feature is that it can be broken while experiencing an applied force. After creating a fixed joint I explain how to choose appropriate values for the break force and torque.

First we need our shapes and actors, we can start with some boxes of unit size.

    PxBoxGeometry boxGeo(PxVec3(0.5,0.5,0.5)); //Dimensions are for half-length

    PxRigidActor *pRA1, *pRA2;
    PxTransform kform = PxTransform::createIdentity();

    kform.p = PxVec3(0,3,0);
    pRA1 = PxCreateDynamic(*gPhysicsSDK, kform ,boxGeo,*defaultMaterial, 1.0);
    pRA1->isRigidDynamic()->setRigidDynamicFlag(PxRigidDynamicFlag::eKINEMATIC,true);

    kform.p = PxVec3(1,3,0);
    pRA2 = PxCreateDynamic(*gPhysicsSDK, kform , boxGeo,*defaultMaterial, 1.0);

I have set one of the actors to be kinematic so it will remain suspended despite gravity, while the other will be held up entirely by the strength of the joint. Since the boxes they are of unit length, and are one unit apart, the surfaces will be in contact.

It should also be noted that the joint is formed between the two actors and not the shapes themselves. If the shape isn't centered on the actor, or the actor contained multiple shapes then we might want to consider different local frames.

    PxTransform local1 = PxTransform::createIdentity(),
        local2= PxTransform::createIdentity();

    local1.p = PxVec3(0.5,0,0);
    local2.p = PxVec3(-0.5,0,0);

    PxFixedJoint* pJoint = PxFixedJointCreate(*gPhysicsSDK, pRA1, local1 ,pRA2, local2);

I have moved the position of the local frame to be the same distance as the half-length of the box. This way the joint exists at the edge of the box and not within it. Leaving the position at (0,0,0) will center the joint on the middle of the actor causing the two actors to draw together until they overlap. Moving the local frame further from the origin will force the actors to start further apart. I have made it so that the joint end positions fall exactly on the surface of the box.

For a fixed joint there are two important modifiers to consider. First is the break force, which defines the force and the torque at which the joint will break. These are set to a maximum value by default, but there are some cases in which you would want actors to break apart.

    pJoint->setBreakForce(fForce, fTorque);

In this example the weight of the actor is a force of its own which could break the joint. A box of unit size, and of unit density will have a unit mass.

    mass = 1.0f;

and if we set gravity to a convenient number,

    gravity = PxVec3(0.0f, -10.0f, 0.0);

then the shearing force on our arrangement is

    Force = mass*gravity = 1.0 * -10.0 = -10.0

so in order for one box to not break the joint we need a minimum break force of 10.0.

We also need to consider the torque of the actors themselves. In the simple case like this, where the applied force (due to the weight of the object) is already perpendicular to the axis of the joint the torque calculation is simple.

    Torque = length x force = |length|*|force|*sin(90deg) = |length|*|force|

the length of the lever arm is measured from the joint to the actor, which is also the magnitude of the position vector of the local frame.

    length = |localPose2.p| = |(-0.5,0,0)| = 0.5

    Torque = length * force = 0.5 * 10.0 = 5.0

These are example calculations of the minimum force and torque required to suspend a box of unit size and density off the side of a fixed actor. Further estimations should be made to accommodate for collisions with other actors as well.



The other important modifier is the constraint flag. In particular the default setting is that objects constrained by a joint are allowed to pass through each other. The only constraint is the one enforced by the joint itself. In some cases it may be better for actors connected by a joint to be allowed to interact and collide with each other.

    pJoint->setConstraintFlag(PxConstraintFlag::eCOLLISION_ENABLED, true);

Best of luck finding uses for fixed joints.
Happy Coding!

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.