Sign in to follow this  
Dhaos

[UNRESOLVED] Predicting a 3D Point given a rotation

Recommended Posts

I wish to mimic the actions of 3d modeling suites which allow you to move a vertice to your mouse cursor no matter the world or camera rotation. How is such a thing compensated for? Here is my sample code attempted to shoot a ray from the mouse position into the world, compensating for world rotation. It does not work. I have checked and tried numerous methods, all of which are failing. Can anyone please point me the right direction? I have been working, researching, and studying this for over ~20 hours now. I am fried. I know I am missing some fundamental concept, its usually the bane of anything I try to do. Also I AM NOT trying to pick an object or a triangle. I want to determine world coordinates based on where I click. I visualize rotating the xyz axis, drawing a line from the cursor and trying to "hit" the axis and returning that X or Y or Z point, not necessarily all 3. cursor code
	cursor_x_3d =  ((cursor_x_2d - 256.0f) / 383.5f) - 1.0f;
	cursor_y_3d = -((cursor_y_2d -   0.0f) / 383.5f) + 1.0f;

	D3DXMATRIX mry;	//matrix rotation y
	//new stuff
	D3DXVECTOR3 vpo;//vector plane origin
	D3DXVECTOR3 vpn;//vector plane normal
	D3DXVECTOR3 vro;//vector ray origin
	D3DXVECTOR3 vrd;//vector ray direction
	D3DXVECTOR3 vpi;//vector plane intercept point
	
	vpo.x = 0.0f;
	vpo.y = 0.0f;
	vpo.z = 0.0f;

	vpn.x = 0.0f;
	vpn.y = 0.0f;
	vpn.z = -1.0f;

	vro.x = cursor_x_3d;
	vro.y = cursor_y_3d;
	vro.z = 0.0f;

	D3DXMatrixRotationY(&mry,D3DXToRadian(object_rotation_y));
	D3DXVec3TransformCoord(&vro,&vro,&mry);

	vrd.x = cursor_x_3d;
	vrd.y = cursor_y_3d;
	vrd.z = 1.0f;

	D3DXMatrixRotationY(&mry,D3DXToRadian(object_rotation_y));
	D3DXVec3TransformCoord(&vrd,&vrd,&mry);

	D3DXPLANE plane;
	D3DXPlaneFromPointNormal(&plane,&vpo,&vpn);
	D3DXPlaneIntersectLine(&vpi,&plane,&vro,&vrd);

viewport code
	dx_viewport_workspace.X		= 256;
	dx_viewport_workspace.Y		= 0;
	dx_viewport_workspace.Width	= 768;
	dx_viewport_workspace.Height	= 768;
	dx_viewport_workspace.MinZ	= 0.0f;
	dx_viewport_workspace.MaxZ	= 1.0f;

[Edited by - Dhaos on November 10, 2008 12:59:30 PM]

Share this post


Link to post
Share on other sites
Three things to consider:

1. FPU precision - device creation tends to override the FPU precision for performance. Look into setting D3DCREATE_FPU_PRESERVE and see if it makes any difference.

2. Window rect - A classic mistake is to forget to translate mouse coordinates from window to client coordinates. This way you get an offset due to the title bar/border of the window, but this tends to be more constant rather than changing depending on another variable.

3. Stale variables - Again, another classic mistake is to do the projection/intersection test before the matrices are updated for the next rendering. Thus you're actually intersecting against the previous frame's image/data! Check you're using the latest-n-greatest data for your calculations.

Otherwise, without stepping deep into the code and examining it I don't know!

hth
Jack

Share this post


Link to post
Share on other sites
Thank you for taking time to reply. I checked through each point you brought up to see if anything could be done.

@1)Using D3DCREATE_FPU_PRESERVE had no effect, which would probably rule out a float precision issue.
@2)I made sure to create the window borderless so its basically an empty full screen panel that directx renders to. Extracting the x/y coordinates during WM_MOUSEMOVE show exactly 0-1023x and 0-767y. So that seems to be ruled out as well.
@3)Awhile back I disregarded getting information from the world view and projection matrix due to that very problem. My tests ONLY use D3DXMatrixRotationY & D3DXVec3TransformCoord with freshly created local variables. So using old data is also impossible.

[Edited by - Dhaos on November 10, 2008 1:16:44 PM]

Share this post


Link to post
Share on other sites
Look at picking. It's really the same, with the only difference being that instead of intersecting your ray with a triangle, you have to check it's in the vicinity of a vertex.

Share this post


Link to post
Share on other sites
Either I am misunderstanding how this is accomplished, or nobody knows what I'm asking. So I uploaded some pictures of my application to explain.

