[UNRESOLVED] Predicting a 3D Point given a rotation

Started by
18 comments, last by BlackSeeds 15 years, 5 months ago
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]
Advertisement
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

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

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]
I am still unable to resolve this issue. I am merely trying to move a vertice to your cursor compensating for any world or view rotation.
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.
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.
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.



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...


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.
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 variablesfloat 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 radiansdouble 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, byposition->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.

This topic is closed to new replies.

Advertisement