Home
Demo and Benchmark Documentation Engines
 
Demo and Benchmark Documentation Engines
Navigation
» Introduction » Install Instructions » Developer Documentation » Simple Example » Graphics Engine Integration Examples »»Getting started with Irrlicht and PAL (Terrain example) »»»Setting up Irrlicht with PAL »»»Binding Irrlicht objects to PAL objects »»»Adding the Terrain »»Getting started with Horde3D and PAL (Ragdoll example) » PAL Developer Documentation » PAL Publications

Setting up Irrlicht with PAL

This is the first tutorial on using Irrlicht with PAL. At the end of this tutorial you will be able to drop a number of objects on to a terrain.

To begin with, please ensure that you have PAL installed and compiled, and that you can compile the Irrlicht terrain tutorial. We will be extending the TerrainRendering example.

The first thing to do used is to add the PAL initialisation code to Irrlicht. To do this, insert the following code into the begining of the main function:

	//load physics
	PF->LoadPALfromDLL(); 

	//let user select physics driver, we will just set it to use bullet for now.
	PF->SelectEngine("Bullet");

	//set up physics
	palPhysics *pp = PF->CreatePhysics();
	if (pp)
		pp->Init(0,-9.8,0);

We also need to include the PAL library, do this by adding the header file at the top of the main program:

#include "pal/palFactory.h"
#pragma comment(lib, "libpal.lib") //only for MSVC!