http://www.crystaltechstudios.com/temp/program0.gif
http://www.crystaltechstudios.com/temp/program1.gif
http://www.crystaltechstudios.com/temp/program2.gif
http://www.crystaltechstudios.com/temp/program3.gif

The red dot is where I clicked, the vertice I was attempting to move should be pretty obvious. I want the vertice to appear where my cursor is NO MATTER THE ROTATION. I have no idea how to compensate for this. I tried using offsets, tried using line-plane intersect, nothing gives me the results I want. So I am probably misunderstanding something fundamental. EVERY single picking tutorial I have found (some 15 or so of them) does *not* deal with this problem.
All picking tutorials teach is you is to rotate your cursor towards the origin by your world/view/projection matrix and see if it hits an object, nothing else.
I don't WANT that. I want to know how to change a vertice's coordinates to my cursor click VISUALLY no matter what rotations are going on.

Share this post


Link to post
Share on other sites
Quote:

I don't WANT that. I want to know how to change a vertice's coordinates to my cursor click VISUALLY no matter what rotations are going on.


If i understand right you have:

- 3d objects in world coordinates,
- you want to select one vertice using the mouse.
- you have the selected vertice in world coordinate, so you already have the initial x,y,z position of selected vertice.
- Now you want to move that vertice to a new x,y,z position in world coordinates using the mouse...and for doing that you want to convert your mouse 2d screen coordinate into equivalent 3d world coordinate...and that is where your are wrong about your aproach...you cant do that.

You see, you can take any 3d coordinate and calc the equivalent 2d screen coordinate, several 3d coordinates can result in the same 2d coordinate when converted, (that is why there is a thing called Zbuffer which tells what 3d coordinate will actually paint the pixel in the screen); however you CAN NOT take any 2d screen coordinate and calc the equivalent 3d coordinate, becouse you dont know how depth into the screen you are "meaning" with your mouse...well except when you are asuming how depth into the screen your are.

Most 3d modelling programs works using the tipical 4 windows view for modeling:

- FRONT. How the objects looks when seen the front, the mouse is used for update the X,Y coordinate of any selected vertice, the Z cordinate remain unchanged when the user works in that view.

- TOP. How the object looks when seen from above (top down view), the mouse is used for update the X,Z coordinate of any selected vertice, the Y coordinate remain unchanged when the user works in that view.

- LEFT. How the object looks when seen the left, the mouse is used for update the Y,Z coordinate of any selected vertice, the X coordinate remain unchanged when the user works in that view.

- Perspective. Actual 3d view of the objects in perspective, some programs use this view just for show how the objects looks, but not for updating vertices; however some programs allow to updated vertices in perspective using a switch, when selected mouse update x,y, another switch meanmouse update yz and so on.

good luck.



Share this post


Link to post
Share on other sites
Do you mean move the vertex using a widget like in 3ds max? if so i can help because i have implemented this.

so basically you have 3 axes, which appear at the vertex which you can click and drag to move it on the x, y or z axis and possibly combinations of these?

you don't have to actually use a widget but the methods the same and the widget makes it easier to understand. but if you use trigonometry based on your camera rotations you can move the vertex on all 3 axes when you click and drag and it will appear to follow the cursor.

If this is what you looking for i can give you math or help you understand it :) hope this helps...


Share this post


Link to post
Share on other sites
YAY people who know what I am looking for!

@tpascal: So how do I approach it then? I do only wish to move one axis at a time. Do I need to collect what a given coordinate is within the zbuffer? And if that is the case how do I determine such a value? Also 3dsmax allows you to work in perspective view as well as most other applications. They just don't allow xyz to be modified simultaneously. I just want to predict a single x y OR z, not all 3.

@BlackSeeds: I believe that is what I am looking for. Moving a vertice along a *single* axis. Please do elaborate on the math and concept behind this, this might be what I have been searching for.

Both of you, thank you for replying, I'm excited that I might know how this works soon.

Share this post


Link to post
Share on other sites
Quote:
Original post by Dhaos
YAY people who know what I am looking for!

@tpascal: So how do I approach it then? I do only wish to move one axis at a time. Do I need to collect what a given coordinate is within the zbuffer? And if that is the case how do I determine such a value? Also 3dsmax allows you to work in perspective view as well as most other applications. They just don't allow xyz to be modified simultaneously. I just want to predict a single x y OR z, not all 3.

@BlackSeeds: I believe that is what I am looking for. Moving a vertice along a *single* axis. Please do elaborate on the math and concept behind this, this might be what I have been searching for.

Both of you, thank you for replying, I'm excited that I might know how this works soon.


ok thats good, so if you want to select your axis you want to move you may want to have a widget (little visual representation which helps you choose an axis).

