2D mouse (rotation in 3D world)

Started by
42 comments, last by lightxbulb 10 years, 4 months ago

Hello,

I have a Point on a euclidean plane (x, y) that represents a position of my cursor on the window of my application.

Now lets say in my application I have a cube in a 3D space (x, y, z), I want to rotate the cube on the Y axis so that always faces the

in the relative direction of my cursor on the window.

--------------------------------------------------------------------

for example

(given the origin of this plane is the center of my app's window) If my cursor is on the positive Y axis of the window then the cube will be rotated to face north. If my cursor is (-x, +y) then the cube will face northwest.

What im am having problems with or failing to see the correlation of is if I have a point on a 2d plane how do I transcripe it to a Y-Axis rotation in a 3D space

GetCursorPos(&cursorPos);

cube.rotate(cursorPos.y, 0.0f, 1.0f, 0.0f); // Maybe? cube.rotate(cursorPos.x + cursorPos.y, 0.0f, 1.0f, 0.0f);

Above is the method I have been trying and if you guessed thats totally off par or wrong you would be correct.

At least from a result stand point

----------------------------------------------------------------------

Should I just take a closer look into the euclidean coordinate system or is there some mathematically formula to all this and if so PLEASE point me into the direction of said formula!

Any response or tip will be greatly appreciated

-Marcus

Advertisement

I'm not sure about the solution. But I think you should transform the mouse position into world-space. By using D3DXVec3Unproject. Maybe 2 times. (x,y,0) and (camera pos) or (x,y,1) . I think this is a starting point! After you have the right vector, you can set your cube to rotate so it face the vector (or have the same normal)

Hi!

First of all, let me say I didn't quite get what you were trying to achieve, and I believe most people won't. How does a cube "face" "north" or "northwest"? There are six different faces that can face the "given direction". So for now let's assume that you have an object that can actually "face" some direction in a single way(for example a vector). Now I am not really sure what you meat by "north" etc. when it comes to 3d space. "North", "west", "east" and "south" are used for 2d maps as far as I know, in 3d space you can have an infinite number of 2d planes, even assuming you consider only the three main planes you'll have XY, XZ, YZ. I'll assume you meant the the XZ plane as you said you wanted to rotate the cube around (it's?) Y axis. But to rotate an object only around axis, you really need either only the X or Y movement of the mouse. I'll assume however that you want both of them somehow to portray the directional vector for the object.

So if I got you right (which I am not really sure about), you want the directional vector for the cube/object("where it's facing to) to be defined from the vector from the center of the screen to your mouse coords(considering in the center of the screen the mouse coords is the pair 0,0). What I'd do in this situation is to first get my mouse pair coords (Mx, My) and then actually map it to the XZ plane(you want to rotate the cube around Y right?), so I'd get something like this for the directional vector(let's call it v2) for the object:

(Mx, 0, My) - basically the x direction will be defined by how you move your mouse from left to right and the z direction by how you move your mouse forward/backward. And I believe you should get the "mouse on positive Y axis = north" etc. behaviour you're looking for. You should of course consider the scenario when you have a directional vector pair equal to the zero vector: Mx=My=0 => (0,0,0), then you can use some default direction for the cube.

Now, I do not know whether you have some function to align an object to a vector, but you can always calculate the needed rotation. If you have a default directional vector for the cube v1 and you have the new one v2, then you can calculate the angle of rotation around the Y axis in numerous ways, you can find the angle from the dotproduct of v1 and v2 and then define in which direction it's being rotated by looking at the vector product's direction. You can also write the coordinates of the new directional vector in polar form and then define the angle of rotation from there(you'll only need the angle for rotation around Y) etc.

Hope that helps.

P.S.

I'd advise the polar coordinate conversion, I believe it will be the easiest.

http://en.wikipedia.org/wiki/Polar_coordinate_system#Converting_between_polar_and_Cartesian_coordinates

http://en.wikipedia.org/wiki/Dot_product

http://en.wikipedia.org/wiki/Vector_product

Decided I won't be stingy and give the full example, after reading your post again and seeing you wanted the "formula":

If the x,y coords of your mouse in the center of the screen are not 0 you'll need to map them there.

Assuming the center of your screen has screen coords x0,y0 then to get the new coords of the mouse relative to a center scree 0,0 you'll do this:

1) Current mouse coords relative to some screen coord system not starting at the center of the screen - (mx0,my0)

2) Converting them to new coords mx,my relative to the new screen coord system (mx = mx0-x0, my= my0-y0) (you may have to do other transformation if the coord system is not witht the same handedness, however I believe that if you're using directX the screen coords start at the left top corner of the screen, so you'll need to have x0= screenWidth/2, y0= screenHeight/2).

3) Here' what you'll have for the directional vector: v2 = (mx, 0, my)

4) To find the angle based on the coordinates: YRotationAngle = atan2(my,mx).

5) Just rotate the cube by YRotationAngle on the Y axis.

Hello LightXBulb,

Sorry my fault for failing to elaborate. This is indeed a 3D world. However all the math of the transformations and rotations deal exclusively with X, Z coordinates.

So afaik that makes the math pretty much analogous to that of a 2D world. Given my odd terminology of "north", "East", "west", "south". But you already came to that conclusion.

Thanks for the informative reply. And sorry for not being a bit more clear as to what I meant. And thanks for the formula ;)

-Marcus

