"2d" movement based on camera rotation ( Math &

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
TekniX
Posts: 24
Joined: Tue May 01, 2007 12:39 pm

"2d" movement based on camera rotation ( Math &

Post by TekniX »

Hi guys,

I could use some help with this little issue here... The problem I'm facing is the following :

fake a 2d movement ( on the screen ) of a 3d node based on the cameras rotation. e.g. camera looks down e.g. vec3df(0,-1,0) I click on my node and translate it towards the top/bottom of the screen, I want the node to stay at the same distance from the camera than it had originally

this means, the nodes movement should be restricted to x and z axis, which in this case is really easy.. but I want to be able to do this for every camera rotation not just "orthogonal" views.. So I thought of the following...


1. get the vec3df position of the node ( thing thats going to be moved )

2. get a ray from the camera through the destination screen coordinate ( using getRayFromScreenCoordinates(destination position, camera)

3. now get the closest position to the node position on the ray with getClosestPoint(nodePosition)

The closest position SHOULD be a straight line from the original node position, so that the distance to the camera stays the same...
This method works ok for "orthogonal" views, but as soon as the camera has a little bit of rotation the node gets closer and closer ( with every movement ) or further away (depending on the camera rotation ) .. So this method is not really "good" .

What I am trying now is the following

1. get position of the node ( vec3df )

2. build plane plane3df iPlane(nodePos,camera->getTarget())

3. get ray through screen coordinates ray = getRayFromScreenCoordinates(mouseReleasePosition,camera)

4. iPlane.getIntersectionWithLimitedLine(ray.start,ray.end,iPoint)

5. iPoint should be the new position of the node...

When I move the node towards the center of the screen it goes further away, when I move the node towards the side of the screen it comes closer..

Actually the first method worked better and thats strange because, thinking in a math way the second method should be absolutely failsafe ;) ..... anything I did completely wrong ? Some better way I have just not "seen" ?

Thank you :)

Kind regards

TekniX
kazymjir
Posts: 727
Joined: Sat Feb 20, 2010 4:05 pm
Location: Munich, Bayern

Post by kazymjir »

I am not sure what do you want to achieve, so I made picture:

Image

So you want to have always constant distance between camera and node, when camera is going upward/downward ?
TekniX
Posts: 24
Joined: Tue May 01, 2007 12:39 pm

Hey

Post by TekniX »

Not really ;) I made some images as well now hehe
Image

on this image you see a camera an a small cube plus a highlighted plane, I want to move the cube on this plane .

Image

on this image you see through the camera, ( like the irrlicht window ) I want to click on the node, drag the mouse accross the screen ( complete image ) and then the node should stop when i let lmouse up, ( which is all ok ) the only problem is the math / logic behind the plane and the camera ray.... BTW: dont get irritated by the gizmo I dont want that, basically I want to fake a 2d movement based on screen coordinates and convert that into the 3d position..

The plane should face the camera an be bigger than the "view" so that I always get a collision between the getRayFromScreenCoordinates ray and the plane...

I hope this helps ;)

Thank you :) [/img]
kazymjir
Posts: 727
Joined: Sat Feb 20, 2010 4:05 pm
Location: Munich, Bayern

Post by kazymjir »

Hmmm, I think that I understand you.
So, you want to rotate camera with this plane, where the cube is in constant position. When you click on the cube, you want to change it position using this plane and it's X and Y axis?
Not XY axis relative to the world, but relative to the plane, yes?
stefbuet
Competition winner
Posts: 495
Joined: Sun Dec 09, 2007 4:13 pm
Location: france

Post by stefbuet »

You can't translate a node in a plane orthogonal to your view vector keeping the camera-node distance constant.
I guess a simple solution to achieve what you want to do is define 2 vectors defining your camera orthogonal plane basis, for exemple (0,1,0) and (1,0,0), then you can multiply those vectors by the camera transformation matrix to get transformed vectors. Then to move your object just add to the object position the 2D mouse position offset multiplyed by the transformed basis vectors.

Image
kazymjir
Posts: 727
Joined: Sat Feb 20, 2010 4:05 pm
Location: Munich, Bayern

Post by kazymjir »

So I am right, Stefbufet?
Teknix want to move node using plane axis (like in your picture, U and V), not global axis?

If yes, I can write mathematical solution, but I cannot give any source code, due to I almost forgot Irrlicht API by not using it for long time.

Steps:
1. Get vector of current position of your node, (name it "a")

2. Get rotation of a plane and create rotation matrix, (name it "A")

3. Create second rotation matrix based on matrix A, but with negative angles, name it "B" (for example, if X rotation axis of A matrix is 47 degree, for B matrix it will be -47 degree)

4. Create a translation vector, which points where you want to move your node (use only X and Y axis of a plane), name it T

4. Multiply: A * T * B * a . The result is a new position of your node.


Example (where n vector is a new position of your node):
current position of your node it's 3,2,0 (XYZ),
current rotation of plane is 45 degree on Z axis,
you want to move the node to +5X, + 4Y

Image

It would be nice if somebody verify my theory, due to I didn't use matrices for a long time.
Lonesome Ducky
Competition winner
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Post by Lonesome Ducky »

This can be most easily achieved by getting the direction between the top-most points on the camera's view frustum and the top and bottom points of one side.

Code: Select all

vector3df dirX = (camera->getViewFrustum()->getFarRightUp()-camera->getViewFrustum()->getFarLeftUp()).normalize();
vector3df dirY = (camera->getViewFrustum()->getFarRightDown()-camera->getViewFrustum()->getFarRightUp()).normalize();
This gives you the direction of the 2d movement on the plane.

A basic function to get the 3d position from a 2d point:

Code: Select all