so if we consider that our mouse has 2 dimesions we need a way to transform these in to world coordinates.



//this gets the difference between the last mouse position and current one
//so you will have to track that by having new mouse and old mouse variables
float incx = input.mouseIncrement.x;
float incy = input.mouseIncrement.y;

//I have 2 rotation variables for my camera - i know quiet a fe camera //implementations don't store rotations they are in degrees (OpenGL) so
//I convert to radians
double xrot = degreesToRadians(camera.rot.x);
double yrot = degreesToRadians(camera.rot.y);

//heres where the magic happens, we use sin and cos to work out
//how much to move the objest position on each axis, by

position->x += selectedAxis->x * float( (cos(yrot) * incx) + (-(sin(xrot) * sin(yrot)) * incy ) );

position->y -= selectedAxis->y * float( cos(xrot) * incy );

position->z += selectedAxis->z * float( (sin(yrot) * incx) + ((sin(xrot) * cos(yrot)) * incy ) );






This makes it follow where you drag the mouse so it feels logical and correct.

the variable selected axis, indicates which axis we want to move on the value is 1 if we want to move and 0 if we don't want to affect the axis and hence multiplies our result to 0 so it will always be 0. Selected axis in this case is determined by the widget I use (which axis you are clicking and dragging)

If you need more info just say..

Edit
oh yeah, consider the way it works as the object interpreting a mouse gesture as a 3d movement as opposed to moving it to where the cursor is. If you want better explanation on the maths I can help, I worked it out on paper, using the major points of rotations (0,90 and 180 degrees) once i had what sin and cos need to do at the major points, the in betweens just worked... minus a few problems which were easily resolved.

Share this post


Link to post
Share on other sites
@BlackSeeds: I am running into problems trying to implement your code snippet. The "point" I am dragging is lagging behind my cursor unstably. I think you are using OpenGL, and I am using DirectX so some things are slightly different. DirectX uses a left hand coordinate system so I -= when you +='d.

Here is my source. cursor_x_drag is initially calculated using normal coordinates (0 to screen width, 0 to screen height) so I divide them 383.5 (since my viewport is 768x768) to get them into "3d" coordinates (-1.0 to 1.0 and all that wonderful stuff). Still something is wrong, probably in my implementation. Could you elaborate more? If you need any more information from me I'll gladly provide it.


float increment_x = cursor_x_drag / 383.5f;
float increment_y = cursor_y_drag / 383.5f;

double rotation_x = D3DXToRadian(object_rotation_x);
double rotation_y = D3DXToRadian(object_rotation_y);

object.vertice[1].position_x -= float((cos(rotation_y) * increment_x) + (-(sin(rotation_x) * sin(rotation_y)) * increment_y));


Share this post


Link to post
Share on other sites
Quote:

in perspective view as well as most other applications. They just don't allow xyz to be modified simultaneously. I just want to predict a single x y OR z, not all 3.


Well, with a mouse you can update two axis at the same time, but you can make your program to update just one axist at one time if you want.

For doing just the PAN effect I dont use any complex math, really, but maybe in my editor i am not really interested in move objects at exact milimetric positions.

Like BlackSeeds tould, you can use windgets (or push butons that can be On/Off to tell which axis you want to update); then you use the "drag" mouse method, mean you clik and hold a mouse button, at that moment you save current x,y mouse position, then use an "On mouse move" event and there you check the new mouse x,y position and calc the displacement from the initial position and update your vertex position in the selected axis using the displacement from the X or Y mouse coordinate; if i have selected to update XZ then mouse X displacement will update X vertice coordinate, and Y mouse displacement will update Z vertice coordinate

Like i said i dont use any complex math, i just define how much units in world coordinate the vertice will be updated for any mouse x,y displacement; low factors will drag the vertice slowly, high factors will drag faster.


Now, for me this work becouse i really know what is the current position in world coordinate for all vertices in my model so i can add any displacement i want to any vertice; BUT if you only know the original model vertices and to that you have done a lot translation and rotation a matrix and then you use that matrix to show in screen the resulted transformed model then the above aproach will not work.



Share this post


Link to post
Share on other sites
@tpascal: I understand how mouse dragging works.
I still don't understand how to get the vertice to stay aligned to my cursor. It always lags behind.
I think that is what BlackSeeds was trying to show me. Alas I could not get his code sample to work. The vertice would always lag behind my cursor. This only occurs when the scene is rotated.
I get how to move a vertice based on mouse movement but I cannot get it to align to my mouse cursor if any rotations take place. This is the core problem I am facing. Also I have full access to the vertices original and transformed coordinates. Its again just getting its movement to align to my cursor that I cannot grasp.

Share this post


Link to post
Share on other sites

Quote:

