Havok Physics Tutorial 1

Most gamers and video game developers know more or less what is Havok engine. Beside physics simulation and collision detection, Havok offers many other features, like animation, realistic cloth or dynamic destruction of rigid bodies. Being cross platform middleware, Havok is used in pretty large number of video game titles: from PC’s Painkiller, PSP Killzone: Liberation to Assassin’s Creed, Dead Space or Fallout 3 on modern video game systems. Best thing – you can try it for free and use it in your home-made game or demo application. After registration on Havok site, you get binary bundle featuring standard Havok Physics and Havok Animation products.

Havok logoIt could be hard for one to instantly “jump in” and create a simulation using Havok. Provided documentation is excellent and there are Havok software engineers on Intel Software Network to help and answer questions, but the SDK and it’s range of features are huge. Therefore I would like to write some tutorials or helpers about starting with Havok Physics 6.5.0. I believe that beside official support, it’s hard to find such information elsewhere, so hopefully it will help someone (or not, anyway – I’m going to write something).

Tutorial is intended for C++ developers, not artits or modellers (you can also use Havok in 3D modelling applications, like 3ds max), so you should have basic C++ skills and Microsoft Visual C++ IDE. I will present how to setup and link libraries, initialize Havok, create a flat surface and preview it in Visual Debugger. Of course all of it can be found in documentation and demos added to SDK, but I’ll try to compact everything here. Continue to tutorial with following link:

1. Getting started with Visual Debugger

After unpacking SKD, check folder structure. /Docs contains quickstart and user guides, which you should get familliar with and refer to when something written here is incomplete, doesn’t work for you or you have a feeling that i’m just wrong.

Check the /Demo and /Tools folders. /Tools contains Visual Debugger – a very useful application which we will be using extensively from now to preview results of our progress. Powerful feature of Visual Debugger is ability to remotely connect to machine which runs the simulation. In Network bookmark in Visual Debugger options you can set IP address and socket used to communicate over network. If you use the same machine to run simulation and Visual Debugger, set ip address to localhost or 127.0.0.1

All right, Visual Debugger presents empty scene and says [Connecting...] on title bar. We have to feed simulation data to it. Go to /Demo folder to find executable demo example in /StandAloneDemos. Run ConsoleExample… executable and check Visual Debugger. You should see ball breaking through set of walls. Steer camera to preview entire scene (check View->Camera->Fly mode).

Havok Visual Debugger in action

SimpleMultithreadedConsoleMain.cpp contains whole source code of this demo. It is excellent starting point to learn. If you feel adventurous, open provided VC++ solution (.vcproj), look at, modify the code and build it yourself. Proivided project is already set up, so it should build without a problem. In the next section we will see how to link newly created project and initialize Havok from scratch.

2. Linking with Havok

Run Visual C++ and create new windows console empty project. I use VC++ 2008 Express, if you have another version, there will probably be minor interface differences from provided screenshots. In project properites window select Linker->General->Additional Library Directiories. Add a library path hk650r1\Lib\win32_net_9-0\debug_multithreaded_dll using file dialog.

Linking Havok - additional library directories

Add common and physics libraries in Linker->Input->Additional Dependencies.

common libraries (hk prefix):

  • hkBase.lib (provides functionality common to all Havok libraries)
  • hkCompat.lib (version compatibility library)
  • hkGeometryUtilities.lib (geometry operations)
  • hkInternal (A public interface to Havok’s internal classes and data structures)
  • hkSceneData.lib (data descriptions that are extracted from the animation toolchain)
  • hkSerialize.lib (import/export library – havok data serialization)
  • hkVisualize.lib (Visual Debugger definition)

physics libraries (hkp prefix):

  • hkpConstraintSolver.lib (constraint solver)
  • hkpCollide.lib (collision detection functionality)
  • hkpDynamics.lib (core dynamics library)
  • hkpInternal.lib (a public interface to Havok’s internal classes and data structures)
  • hkpUtilities.lib (contains a number of handy utilities, including example actions and the Visual Debugger)
  • hkpVehicle.lib (abstraction layer and default vehicle implementations for the Havok Vehicle Kit)
Linking Havok - additional dependencies

Thats all we need for now. Library detail and dependencies can be also be found in Quickstart Guide. If you check properties of stand-alone demo mentioned earlier, you will see those libraries linked there. You can copy entire list to your project.

Now create empty .cpp file main.cpp with following main() function:
int main(int argc, const char** argv) {}

By doing this a new tab , C/C++, will appear in project configuration properties. Go to C/C++->General->Additional Include Directories and add path hk650r1\Source. That directory will be added to list of directories searched for include files. From now on, when we write #include statement in our code, compiler will search there for specified headers.

Linking Havok - additional include directories

In addition, add HK_DEBUG to preprocessor definitions (C/C++ ->Preprocessor->Preprocessor Definitions) .

3. Coding – Havok utility class

Some coding at last! If you look on that stand alone demo we launched at at the beginning, you will see that it is written procedurally for simplification. Drawback of that solution is much code in one place (although comments written by demo makers are very good and they help to orientate). I deciced to take adventage of more OO approach. Take a look at declaration of a class which encapsulate Havok data and allow to step the simulation forward.

