Tokamak integration

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Guest

Tokamak integration

Post by Guest »

I am trying to create the generic "falling blocks" physics demo in irrlich to give myself a quick introduction to both. I'm using the "Enhancing the engine" tutorial as a basic to create my blocks, and this tokamak tutorial here[url] for the physics portion.

The only problem I'm having is transferring the translation matrix from tokamak to the irrlich objects. Has anyone else made any progress integrating tokamak (or any other physics engine)?

Thanks in advance
¿?
enigmatic
Posts: 8
Joined: Mon Oct 13, 2003 1:06 pm

Post by enigmatic »

Well, I guess the link was abused by BBCode. At least it works. And I'm enigmatic, the guy who posted this.

Hopefully something will come out of all this
Gorgon Zola
Posts: 118
Joined: Thu Sep 18, 2003 10:05 pm
Location: switzerland

Post by Gorgon Zola »

hi,
try with 'scenenode.getAbsoluteTransformation()'
irrlicht matrix is on row major order, that is, you could just use the same code like for filling a D3DMatrix

hope this helps, I'd really like to see your demo when it's done
:)
cheers
gorgon
enigmatic
Posts: 8
Joined: Mon Oct 13, 2003 1:06 pm

Post by enigmatic »

But how do I set the matrix equal to the value returned by tokamak? Here's the code right now:

Code: Select all


			neT3 t = gCubes[i]->GetTransform();

			irr::core::matrix4 mat = CubeNode[i]->getAbsoluteTransformation();

			mat(0,0) = t.rot[0][0];
			mat(0,1) = t.rot[0][1];
			mat(0,2) = t.rot[0][2];
			mat(0,3) = 0;
			mat(1,0) = t.rot[1][0];
			mat(1,1) = t.rot[1][1];
			mat(1,2) = t.rot[1][2];
			mat(1,3) = 0;
			mat(2,0) = t.rot[2][0];
			mat(2,1) = t.rot[2][1];
			mat(2,2) = t.rot[2][2];
			mat(2,3) = 0;
			mat(3,0) = t.pos[0];
			mat(3,1) = t.pos[1];
			mat(3,2) = t.pos[2];
			mat(3,3) = 1.0;
Gorgon Zola
Posts: 118
Joined: Thu Sep 18, 2003 10:05 pm
Location: switzerland

Post by Gorgon Zola »

Ouups, your right thats no mointer returned, hmm...
seems there's no method to get access to the matrix
but there are setPosition and serRotation methods,
well... maybe niko could add an interface to set the transformation matrices then? in the next version? would be really handy for physic plugins...

But meanwhile you could still extend ISceneNode and build your own node with access to the node, and copy past the code from niko's implementation classes... a bit complicated i think :cry: ...
enigmatic
Posts: 8
Joined: Mon Oct 13, 2003 1:06 pm

Post by enigmatic »

OK, I can get the position stuff working using the Node->setPosition() method:

Code: Select all

			neV3 p = gCubes[i]->GetPos();

			TempVect.X = p[0];
			TempVect.Y = p[1];
			TempVect.Z = p[2];

			CubeNode[i]->setPosition(TempVect);
if I set the AbsoluteTransformation matrix, it completely wigs out, so I want to use the setRotation method. This will make it easier for everyone else to.

The question is, how to convert from the translation matrix to angles? I can't seem to find any angle methods that work in tokamak's API, so is there an easy mathmatical way of doing this?
enigmatic
Posts: 8
Joined: Mon Oct 13, 2003 1:06 pm

Post by enigmatic »

Woo, got it!!!

I need to majorly clean up the code, then I'll upload it. Here's a quck executable though:

http://enigmatic.shackspace.com/boxdrop.zip

Basicly, the tokamak object has a getRotationQ() function that returns a X, Y, Z, W matrix that corrisponds to the rotation about the respective axis (in radians). I don't know what the W is though. Any ideas?

Quick key guide to demo:
Alt+F4 - exit
Arrow keys - move
mouse - look

(it's using the FPS camera, so no fancy stuff there)
Cleves
Posts: 224
Joined: Mon Sep 08, 2003 6:40 pm

Post by Cleves »

looks great m8! nice physics :D
FleshCrawler
Posts: 108
Joined: Fri Aug 22, 2003 1:04 pm
Location: Kerkrade, Netherlands
Contact:

Post by FleshCrawler »

wow, nice :)
I've been absent for really long, but i'm ready to reign my terror on you once again, mwuahahahahaha
Guest

Post by Guest »

[quote="enigmatic"]
Basicly, the tokamak object has a getRotationQ() function that returns a X, Y, Z, W matrix that corrisponds to the rotation about the respective axis (in radians). I don't know what the W is though. Any ideas?
quote]
cool!
could be that the tokamak function returns the rotation quaternion. if you'r into maths :
http://www.gamedev.net/reference/articl ... le1095.asp
enigmatic
Posts: 8
Joined: Mon Oct 13, 2003 1:06 pm

Post by enigmatic »

Yup, it's a quaternion...or at least, I'm pretty sure it is. I still don't know where the W fits into all this, because it's not a scale, nor does it seem to relate to the rotations in any other way.