vector3df get3DCameraPlanePos(ICameraSceneNode* camera, vector2df position, f32 centerDist) {
	vector3df center = camera->getAbsolutePosition()+camera->getAbsoluteTransformation().getRotationDegrees().rotationToDirection()*centerDist;
	vector3df dirX = (camera->getViewFrustum()->getFarRightUp()-camera->getViewFrustum()->getFarLeftUp()).normalize();
	vector3df dirY = (camera->getViewFrustum()->getFarRightDown()-camera->getViewFrustum()->getFarRightUp()).normalize();
	return center+dirX*position.X-dirY*position.Y;
}
position is offset from the center of the screen, and centerDist is how far away the plane is. Code is untested, but should work.

To do what you want, this may be better suited:

Code: Select all

vector3df get3DCameraPlanePos(ICameraSceneNode* camera, position2di position, dimension2di screenSize) {
	vector2df offPos((screenSize.Width-position.X)*2.0f-1.0f,-((screenSize.Height-position.Y)*2.0f-1.0f));
	vector3df center = camera->getAbsolutePosition()+camera->getAbsoluteTransformation().getRotationDegrees().rotationToDirection();
	vector3df dirX = (camera->getViewFrustum()->getFarRightUp()-camera->getViewFrustum()->getFarLeftUp()).normalize();
	vector3df dirY = (camera->getViewFrustum()->getFarRightDown()-camera->getViewFrustum()->getFarRightUp()).normalize();
	return center+dirX*offPos.X-dirY*offPos.Y;
}
Last edited by Lonesome Ducky on Thu May 12, 2011 12:35 am, edited 5 times in total.
stefbuet
Competition winner
Posts: 495
Joined: Sun Dec 09, 2007 4:13 pm
Location: france

Post by stefbuet »

This solution is nicer.
btw, my name has nothing to do with a buffet! Buet is a mountain!
kazymjir
Posts: 727
Joined: Sat Feb 20, 2010 4:05 pm
Location: Munich, Bayern

Post by kazymjir »

Oh sorry Stefbuet, I am on this forum for a very long time and just now noticed that your nick is Stefbuet, not Stefbufet :D
TekniX
Posts: 24
Joined: Tue May 01, 2007 12:39 pm

wow :)

Post by TekniX »

Wow, that was a lot of replies ;) . Thank you very much guys. I am going to try out the things you have mentioned here and give you feedback, maybe at the end of the day maybe tomorrow ! Great to have some people who know math :lol:
Thanks for now and cu later :)
TekniX
Posts: 24
Joined: Tue May 01, 2007 12:39 pm

Post by TekniX »

Ok guys, halftime report ;)

@Kazymjir : Ok, after I had all the stuff, A, B, T and a, I did not have any possibility of multiplicating it all together, nor in parts... the matrix * matrix worked, but matrix * vector .. compiler error stating that theres no operator supporting that :( . So not really helping me since I cant do it by "hand" ..

@Stefbuet : Somehow your solution sounded logical, but implementation failed with matrix * vector multiplication ... Maybe I'm doing something wrong here ? Im just taking my matrix4 and multiplying by vector3df ....

@LonesomeDucky : Yours was the most promising, but somehow the position it returns is way off .. and I mean way off... Look at this
X:100 Y:3 Z:100

(Dir X : 0 Y: 0 Z: 1) vector from camera view frustrum
( Dir Y : 0 Y: -1 Z: 0) vector from camera view frustrum
Then I move the mouse cursor like "two" pixels up and right... minimal movement.. and the node jumps here :
vector contains :
x : 259.375 y : -617 z : 892

What exactly does this line :

Code: Select all

core::vector3df center = camera->getAbsolutePosition()+camera->getAbsoluteTransformation().getRotationDegrees().rotationToDirection();
And should I not calculate the offPos from the previous click - current click ? Because as far as I understand it you calculate it from the screen size width ( so to say center of the screen )

Any more help would be appreciated.. but I do have a deficit in Maths.. So the basic questions right now are :

ISceneNode -> getRelativeTransformation() : Gives me what ? A matrix containing the position and rotation of the scene node...

Normalized vector of the camera view frustrum top right to top left as I get it from this : (camera->getViewFrustum()->getFarRightUp()-camera->getViewFrustum()->getFarLeftUp()).normalize(); . Multiplied by the Relative transformation matrix of the IScene node ? What would that give me ? And how do I do it ? Because multiplying matrix4 and vector3df doesnt work ..

Thanks for the first, and Ill keep trying to fix the get3dCameraPlanePos ;)

Regards,

TekniX

Ps: If you have a good tutorial on matrixes and stuff for 3d game programming ( all the other stuff is so little graphics... I cant imagine shi* when I read it ;) ) ill be happy to read through it!
kazymjir
Posts: 727
Joined: Sat Feb 20, 2010 4:05 pm
Location: Munich, Bayern

Post by kazymjir »

Vector is just matrix but with one column.
To multiply two matrices, number of columns of the first matrix must be the same like number of rows of the second matrix.
So, you have to use vector4df instead of vector3df.

It looks like this: vector4df(x,y,z,1)
TekniX
Posts: 24
Joined: Tue May 01, 2007 12:39 pm

Post by TekniX »

Hmm in that case I will have to use some different method becaus the irr:core:: namespace contains no vector4df ..
Lonesome Ducky
Competition winner
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Post by Lonesome Ducky »

I convert the position into the range of -1 to 1, because at a distance of one (which the centerDist is found to be 1 unit away from the camera, using its direction) the screen should have a max y of 1, and a min y of -1, etc. I'll have to try fixing it when I get back to my computer.
kazymjir
Posts: 727
Joined: Sat Feb 20, 2010 4:05 pm
Location: Munich, Bayern

Post by kazymjir »

Post Reply