class HavokUtilities
{
public:
 HavokUtilities(void);
 virtual ~HavokUtilities(void);

 void registerVisualDebugger();

 void stepSimulation(float dt);
 void stepVisualDebugger(float dt);

 hkpWorld* getWorld();
 hkVisualDebugger* getVisualDebugger();
 float getTimestep();

private:
 void initHavok();
 void deinitHavok();

 bool m_visualDebuggerActive;

 hkpWorld* m_world;
 hkVisualDebugger* m_vdb;
 hkpPhysicsContext* m_context;

 hkJobThreadPool* m_threadPool;
 hkThreadMemory* m_threadMemory;
 hkJobQueue* m_jobQueue;
 char* m_stackBuffer;
};

That seems complicated, and it may break “The Single responsibility principle” but at least everything is contained in single class for your convenience. Let’s start with interface:

  • HavokUtilities() sets default timestep and calls private initHavok() method (data initialization).
  • ~HavokUtilities() calls deinitHavok(). This way, if HavokUtilities object is destroyed, all resources assigned by it will be freed.
  • registerVisualDebugger() sets up Visual Debugger. If you want to use VD, you have to call this after creating HavokUtilities object
  • stepSimulation(float dt) and stepVisualDebugger(float dt) methods have to be called inside some loop. They tell the simulation and VD to step forward by delta time dt.
  • getWorld() returns pointer to hkpWorld (Havok world instance)
  • getVisualDebugger() returns pointer to hkVisualDebugger (VD instance)

In the interface section you can see declaration of physics world, Visual Debugger and context(which processes information from referenced world and presents them to debugger). World is container for simulated objects. We can add simulation elements to it, and during simulation stepping physical interactions of those objects will be resolved.

Havok memory, thread pool and job queue are declared below. Thread pool and job queue are used in multithread world stepping. If you would like to read more about how multithreading is implemented in Havok, refer to “Multithreading” chapter in User Manual. At the moment keep in mind that after registering physics world with job queue (initHavok() function):

m_world->registerWithJobQueue(m_jobQueue);

we can step the world using current and all the threads in the thread pool (stepSimulation() function):

m_world->stepMultithreaded(m_jobQueue, m_threadPool, dt);

There is no point in pasting whole source file here, just download header and implementation and add them to your project. Header has also pretty number of necessary includes not listed in class declaration previously. Both have extensive comments so take a look at them and try to figure how everything works. You should have HavokUtilities.hpp, HavokUtilities.cpp and main.cpp with empty main() function in your project.

HavokUtilities.hpp

HavokUtilities.cpp

4. Coding – application loop

Now we have to esablish some kind of game loop in main(). We will duplicate this loop from stand alone Havok demo, but before that we have to create our HavokUtilities object, register VDB:

