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.






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.