Position relative to camera position [SOLVED]

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
pilesofspam
Posts: 62
Joined: Mon May 11, 2009 4:31 am

Position relative to camera position [SOLVED]

Post by pilesofspam »

I've got this space game I'm making, and so far everything is going well, except I'm trying to create some projectile-beams from the sides of the spaceship you're flying, shooting at the camera target. Eventually, I want to be able to shoot these at a target you click with your mouse/crosshair, but for now I'd be happy to initialize them at the sides of the ship and send them towards the camera target. I'm trying to take the camera rotation vector, normalize it, then swap x and z, making one (x or z) negative for the start positions of the beam on each side. This isn't working. First, the beam seems to move its origination point based on which way I turn the camera, and second, I stop getting beams at all when my camera moves away from the origin.

I'm posting the relevant code. Any ideas? Any help is greatly appreciated.

Code: Select all

   beam=smgr->getMesh("./models/Cylinder.irrmesh"); //Cylinder.irrmesh is the beam model
	u32 then = device->getTimer()->getTime(); //used for framedeltatime below
	u32 lastshot = then;
	vector3df dir;
	vector3df rot;
	vector3df pos;
	vector3df shift;
	beamcontrol = NULL;
	while(device->run())
	{
		//frame delta time, so we move the same distance with respect to time, not frames
		const u32 now = device->getTimer()->getTime();
		const f32 frameDeltaTime = (f32)(now - then) / 1000.f; // Time in seconds
		then = now;


		if ((receiver.IsKeyDown(irr::KEY_KEY_W)) && ((now - lastshot) > 200))
		{
		            lastshot = now;
			         // if the beam already exists then delete it
			         if (beamcontrol) {beamcontrol->drop(); beamcontrol = NULL; }
						printf("shot!");
                  pos = Camera->getPosition();
                  dir = Camera->getTarget() -Camera->getPosition();
						rot = Camera->getRotation();
						shift = rot.normalize();
						rot = Camera->getRotation();
						beamcontrol = smgr->addMeshSceneNode(beam,0, -1, 10000.0f*core::vector3df(shift.Z, 0.0f, -shift.X), rot,core::vector3df(500, 500, 1000));
                  beamcontrol->setMaterialFlag(EMF_LIGHTING,false);
		}


		else if(receiver.IsKeyDown(irr::KEY_KEY_Q))
		{
			device->drop();
            return 0;
		}
		driver->beginScene(true, true, SColor(255,100,101,140));

		if (beamcontrol)
		{
			beamcontrol->setPosition(beamcontrol->getPosition() + dir * speed * frameDeltaTime);
			//beamcontrolright->setPosition(beamcontrolright->getPosition() + dir * speed * frameDeltaTime);
		}
		smgr->drawAll();
		//guienv->drawAll();

		driver->endScene();
	}
Last edited by pilesofspam on Tue Apr 20, 2010 9:12 pm, edited 1 time in total.
randomMesh
Posts: 1186
Joined: Fri Dec 29, 2006 12:04 am

Re: Position relative to camera position

Post by randomMesh »

Did you set

Code: Select all

camera->bindTargetAndRotation(true);
?
I can't spot this line in your code. Otherwise you can't get the rotation via getRotation();
The FPS camera has this enabled by default.
"Whoops..."
pilesofspam
Posts: 62
Joined: Mon May 11, 2009 4:31 am

Post by pilesofspam »

No- but I'm using the fps camera. I plan to change it eventually and I'll remember that. Thanks!

I'm getting the correct rotation, as my projectile is oriented correctly on exit, but the origin of the projectile is wrong, and inconsistent (not between identical shots, but between different camera rotations).
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

The problem lies here...

Code: Select all

rot = Camera->getRotation(); 
shift = rot.normalize(); 
The camera rotation is not a vector in the normal sense. It is a series of three values, the rotations around the X, Y and Z axes.

Are the projectile-beam turrets supposed to be attached to the camera 'pod', or is the camera 'pod' supposed to rotate independently of the turrets? i.e., if the camera rotated 90° to the left, would the left turret be in front of the camera, or would it still be to the left of the camera?

If the turrets are attached to the camera, then you want something like this...

Code: Select all

core::vector3df Z = Camera->getTarget() - Camera->getAbsolutePostion();
Z.normalize();

core::vector3df Y = Camera->getUpVector();
Y.normalize();

core::vector3df X = Z.crossProduct(Y);

// i'm pretty sure this is right
core::vector3df turret_on_left = Camera->getAbsolutePosition() - (X * 1000.f);
If the turrets are not supposed to move when the camera rotates, then you don't need to take the camera rotation into account. You may need to take the ship rotation into account though.

This would all be simpler to think about if every turret was an empty scene node that was a child of the ship. If the turrets were all at the correct positions, then you just need to start your projectile at the absolute position of the turret and fire it toward the camera target.

If you want to do it the hard way, you have to write something like this...

Code: Select all

// if the camera is on the port (left) side of the ship, this is the position of 
// the turret to the left of the camera
core::vector3df Z(0.f, 0.f, 1.f);
Ship->rotateVect(Z); // forward in ship coordinate space