I'm working on the code tonight, so hopefully I'll have it up late this evening :)
enigmatic
Posts: 8
Joined: Mon Oct 13, 2003 1:06 pm

Tutorial

Post by enigmatic »

I'd sent the source to Niko. Hopefully he'll get it up, or at least do something with it :)

Here's the file: http://enigmatic.shackspace.com/boxdrop.zip (388k)

And here's the pieces of the tutorial that matter:
Irrlicht/Tokamak integration tutorial by enigmatic (enigmatic@shackmail.com)

Code based off Irrlicht tutorial 3, Creating a Custom Scene Node
Found here: http://irrlicht.sourceforge.net/tut003.html

With tokamak information taken from Adam Dawes' cube stacking
tutorial found here: http://www.adamdawes.com/programming/to ... Cubes.html

I will go over the entire code, however the vast majority of it comes from one
tutorial or the other. I will note which is which, and any alterations I have
made. I will also note my own code.

A very important note is that irrlicht and tokamak use the same names for some
data types. This causes all sorts of errors. Thankfully irrlicht has been written
with integration in mind, and is built using namespaces. Tokamak, on the other had,
does not. This means that you are forced to reference the irrlich namespace rather
use the "using" keyword to simplify tasks. You do this by placing "irr::" in front
of all irrlicht specific calls.

I'm going to concentrate on the integration stuff, and skim over the rest, since I
don't want to cover what's already been taken care of thanks to the tutorials above.

Irr denotes Irrlicht
Tok denotes Tokamak
Includes

These come from both tutorials. The irrlicht and tokamk libraries are self
explanitary, while the others are a little strange. These are used for the
timing functions. Nothing to magical beyond that

Code: Select all

#include <irrlicht.h>
#include <tokamak.h>
#include <windows.h>
#include <time.h>
Inclusion of the specific libraries. Again, the abbaration is the
winmm library, used for the timeGetTime() function.

Code: Select all

#pragma comment(lib, "Irrlicht.lib")

#ifdef _DEBUG
#pragma comment(lib, "tokamak_d.lib")
#else
#pragma comment(lib, "tokamak.lib")
#endif

#pragma comment(lib, "winmm.lib")
Defines to make playing with the simulation easier.

PI is used to convert from Degrees to Radians.
CUBECOUNT is the number of cubes to stack
CUBEX/Y/Z are the dimentions of the cube (any size box you want)
CUBEMASS is the mass of the cube
FLOORSIZE is the size of the square "floor" that the cubes fall on.

Play with the cube information and see what happens (to heavy, or to
small cubes seem to fall through the floor)

Code: Select all

#define PI 3.1415926
#define CUBECOUNT 30
#define CUBEX 5.0
#define CUBEY 5.0
#define CUBEZ 5.0
#define CUBEMASS 50.0f
#define FLOORSIZE 300
tok - Global variables for Tokamak:
First the simulator itself

Code: Select all

neSimulator *gSim = NULL;
The cube pointer array

Code: Select all

neRigidBody *gCubes[CUBECOUNT];neAnimatedBody *gFloor = NULL;
Timer variables

Code: Select all

bool gbUseHFTimer;
INT64 gCurrentTime;
float gfTimeScale;
tok - almost straight from the tok tutorial, we initialize the physics engine:

Code: Select all

bool InitPhysics(void)
Vary the position so the cubes don't all exactly stack on top of each other
(makes for a more interesting simulation)

MC - You may need to play with the randomization stuff, since your cube may be to big to be easily destabelized

Code: Select all

		pos.Set((rand()%10) / 20.0f * CUBEX, 4.0f + i * (CUBEY + 1) ,  rand()%10) / 20.0f * CUBEZ);
		gCubes[i]->SetPos(pos);
OK, the main function, where the meat is. Here's where I had the most fun.

Code: Select all