I get how to move a vertice based on mouse movement but I cannot get it to align to my mouse cursor if any rotations take place.


When you say "if any rotations take place." do you mean the camera was rotated to see the model from different angle or do you mean the model vertices was actually rotated?

Share this post


Link to post
Share on other sites
Right now the only rotation that takes place is a world transformation. So yes, the rotation was used to see the vertices from another angle. The view matrix is static, and no "other" rotations are occurring.

Share this post


Link to post
Share on other sites
hey dahos,

so did you manage to get the code sample i gave you working in any way, if the only problem is the lagging of the vertex behind the pointer we can add some stuff to resolve that.

the main thing is....Does the vertex move in the correct direction you are dragging the mouse? if so then were almost there

Basically what I do is take a vector from the camera position to the vertex and get the distance of this vector, you can then scale your movement by this distance.

so for instance:

position x += (the math i showed you earlier) * distance

so the further you are away the vertex will move larger distances, the closer you are the more accurate it will be. this may take a bit of tweaking to get it how you want.

If this is not the problem you are having then just let me know what issues you have and ill try and help.

yes my implementation is OpenGL, but looks like you negated correctly to get it working in the other coordinate system :)

also what are your variables cursor_x_drag I didn't quiet understand that bit.

Share this post


Link to post
Share on other sites
Yes, the vertices move in the direction I am dragging. However they lag behind more and more based on the rotation used. More lag at 45rotation_y than say 15rotation_y.

I should point out that simply setting vertice's x & y to my cursor position produces a nearly identical effect. The sin/cos adjustments in your code snippet seemed to have little effect.

cursor_x_drag & cursor_y_drag are just variables that store the difference between your current and last cursor position. Updated every frame.

I will try your distance scaling method and see if it adjusts things appropriate. If it still causes problems I'll upload some more screenshots to avoid any confusion on what is happening.

Share this post


Link to post
Share on other sites
what you need to do is move it on x,y and z at the same time.

if you consider at 0 degrees rotation on the x and y axis, +x mouse drag will cause the vertex to move only on the x axis, because of the math z and y will have 0 increment,

if you got to 90 degrees rotation on the y-axis the x position of the vertex will move by nothing because we are looking directly down the x axis and hence z will become the axis that we want to move there vertex on by dragging the mouse in the x axis of the screen.

now if we consider you are at 45 degrees rotated about the y axis, we want the vertex to effectively strafe the screen so here we move its position by 0.5 x and 0.5 z sop half and half.

it effectively works like spherical coordinates

Share this post


Link to post
Share on other sites
BlackSeeds, I think you just solved my problem. I never even THOUGHT of adjusting the z coordinate with the x coordinate. That keeps my vertice *perfectly* lined up with the cursor. (I would assume by this logic, you translate using 2 axis while rotating by the 3rd, xz rotated by y, yz rotated by x, xy rotated by z). The resulting distance from the vertice to the camera is the distance you need to translate x by. Or rather where x *would* be if no translation had occured...or rather your mouse cursor's location.

I'm so excited...I knew this was going to be so simple it's silly. I'm going to do some more extensive testing to make sure this is fully working properly. I'll post back again if any other issues crop up.

Seriously, thank you for taking time out to explain this to me. It's been driving me completely insane for over a week now. Mostly because the majority of programs never need this kind of information, so very little information on the subject is available.

Share this post


Link to post
Share on other sites
Quote:
Original post by Dhaos
BlackSeeds, I think you just solved my problem. I never even THOUGHT of adjusting the z coordinate with the x coordinate. That keeps my vertice *perfectly* lined up with the cursor. (I would assume by this logic, you translate using 2 axis while rotating by the 3rd, xz rotated by y, yz rotated by x, xy rotated by z). The resulting distance from the vertice to the camera is the distance you need to translate x by. Or rather where x *would* be if no translation had occured...or rather your mouse cursor's location.

I'm so excited...I knew this was going to be so simple it's silly. I'm going to do some more extensive testing to make sure this is fully working properly. I'll post back again if any other issues crop up.

Seriously, thank you for taking time out to explain this to me. It's been driving me completely insane for over a week now. Mostly because the majority of programs never need this kind of information, so very little information on the subject is available.


excellent :) hope it works out for you, always glad to help someone out as on numerous occasions I have been helped on this forum.

you are right about translating 2 axis about the 3rds rotation. whats more, if you translate about all 3 in one go,

ie. translate x+z about y rotation, translate y about z rotation,

so now when you drag the cursor +x and +y on the screen the vertex will move precisely with the cursor. The only issue left is scaling the translation so that it lines up nicely with the cursor regardless of distance.

don't hesitate to post back if there any other issues that arise



Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this