core::vector3df turret_on_left = Camera->getAbsolutePosition() - (Z * 1000.f);
Travis
blAaarg
Posts: 94
Joined: Tue Mar 02, 2010 9:11 pm
Location: SoCal

Post by blAaarg »

Hi, Piles...:) I typed this all out and vitek beat me to it. D'oh!:x Anyway, here's another way of doing vitek's first solution, if it's not TMI:

Normalizing a rotation vector and then setting it as a position vector seems to me would cause strange effects because normalizing is for changing the length of a position or--more commonly--a direction to equal 1. A rotation vector (like that returned by getRotation() ) stores degrees of spin around x,y,z axes not coordinates.

For addMeshSceneNode() try setting the camera (or spaceship) as the parent (2nd parameter) and for the position vector (4th parameter) supply the offset to the right and back that you want the beam to originate from, and don't change it based on any rotations. Rotating the camera should keep the origin of the laserbeams in the same place relative to the camera, so they move and rotate with it.

Setting the rotation of the beamcontrol would then depend upon how it's modelled. If it's modelled down its own local z-axis then you would set the 5th parameter to (0,0,0)...if down the x-axis then probably rotate to (0,90,0) etc. Like the origin of the laserbeams, this value would be independent of the camera's rotation. And, I'm assuming you set bindTargetAndRotation() like randomMesh said.

This will shoot the laserbeams straight forward (hopefully) relative to where the camera is pointing, and should work regardless of how the camera moves or rotates. But, if you want them to cross at a point in front of the camera there's a little bit more you'd have to do to rotate them. That's just a few more lines of code, though, so hopefully this helps in the right direction.
"Computers don't make mistakes! What they do they do on purpose!!"

-Dale Gribble
pilesofspam
Posts: 62
Joined: Mon May 11, 2009 4:31 am

Post by pilesofspam »

Thanks guys! Vitek, that got me thinking- you're right, a rotation vector isn't going to give me a proper direction when normalized, but the camera DIRECTION should. Then I can pick a spot where the dot product is 0- a translation directly right or left of the camera direction- and use this (it works!).

Code: Select all

     pos = Camera->getPosition();
     dir = Camera->getTarget() - Camera->getPosition();
     rot = Camera->getRotation();
     shift = dir.normalize();

     beamcontrolleft = smgr->addMeshSceneNode(beam,0, -1, core::vector3df(pos.X + 10000.0f*shift.Z, pos.Y+0.0f, pos.Z-10000.0f*shift.X), rot,core::vector3df(1000, 1000, 1000));
     beamcontrolright = smgr->addMeshSceneNode(beam,0, -1, core::vector3df(pos.X - 10000.0f*shift.Z, pos.Y+0.0f, pos.Z+10000.0f*shift.X), rot,core::vector3df(1000, 1000, 1000));

     beamcontrolleft->setMaterialFlag(EMF_LIGHTING,false);
     beamcontrolright->setMaterialFlag(EMF_LIGHTING,false);
Note the only real change is in shift- which is now the normalized camera direction vector not the rotation vector

This gives me two beams, one originating on each side of the camera with respect to the camera's target, pointed towards the camera target. I then move the beams at some factor speed in the direction of their original rotation.

Thank you very much folks, I've learned a lot here.[/i]
pilesofspam
Posts: 62
Joined: Mon May 11, 2009 4:31 am

Post by pilesofspam »

Sorry to post again and bump this already solved issue- BUT if anybody looks to this as an example, be aware of the following in the first post of the thread:

This line:

Code: Select all

if (beamcontrol) {beamcontrol->drop(); beamcontrol = NULL; }
causes a segfault sometimes after compiling under linux gcc. gdb reports SIGSEGV, or invalid memory which (oversimplified) means you messed up a pointer. After a few tries and backtraces it pointed me towards the above code. It should instead read (for proper operation)

Code: Select all

if (beamcontrol) {beamcontrol->drop(); beamcontrol = 0; }
And if you prefer you can set a separate bool somewhere to do the same job and leave your pointer alone.
slavik262
Posts: 753
Joined: Sun Nov 22, 2009 9:25 pm
Location: Wisconsin, USA

Post by slavik262 »

pilesofspam wrote: This line:

Code: Select all

if (beamcontrol) {beamcontrol->drop(); beamcontrol = NULL; }
causes a segfault sometimes after compiling under linux gcc. gdb reports SIGSEGV, or invalid memory which (oversimplified) means you messed up a pointer. After a few tries and backtraces it pointed me towards the above code. It should instead read (for proper operation)

Code: Select all

if (beamcontrol) {beamcontrol->drop(); beamcontrol = 0; }
:shock:
You do know that NULL is defined to 0 or a flavor thereof such as ((void*)0), right? There is no difference between the line and your "fix."
pilesofspam
Posts: 62
Joined: Mon May 11, 2009 4:31 am

Post by pilesofspam »

I always thought so. You are correct, pardon my error. I came back to fix this only to find it already discovered. In order to avoid threadjacking, I'll start a new one after experimenting. Turns out my segfault is due to beamcontrol->drop(); and gets picked up at smgr->drawALL();
Post Reply