int main()
{
tok - timer stuff

Code: Select all

	float fElapsed;
    static float fLastElapsed;
	int i;
MC - I needed a vector3df to pass to the Node movement functions

Code: Select all

	irr::core::vector3df TempVect;
MC - I moved the camera so the initial view is more interesting then turned it toward the origin, there the cubes fall

Code: Select all

	camera->setPosition(irr::core::vector3df(20,30,20));
	camera->setTarget(irr::core::vector3df(-20,-30,-20));
MC - This is a major step, in case it's not obvious. Initialize Tokamak

Code: Select all

	InitPhysics();
MC - Here we set up our array of cubes then create them. Make sure you DO NOT drop() the cubes, since we need to use the pointer to refer back to the cubes to position them

Code: Select all

 PhysicsCubeNode *CubeNode[CUBECOUNT];
		
	for (i=0; i<CUBECOUNT;i++)
	{
		CubeNode[i] = new PhysicsCubeNode(smgr->getRootSceneNode(), smgr, 666);
	}
MC - I'm one of those programmers that will fit 2 or more commands on one line if I can. Plus, I think this is a really cute way of calling and dropping a node without using a variable. I use the magic of C++ to create a new Node and drop that same node in the same look. If I was doing this the long way I would need a PhysicsFloorNode pointer

Code: Select all

	(new PhysicsFloorNode(smgr->getRootSceneNode(), smgr, 666))->drop();
tok - Initialize the timer and the variable to count the last number of milliseconds. this makes sure there isn't a wierd jump in the program.

Code: Select all

	InitTimer();
	fLastElapsed = 0;
Now the fun begins.

Code: Select all

while(device->run())
	{
tok - Find out how much time has elapsed since we were last called

Code: Select all

	    fElapsed = GetElapsedTime();
tok - Prevent the elapsed time from being more than 20% greater or less than the previous elapsed time.

Code: Select all

		if (fLastElapsed != 0)
		{
	        if (fElapsed > fLastElapsed * 1.2f) fElapsed = fLastElapsed * 1.2f;
			if (fElapsed < fLastElapsed * 0.8f) fElapsed = fLastElapsed * 0.8f;
		}
		
		if (fElapsed > 1.0f / 45.0f) fElapsed = 1.0f / 45.0f;
		
	    fLastElapsed = fElapsed;

		gSim->Advance(fElapsed);
MC - here where the real magic happens. We loop through each cube;

Code: Select all

		for (i=0; i<CUBECOUNT; i++)
        {
First, we get the position from the Tokamak cube
We set up out temporary vector
And set the position of the cube that Irrlicht is going to draw

Code: Select all

 		neV3 p = gCubes[i]->GetPos();

			TempVect.X = p[0];
			TempVect.Y = p[1];
			TempVect.Z = p[2];

			CubeNode[i]->setPosition(TempVect);
Last, we get the rotation from the Tokamak cube. This is a the rotation quaternion, I believe More information is found here:
http://www.gamedev.net/reference/articl ... le1095.asp
(Thanks to unnamed forum user)

Again, the temporary vector is set
we convert it to degrees and set the Irrlicht cube's rotation

Code: Select all

			neQ q = gCubes[i]->GetRotationQ();

			TempVect.Y = q.Y;
			TempVect.X = q.X;
			TempVect.Z = q.Z;

			TempVect *= 180 / PI;
			CubeNode[i]->setRotation(TempVect);
		}
tok - When we're one, we kill the physics engine

Code: Select all

	KillPhysics();
MC - And drop all the node pointers that we don't need anymore

Code: Select all

	for (i=0; i<CUBECOUNT;i++)
		CubeNode[i]->drop();
And there you have it...download the source and play with it if you'd like. It's simply a .cpp file, so you can adapt it to whatever IDE you'd like
Cleves
Posts: 224
Joined: Mon Sep 08, 2003 6:40 pm

Post by Cleves »

Thanks alot enigmatic! :D
Gonosz

Post by Gonosz »

I don't think that the rotation information is stored directly in the (x,y,z) triple in a quaternion. To prove this, I copied the code below from a quaternion class. So if you have to give the Irrlicht engine the rotations by the axes X,Y,Z, you have to calculate these angles from the (x,y,z,w) values... there should be several ways to do this, like transforming the quat to a matrix and passing that to Irr, or converting it to an axis-angle pair, and transfroming an identity matrix with them. I haven't tried any of these, but I will have to, since the more complicated Tokamak stuff (like that falling RadDude :P) just don't seem to work correctly.

Code: Select all

        angle *= ( M_PI / 180.0 );

        // Normalize the axis.
        GLfloat factor = x * x + y * y + z * z;
        assert( factor != 0 );

        GLfloat scaleBy( 1.0 / sqrt( factor ) );
        x = x * scaleBy;
        y = y * scaleBy;
        z = z * scaleBy;

        // Build a quaternion!
        d_val[ 0 ] = cos( angle / 2.0 );

        GLfloat sinHalfAngle( sin( angle / 2.0 ) );
        d_val[ 1 ] = x * sinHalfAngle;
        d_val[ 2 ] = y * sinHalfAngle;
        d_val[ 3 ] = z * sinHalfAngle;
Gonosz
Gonosz
Posts: 24
Joined: Wed Oct 29, 2003 4:21 pm
Location: Hungary (one joke and you're dead)

Post by Gonosz »

I have solved the problem with the following code. If your class is a child of ISceneNode, you can access the transformation matrix easily (only be careful it's transposed)

Code: Select all

	neQ q = gCube->GetRotationQ();
	neM4 neMatrix = q.BuildMatrix();
	neMatrix.SetTranslation(gCube->GetPos());
	for (int x=0; x < 4; x++)
	{
		for (int y=0; y < 4; y++)
		{
			AbsoluteTransformation(y,x) = neMatrix.M[x][y];
		}
	}
http://www.extra.hu/i713/load/tokamak.jpg
To correct the tutorial, you have to put an 'Update(neRigidBody *gCube)' function into the PhysicsCubeNode class, and call that in the main() update cycle (from line 502)

Now the cubes will lie on the ground the way they always should've :) BTW I have copied the RadDude from Tokamak tut 9, and modified it to work with Irrlicht. If anyone is interested, I can post the source.

Gonosz
Last edited by Gonosz on Thu Oct 30, 2003 2:07 pm, edited 1 time in total.
Post Reply