No need to be sorry really, in the end my conjectures based on your explanation seem to actually have been right, so I guess you explained it well enough smile.png , it's just I'm used to solving really well defined problems, and kinda have an issue with "not so well defined ones" as I don't like to assume things (my whole solution may prove to be for another problem). I didn't really elaborate on my answer much, because I didn't know whether my assumptions were right, so if something is not clear enough in my post, feel free to ask me to elaborate on it. For example if you don't have an atan2 function, there are a few workarounds you can do etc. It'd be nice to post a reply to say if you managed to make it work happy.png

P.S. What are you working on actually?(if it's not a secret, otherwise please ignore this question)

Wow, thanks!

The results from the formula are actually a vast improvement. Not saying I didn't think they would be!

The formula you gave was actually pretty straight forward even for a layman like myself to follow.

Oh and apparently intellisense told me I did have atan2 function biggrin.png (What does that do again?)

Oh, and it's just another tech demo that MIGHT go somewhere. I have a bad habit of not finishing my programs. I'd post a screenshot (but honestly Im not sure how to go about doing that with this forum layout tongue.png)

 
    float x0 = 0.0f;
    float y0 = 0.0f;

    x0 = 850.0f / 2; //Hardcoded the width and height for the sake of speed
    y0 = 650.0f / 2;

    float mx = x - x0;
    float my = y - y0;

    float YRotationAngle = atan2(my, mx);
 

This may be a bit off of the formula you provided but it works a LOT better then What I was using!

Btw "calling" it formula is not really correct, it would be more correct to say algorithm (though it's not even that good).

atan2 function biggrin.png (What does that do again?)

Well the problem is that arctanx, returns usually x only for -pi/2 < x < pi/2 (pi/2=90 degrees) - in order for the function to be injective. That means you'll have only 180 degrees for rotation, but you need 360. Basically you need, by having the x,y pair of you mouse, to be able to determine an angle of rotation between 0 and 2pi (it would've been easier if you had a function align_model_to_vector or something like this) and you cannot really get the full picture with only tan. Usually in such cases you'd check the values of the sin and cos and their signs. For example, if I have a vector defined as (sqrt(2),-sqrt(2)) then I'll get cos(alpha) = x/r = sqrt(2)/2 -> now that means alpha is either 45 degrees or -45 degrees( cos(pi/4) = cos(-pi/4) ), to determine which of the 2 angles it is, we check sin(alpha) = y/r = -sqrt(2)/2 -> now that means alpha is either -45 or -135 degrees, and from these two cases(cos and sin) we see that alpha=-45. What atan2 does, is to help you skip these few steps - basically it should give you an angle between -180 and 180 degrees, which happens to be the behaviour that we desire.

The problem could have been solved with one dot product and one vector product too. As you would've found out the angle between the directional vector for your object by default, and the vector defined by your mouse. And then you'd go on to define the sign of the rotation through the vector product. There could be other methods too, but i really don't think we need more tongue.png .

If you want to be able to solve such problems easily, you can check some books on http://en.wikipedia.org/wiki/Analytic_geometry, it's one of the most useful and practical math studies especially when it comes to game programming/2d/3d/physics etc. I believe it's studied in first year in colleges with math/computer sciences.


I'd post a screenshot (but honestly Im not sure how to go about doing that with this forum layout )

There's a small image icon kinda under the emoticon icon, you just need to provide a link for the img.

This may be a bit off of the formula you provided but it works a LOT better then What I was using!

Nah, I don't think "it's off". I believe the center of your screen coords starts at the left top corner of your screen seeing this code?

And why do you have 850 for width and 650 for height? I don't remember seeing a 850x650 screen resolution...huh.png

You say it works a lot better, but that means it doesn't work perfectly? So the question is, what is there to be desired more(examples?)?

I may be talking nonsense, but maybe you'll get a smoother reaction/rotation if you normalize the vector - basically:

r = sqrt(mx*mx+my*my);

mx =mx/r

my = my/r

Also for even smoother rotations and maybe even some rotation lag/inertia you can try some http://en.wikipedia.org/wiki/Slerp, but that's really for some fancy effects like the cube rotation lagging behind your mouse movement etc. Though for inertia you could really do it with only the mouse movement( taking the mouse postion a few frames back, building up greater rotations the more "speed" your mouse has, or rather the longer it moves in the same general direction), but that's just me getting too much into things and inventing new ways to torture yourself with biggrin.png , sorry about that.

9iid.png

I managed to make that a bit more difficult then I should have.

Anyways my goal is to have the torso of the players character and his head face the position of the muse cursor and also shoot in the direction

r = sqrt(mx*mx+my*my);

Thats the vector magnitude formula: sqrt(x2 + y2 + z2) Assuming of course its a 3D vector.

So by normalizing mx and my by r. r is the magnitude of mx and my, that could yield smoother rotation. Ill give it a shot

-Marcus

Anyways my goal is to have the torso of the players character and his head face the position of the muse cursor and also shoot in the direction

Is it working as intended with the current code?

So by normalizing mx and my by r. r is the magnitude of mx and my, that could yield smoother rotation. Ill give it a shot

I don't believe it will be really noticeable/much difference on a second thought, as atan2 takes y/x, so it's pretty much the same: (y/k)/(x/k) = y/x, though maybe the precision will change a little, but mostly I believe I was talking nonsense now that I think about it tongue.png . On the other hand, working with a normalized vector is better in many ways. For example, about your player shooting - you can decide the speed of your projectiles to be s and then translate the projectiles each second by the directional vector (mx*s, 0, my*s) - if it's normalized, then the projectiles will move at exactly s meter per second each second as s*|v| = s*1 = s

This topic is closed to new replies.

Advertisement