int main(int argc, const char** argv)
{
    HavokUtilities* havokUtilities = new HavokUtilities();
    havokUtilities->registerVisualDebugger();

and create application loop:

   //create watch object - we will simulate for 30 seconds of real time
   hkStopwatch stopWatch;
   stopWatch.start();
   hkReal lastTime = stopWatch.getElapsedSeconds();

   //initialize fixed time step - one step every 1/60 of a second
   hkReal timestep = 1.f / 60.f;
   //calculate number of steps for entire loop
   //(30 seconds divided by single time step)
   int numSteps = int(30.f / timestep);

   //application loop, breaks after 15 real time seconds
   for ( int i = 0; i < numSteps; ++i )
   {
       //step the simulation and VDB
       havokUtilities->stepSimulation(timestep);
       havokUtilities->stepVisualDebugger(timestep);

       //pause until the actual time has passed
       while (stopWatch.getElapsedSeconds() < lastTime + timestep);
       {
            lastTime += timestep;
       }
   }

We set a watch to simulate 30 seconds of real time - that's our simulation duration. 1/60 time step means that simulation should be stepped 60 times during one second of real time. Time stepping if complicated concept, especially with varying framerate (i.e. in real applications with graphics). For our console demo this fixed step should work well.

After setting time step, we calculate number of steps needed for entire simulation and run a loop, where simulation and VDB are stepped forward by that fixed time step. To simulate real time pass, we hold loop execution after stepping until the actual time has passed. Don't forget to delete HavokUtilities object after loop, so it can call deinitHavok() and free aquired resources.

Our demo should confirm connection to Visual Debugger by writing to the console, although scene in VBD will be still empty - we haven't added any objects to the simulation.

Application running with visual debugger connected

5. Coding - creating fixed surface

Last thing I promised at the beginning of this tutorial - we will create a flat, fixed(static game scene element) surface to preview in VDB. It's not much, but it shows the basics of Havok shapes creation. Write function definition in main.cpp, before main() function:

void addFixedSurface(hkpWorld* world, const hkVector4& position,
                             const hkVector4& dimensions)

Function takes a pointer to physics world, shape position, size and width. Fixed figure with specified dimensions will be added to simulation. Let's see the implementation:

void addFixedSurface(hkpWorld* world, const hkVector4& position,
                             const hkVector4& dimensions)
{
  	//addFixedSurface function
  	//creates fixed surface with specified position and dimensions

  	//create box shape using given dimensions
  	hkpConvexShape* shape = new hkpBoxShape(dimensions,0);

  	//create rigid body information structure
  	hkpRigidBodyCinfo rigidBodyInfo;

  	//MOTION_FIXED means static element in game scene
  	rigidBodyInfo.m_motionType = hkpMotion::MOTION_FIXED;
  	rigidBodyInfo.m_shape = shape;
  	rigidBodyInfo.m_position = position;

  	//create new rigid body with supplied info
  	hkpRigidBody* rigidBody = new hkpRigidBody(rigidBodyInfo);

  	//add rigid body to physics world
  	world->lock();
  	world->addEntity(rigidBody);

  	//decerase reference counter for rigid body and shape
  	rigidBody->removeReference();
  	shape->removeReference();

  	world->unlock();
}

Funtion first creates a hkBoxShape, which defines the object's shape and size for collision detection purposes. hkBoxShape constructor takes half extents as a parameter - X by Y by Z box has a X/2 by Y/2 by Z/2 half extents. This shape, among with position and motion type is used to fill rigid body info structure. Any scene object that doesn't change it's size could be rigid body - boxes, surfaces, car chassis etc. MOTION_FIXED motion type means that object will be static in our physics world. It is necessary - fixed motion type will cause it to fall, according to gravitation set during initialization.

The function has one more thing to do: create a rigid body with rigidBodyInfo passed as a parameter and add it to physics world. Notice the removeReference() calls on rigidBody and shape objects. Havok manages those objects by using a reference system. Therefore physics world (hkpWorld) will keep reference to rigid body once added. If we don't need it anymore here, we could decerase reference counter, giving hkpWorld object full ownership over the object.

We have to call addFixedSurface() in our main() function, after we create HavokUtilities object:

 HavokUtilities* havokUtilities = new HavokUtilities();
 havokUtilities->registerVisualDebugger();
 addFixedSurface(havokUtilities->getWorld(), hkVector4(0,0,0),
                 hkVector4(50.0f,1.0f,50.0f));

This code will create a 100 by 100 surface, with 2 units height, positioned in world origin. Run console application and connect Visual Debugger, you should see something similar to this:

Simulation preview in Visual Debugger

Full main.cpp source can be found here:

main.cpp

6. Summary

This demo covers basic knowledge about Havok Physics. Change something in our application, i.e. change created surface or rigid body motion to MOTION_DYNAMIC, and see the results. The User Guide is very well written and it's your main source of knowledge about Havok, so take a look inside if you haven't already. I plan another part of this tutorial, with dynamic bodies and real physics simulation. If you don't want to wait - see that multithreaded standalone demo supplied with Havok (you should now understand most of the source) - in the next tutorial we create something similar. You can check other demos too, but they have to be build first. Quickstart Guide contains information how to do it.

Archive with full source code and VC++ 2008 solution for this tutorial can be obtained using following link (don't forget to change paths for included directories):

HavokTutorial1.rar

Share this article:
  • Print
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • HackerNews
  • Reddit
  • Wykop

7 Responses to “Havok Physics Tutorial 1”

  1. sam says:

    how can i make a standalone demo,not require the visual debugger???

  2. Piotr Pluta says:

    sam,
    Havok Physics is only middleware – you have to bind it with graphics code to display results of you simulation/game. It could be pure DirectX/OpenGL or some graphics engine like Ogre3D. I will not touch the details here, but generally you take positions of objects from Havok and feed them to the rendering engine.
    I could (and I probably will) prepare a tutorial that shows how to connect Havok with rendering API, but I have to find some time to do it.

  3. Bill says:

    Hey Piotr,

    Thanks for putting this together. I’ve just started at looking at the Havok SDK and I’m fairly inexperienced with OOP as well. This guide filled in some massive gaps in my knowledge so that I could start using the Havok guide. Awesome work! I’ll definitely look out for the next tutorial.

  4. kaka says:

    Thanks for the introduction to havok. It’s reader friendly and useful!

    I’m very much looking forward to your tutorial to show how to connect havok with a rendering API or engine. Thanks!

  5. Piotr Pluta says:

    I’m glad that you find it useful. Positive comments motivate me to finally find some time and make that Havok+rendering tutorial:)

  6. Fritz says:

    Thanks for this tutorial, I’m an expereinced C++ prgorammer but the documentation t comes with Havok is so helter skelter and unorganized that it is practically impossible for a newcommer to understand how to do things

  7. jaVid says:

    THanks For The Information and tutorial ! =)

    and it seems that we don’t have to convert our 3D model into Direct .X file when we use Havok sdk!
    we can load .max (3ds max ) file!!!!! that’s good =)

    the question is will we use direct sdk codes for cams and light ect ?

    i think we will use autodesc Motion Builder for best character motion . .

    problem is that i can’t find tuts of this havok !

    Thanks Again! =)

Leave a Reply