Finally, copy the pal DLL files to the Irrlicht Bin directory (e.g. Copy "bin\Win32-VisualStudio"

Before we can compile this, we will need to include PAL settings to our configuration. (The include and library paths). If you are using Microsoft Visual Studio, you can do this by right clicking on the project, selecting "Properties", then "C/C++", "General", and modifying the "Additional Include Directories" to include PAL. (eg: "C:\lib\pal"). The irrlicht example must also be made compatible with DLL's, so the "Code Generation" option needs to be set to "Multithreaded DLL". We also need to set the library path. Select "Linker" and "Additional Library Directories", add e.g. "C:\lib\pal\lib\release\vs2005".

You should now have a program that compiles and runs - but will do nothing. We still need to glue the PAL code and Irrlicht code together.

^ top

Binding Irrlicht objects to PAL objects

To connect Irrlicht with PAL we need to copy the information from the physics engine (eg: position) to Irrlicht's nodes. We can do this by making a "Bind" class.

class BindObject {
public:
	//the Irrlicht Node
	irr::scene::ISceneNode *node;
	//the PAL "Node"
	palBodyBase *pb;
	//update Irrlicht position from physics
	void Update() {
		//get the location matrix from the physics system
		palMatrix4x4 matrix = pb->GetLocationMatrix();
		//copy it to a Irrlicht matrix
		core::matrix4 mat;
		memcpy(&mat[0], matrix._mat, sizeof(f32)*4*4);
		//set the node position from our Irrlicht matrix
		node->setPosition(mat.getTranslation());
		node->setRotation(mat.getRotationDegrees());
	}
};

Lets test out our new class by creating some cubes. First, we will keep a array of all the objects that we create. This way we know what to update.

Then we can create the Irrlicht scene node, and a corresponding physics box. Finally, we add this to our vector.

//our vector of all physics objects
std::vector<BindObject *> vbo;

//lets make 7 cubes
for (int i=1;i<7;i++) {
	BindObject *pbo = 0;
	float size = 300.0f;
	//create a new bind object
	pbo = new BindObject;
	//lets set the bind object node to a cube scene node
	pbo->node =  smgr->addCubeSceneNode(size,0,-1,core::vector3df(0,0,0),core::vector3df(0,0,0),core::vector3df(1,1,1));
	//lets create a physics box as well
	palBox *pb = PF->CreateBox();
	//set the physics position, and a matching size
	pb->Init(size*i*5,size*5,size*i*5,	size,size,size,	10);
	//assing the bind object body to the physics box
	pbo->pb = pb;
	//add this to our vector of objects
	vbo.push_back(pbo);
}

Now we have everything to display and calculate, but we still have not told the physics to actually calculate anything. To do that, we need to add some code to the main "while(device->run())" loop.

First, we tell the physics engine to increment the time step. This tells the physics engine how much time has passed, and will cause it to calculate the new positions of all our objects.

After this, we will loop through our array of objects, and update the positions.

//update physics
if (pp)
	pp->Update(1/60.0f); //timestep

	//update the irrlicht graphics to be at the same location as the physics engine
	for (i=0;i<vbo.size();i++) {
		vbo[i]->Update();
	}

Now we have something ready to run!

But the cubes fall through the ground! Oh no! We still need to add the terrain.

^ top

Adding the Terrain

Now we will be adding the terrain to the physics engine. So we will not to be needing the Irrlicht terrain collision system (remove from "ITriangleSelector" to "anim->drop()"). Now we will add our own function that will place the terrain at our own desired location and scale.

To begin with we call Irrlichts "addTerrainSceneNode" function. Then, we get access to the buffer that has the vertex and index information for the terrain. This data is then extracted, and passed into the physics engine via the "ptm->Init" call.

void LoadTerrain(float x, float y, float z, float sx, float sy, float sz) {
	//call the irrlicht add terrain scene node
		g_terrain = g_smgr->addTerrainSceneNode( 
		"../../media/terrain-heightmap.bmp",
		0,                                    // parent node
		-1,                                   // node id
		core::vector3df(x, y, z),             // position
		core::vector3df(0.f, 0.f, 0.f),       // rotation
		core::vector3df(sx, sy, sz),          // scale
		video::SColor ( 255, 255, 255, 255 ), // vertexColor,
		5,                                    // maxLOD
		scene::ETPS_17,                       // patchSize
		4                                     // smoothFactor
		);

	//get the vertex buffer
	scene::SMeshBufferLightMap smb;
	g_terrain->getMeshBufferForLOD(smb,0);

	//get the number of vertices and indicies from Irrlicht 
	int nv = smb.getVertexCount ();
	int ni = smb.getIndexCount 	();
	
	//create the physics terrain mesh, and some space to store our data
	palTerrainMesh *ptm = PF->CreateTerrainMesh();
	float *pVerts = new float[3*nv];
	int *pInds = new int[ni];
	
	//get a pointer to the verticies and indicies from Irrlicht 
	irr::video::S3DVertex2TCoords* pv = (irr::video::S3DVertex2TCoords*) smb.getVertices();
	irr::u16* pi = (irr::u16*)smb.getIndices();   
	//copy the vertex and index data
	int i;
	for (i=0;i<nv;i++) {
		pVerts[i*3+0]=sx*pv[i].Pos.X + x; //scale each vertex by sX and set its position with x
		pVerts[i*3+1]=sy*pv[i].Pos.Y + y;
		pVerts[i*3+2]=sz*pv[i].Pos.Z + z;
	}
	for (i=0;i<ni;i++) {
		pInds[i]=pi[i];
	}
	//initialize the physics terrain
	ptm->Init(0,0,0,pVerts,nv,pInds,ni);
	delete []pVerts;
	delete []pInds;
}

Now lets call our function:

LoadTerrain(0,0,0,
				40,4.4,40);

When you run the program, you will see the cubes are now bouncing off the terrain. However, the scale we are using is not suitable for all physics engines, so lets resize our world to be a bit more realistic.

scene::ICameraSceneNode* camera = 
		g_smgr->addCameraSceneNodeFPS(0,100.0f,12.0f);
	camera->setPosition(core::vector3df(0,15,10));
	camera->setTarget(core::vector3df(10,15,10));
	camera->setFarValue(120.0f);
...	
	LoadTerrain(-100,0,-100,
				0.8,0.04,0.8);
...
	float size = 2.0f;
Finally, lets take advantage of PAL to let the user select a physics engine:

std::cin >> i;
	switch(i)
	{
		case 'a': PF->SelectEngine("Bullet");break;
		case 'b': PF->SelectEngine("Jiggle");break;
		case 'c': PF->SelectEngine("Newton");break;
		case 'd': PF->SelectEngine("ODE");break;
		case 'e': PF->SelectEngine("SPE");break;
		case 'f': PF->SelectEngine("Tokamak");break;
		case 'g': PF->SelectEngine("TrueAxis");break;
		default: return 1;
	}	
PAL Physics with Irrlicht