Problems with Rotation

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.
Post Reply
D.Cent
Posts: 18
Joined: Sun May 13, 2007 8:12 pm
Location: Schwieberdingen (Germany)
Contact:

Problems with Rotation

Post by D.Cent »

Hi all,

I wrote a program that displays a level in a special format. The loader I wrote for Irrlicht works correctly.

When I started developing the Loader, I could only slide with my camera (left, right, up, down, forward, back). But now I also want to implement turning.

This is what I wrote (some of the code was copied from this tutorial: http://irrlicht.sourceforge.net/phpBB2/ ... a+rotation ):

Code: Select all

	// In order to do framerate independent movement, we have to know
	// how long it was since the last frame
	u32 then = device->getTimer()->getTime();

	// This is the movemen speed in units per second.
	const f32 MOVEMENT_SPEED = 5.f;

	camera->bindTargetAndRotation(true);

	while(device->run())
	{
		// Work out a frame delta time.
		const u32 now = device->getTimer()->getTime();
		const f32 frameDeltaTime = (f32)(now - then) / 1000.f; // Time in seconds
		then = now;

		core::vector3df nodePosition = node->getPosition();
		core::vector3df nodeRotation = node->getRotation();

                //keys W,A,S,D,I,O for sliding
		if(receiver.IsKeyDown(irr::KEY_KEY_S))
			nodePosition.Y += MOVEMENT_SPEED * frameDeltaTime;
		else if(receiver.IsKeyDown(irr::KEY_KEY_W))
			nodePosition.Y -= MOVEMENT_SPEED * frameDeltaTime;

		if(receiver.IsKeyDown(irr::KEY_KEY_A))
			nodePosition.X -= MOVEMENT_SPEED * frameDeltaTime;
		else if(receiver.IsKeyDown(irr::KEY_KEY_D))
			nodePosition.X += MOVEMENT_SPEED * frameDeltaTime;

                if(receiver.IsKeyDown(irr::KEY_KEY_O))
                        nodePosition.Z -= MOVEMENT_SPEED * frameDeltaTime;
                else if(receiver.IsKeyDown(irr::KEY_KEY_I))
                        nodePosition.Z += MOVEMENT_SPEED * frameDeltaTime;

		float diry = ((nodeRotation.Y+90)*3.14)/180; 

                //arrow keys for rotation
                if(receiver.IsKeyDown(irr::KEY_DOWN)) {
			nodePosition.X += MOVEMENT_SPEED * cos((nodeRotation.Y) * 3.14 / 180);
			nodePosition.Z -= MOVEMENT_SPEED * sin((nodeRotation.Y) * 3.14 / 180); 
		}
                else if(receiver.IsKeyDown(irr::KEY_UP)) {
			nodePosition.X -= MOVEMENT_SPEED * cos((nodeRotation.Y) * 3.14 / 180);
			nodePosition.Z += MOVEMENT_SPEED * sin((nodeRotation.Y) * 3.14 / 180); 
		}
                if(receiver.IsKeyDown(irr::KEY_LEFT)) {
			nodeRotation.Y -= 0.1; 
		}
                else if(receiver.IsKeyDown(irr::KEY_RIGHT)) {
			nodeRotation.Y += 0.1;
		}

		if(receiver.IsKeyDown(irr::KEY_ESCAPE))
		 break;

		node->setRotation(nodeRotation);
		int xf = (nodePosition.X-sin(diry)*125);
		int yf = (nodePosition.Z-cos(diry)*125);
		int zf = 0;

		node->setPosition(nodePosition);

		camera->setTarget(nodePosition);

		nodePosition.Y +=200.f;
		nodePosition.Z -= 150.f;

		camera->setPosition(vector3df(xf,zf,yf)); 

		driver->beginScene(true, true, video::SColor(255,113,113,133));

		smgr->drawAll(); // draw the 3d scene
		device->getGUIEnvironment()->drawAll(); // draw the gui environment (the logo)

		driver->endScene();

		int fps = driver->getFPS();

		if (lastFPS != fps)
		{
			core::stringw tmp(L"Movement Example - Irrlicht Engine [");
			tmp += driver->getName();
			tmp += L"] fps: ";
			tmp += fps;

			device->setWindowCaption(tmp.c_str());
			lastFPS = fps;
		}
	}
But the result is not good at all. When I try to turn, the camera only "jerks" when I try to move to any direction.

What's wrong here?
vipergc
Posts: 27
Joined: Mon Mar 02, 2009 3:33 am
Location: Louisville, KY
Contact:

Post by vipergc »

One thing that jumps out at me is the following..

nodePosition.X += MOVEMENT_SPEED * cos((nodeRotation.Y) * 3.14 / 180);

nodeRotation.Y is in degrees and you are sending that to the cos function and converting the result to radians... you need to do the conversion BEFORE sending it to the cos function as the cos function operates on radian values

nodePosition.X += MOVEMENT_SPEED * cos(nodeRotation.Y * 3.14 / 180);

I would also recommend using a predefined constant for the DEG2RAD conversion and add a bit more accuracy than 3.14

such as

#define SYSPI 3.1415926535897932384626433832795L

or you can calculate it on the fly as SYSPI = 4.0f * atn(1.0) to device accuracy. depending upon the math package accuracy this may not always be the best route to go... its safer to just use a constant as below.
trig functions are typically calculated using Taylor series expansions of varying depth.

// Degrees to radians (pi/180.0)
#define DEG2RAD 0.0174532925199432957


your simple 3.14/180 will evaluate to 0.017444444 in the best of circumstances and this can make quite a difference
Co-Inventor of ZIP files.

Hardware - play with it long enough.. it BREAKS
Software - play with it long enough.. it WORKS
D.Cent
Posts: 18
Joined: Sun May 13, 2007 8:12 pm
Location: Schwieberdingen (Germany)
Contact:

Post by D.Cent »

Thanks for your answer!

I replaced the 3.14 with the define you gave me and I also applied your idea for the cos() / sin() functions, but again the same thing happens - nothing has changed :(
vipergc
Posts: 27
Joined: Mon Mar 02, 2009 3:33 am
Location: Louisville, KY
Contact:

Post by vipergc »

No problem...

also note that setRotation() is a RELATIVE rotation.. from the current position... not absolute, therefore, you will have to track the position yourself and then call setRotation() to move a relative rotational distance from the current position
Co-Inventor of ZIP files.

Hardware - play with it long enough.. it BREAKS
Software - play with it long enough.. it WORKS
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

vipergc wrote:also note that setRotation() is a RELATIVE rotation.. from the current position... not absolute, therefore, you will have to track the position yourself and then call setRotation() to move a relative rotational distance from the current position
Uhm, no. It is indeed a relative rotation, but only relative to its parent. If you call setRotation(0,1,0) many times the rotation will be (0,1,0) always.
vipergc
Posts: 27
Joined: Mon Mar 02, 2009 3:33 am
Location: Louisville, KY
Contact:

Post by vipergc »

Good point.. I stand corrected... the main thing here is that its relative... and he was trying to use it as an absolute
Co-Inventor of ZIP files.

Hardware - play with it long enough.. it BREAKS
Software - play with it long enough.. it WORKS
D.Cent
Posts: 18
Joined: Sun May 13, 2007 8:12 pm
Location: Schwieberdingen (Germany)
Contact:

Post by D.Cent »

Ok, I fixed my problem now (I rewrote my whole code).

I simply set the rotation like that:

Code: Select all

core::vector3df nodeRotation(camera->getRotation);
...
// if left key pressed
{
        nodeRotation.Y -= 1;
        camera->setRotation(nodeRotation);
}
I had to activate the "bindTargetAndRotation"-function.

Now I've got the problem that everytime I rotate about 90 degrees (to the left or right) the whole level disappears! When I continue hitting the key and rotate another 180 degrees, the level appears again.

What's wrong?
D.Cent
Posts: 18
Joined: Sun May 13, 2007 8:12 pm
Location: Schwieberdingen (Germany)
Contact:

Post by D.Cent »

I solved the problem with calling node->setAutomaticCulling(EAC_OFF).

But does it have any disadvantages to deactivate it?
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Yes, you lose the automatic culling, so the node will be rendered even if not in sight. Sounds like a bbox problem. Or do you encounter gimbal lock with the view switching from top to bottom immediately?
D.Cent
Posts: 18
Joined: Sun May 13, 2007 8:12 pm
Location: Schwieberdingen (Germany)
Contact:

Post by D.Cent »

Well, I can not turn more than 90 degrees to the bottom or to the top. If I am looking straight to the bottom/top and continue pressing the key, then the camera stops rotating while making some strange moves (the screen begins jerking).

I do not use any bbox at all.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

The automatic culling uses bbox, so it's necessary to have a properly defined bbox. Sounds like gimbal lock or wrong up vector, though.
D.Cent
Posts: 18
Joined: Sun May 13, 2007 8:12 pm
Location: Schwieberdingen (Germany)
Contact:

Post by D.Cent »

Ok, I did it like this:

Code: Select all

	core::aabbox3d<f32> Box; // our bounding box for culling (portal rendering)
	
	for(u32 i=1; i<odfllevelmesh->getMeshBufferCount()-1; ++i)
	{
		IMeshBuffer* tmp_mesh = odfllevelmesh->getMeshBuffer(i);
				
		for(u32 count=1; count<tmp_mesh->getVertexCount(); ++count)
		{
			video::S3DVertex *vertices=(video::S3DVertex*)tmp_mesh->getVertices();
			Box.addInternalPoint(vertices[count].Pos);
		}
	}
	
	odfllevelmesh->setBoundingBox(Box);
But still I don't see any changes. I tried to do it similar to the 3rd irrlicht example.
Post Reply