DirectInput (DX9) - mouse coordinates

Started by
8 comments, last by Tar 15 years, 2 months ago
Hello, This is probably a very basic question, but I could not find any straightforward solution to it. I grab the current cursor position using the Win32 function GetCursorPos(). It is in screen coordinates obviously. Now I need to find the corresponding position in my world coordinates. It's a kind of reverse world transformation: transforming from screen coordinates to world coordinates. I would appreciate any help, Tar
Advertisement
...That's a bit confusing, given that it seems you really are trying to reverse the pipleine stages when it is not neccessary. If you are trying to, say, change the position of a cursor on a 3D map like in a war game, you may want to link relative changes in the mouse to the world space of the object in question.

Let's say you want to move something like that in the world on the XZ plane.

D3DXMATRIX m;D3DXMatrixTranslation(&m, mouse_x, 0.0f, mouse_y);


...Something like that. Maybe add some simple collision code to keep the 3D "cursor" from embedding itself in some mountain... you know.

Of course, you need to make sure you are getting relative positions and that you cast the changes to float before trying the above. (It may encourage you to perform a kind of lag to the movement for a more natural feel.)

Overall this is a scenario where the solution is easier to find than one could think. Stay with the pipeline flow and ensure that you make good use of relative mouse position changes. Some programmers even set the cursor position to the center of the front buffer at all times and just use that as a basis for relative motion (and prevent unwanted clicking to make another window active.)
Thanks zyrolasting.

Yes, I'm using relative positions (not absolute) and I agree "reverting the pipeline" it's not a way to go - most likely I'm looking at the wrong direction.
The problem is I don't know how to determine the _initial_ cursor position in my world coordinates. Then I could use the relative changes as you suggested.

I will rephrase the question:
How to get the initial mouse position in _world_ coordinates?

Tar

I... don't think that's even possible. As far as the mouse and, well, 2D images of the like are concerned, screen space coordinates is the only available form. the mouse isn't even in the pipeline at all, really. As far as Direct3D is concerned, the mouse doesn't even exist. It's management is up to Windows and Direct Input.

Now, if you want to get the mouse coordinate on your own window only, you could just check to see if the mouse is in bounds of your window's client rect.
But I've never heard of the mouse position being read in world coordinates. Ever. If by some means it IS possible, then I am curious as to why such a (to be frank) pointless endevor came to light.

You are looking at 2 different APIs here. Direct3D concerns itself with the pipeline and a world of graphic possibilities, and Direct Input manages human input from various devices. How they work alongside each other is up to your application.
Just plan your methods with how each API will be using each other's data (They aren't exactly all one entity in one process), and you'll be fine. [smile]
Yeah, it seems I'm really lost.
What I'm trying to do is a really basic thing: I'd like to position an object on the screen when a user clicks a mouse button. The object should be placed at the location of the mouse cursor. You're right: the object exists in Direct3D (world coordinates) and the mouse in DirectInput/Win32API (screen coordinates). I just don't know how to position the object in my world coordinate system using a mouse as an input device. That's it. A pretty basic requirement and I guess there must be a straightforward solution. I just don't know where to look for it.

Thanks,
Tar
Well, I think in order to achieve what you want is something called "picking".
I'm not at the experience level to understand it myself, so I'm not the one toask about it. I do know however, that picking reads where you click on the screen and projects a ray from the mouse into the world (Which closely resembles converting screen space to world space. Hell, it may be just that.) and will get you a world position based on a valid component the ray intersects first.

have you ever used a 3D modeling package like Blender, Truespace, Milkshape, etc.?
They use picking in order for you to even select something like a face or vertex.

Again, I think it's later on in the understanding of Direct3D. I'm in the game institute and I'm still not at the topic, even after a little over 1k pages of material. (It's as much of a headache as it sounds.)
There's two steps involved:

1)
From GetCursorPos (screen coordinates) you need to convert into the windows' client system. Use the function ScreenToClient for this. Now the mouse pos is relative to the client area of your window.

2)
Picking. You cannot however determine a 3d point from a simple 2d point, there is information missing. Imagine the screen in pixels, every pixel on the screen plane can represent actually a line of 3d positions. Of course only the closest to the screen is visible.

The key word is "unproject". There is a function D3DXVec3Unproject. Use it two (!) times, once with MousePosX, MousePosY and 0.0f (for z), once with MousePosX, MousePosY and 1.0f (for z). Now you have 2 points from the aforementioned line in 3d space.

Depending on your goal you can now do intersection tests with that line. Calculate the intersection of the line with a plane to get the final 3d point.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

I don't see what this has to do with DirectInput? Using DirectInput for mouse or keyboard input is an extremely bad idea anyway.
Wow! Thanks guys (Endurion and zyrolasting). It seems the picking technique, intersection tests, and D3DXVec3Unproject are what I was looking for. I need to dig in it.

Evil Steve: yes, this thread drifted from DirectInput. I don't mind using pure Win32 to read mouse input. I just thought DirectInput would be more efficient. I did not know it was quite opposite and I'm surpised Microsoft discourages developers from using DirectInput to read data from mouse or keyboard devices. I'll use Win32 then.

The key idea for me is the "unproject" operation, how Endurion called it. That would correspond to "going back" from screen coordinates to the world coordinates. Exactly what I was looking for! I just thought naively that DirectInput would do this work (intersection tests etc.) "automagically" and gave me somehow mouse position in world coordinates.

Thanks for pointing me in the right direction.
For those who would be interested in a solution to my problem. The problem, as it turned out, was:

"How to convert screen coordinates to world coordinates?"

// Get mouse coordinates and make them relative to the client area window.
// hWnd is a handler to the main window returned from the CreateWindow()
// function.
POINT p = {0, 0};
::GetCursorPos(&p);
::ScreenToClient(hWnd, &p);

// Get matrices and the viewport.
D3DXMATRIX pm; // projection matrix
D3DXMATRIX vm; // view matrix
D3DXMATRIX wm; // world matrix
D3DVIEWPORT9 vp; // viewport
g_Device->GetTransform(D3DTS_PROJECTION, &pm);
g_Device->GetTransform(D3DTS_VIEW, &vm);
D3DXMatrixIdentity(&wm); // make the world matrix an identity matrix
g_Device->GetViewport(&vp);

// Call the D3DXVec3Unproject function twice to determine two points
// in our world space. Having two points we will be able to find
// a line in the world space. One point is for the z-near plane
// (which is usually z=0.0f) and another point is for z-far plane
// (which is usually z=1.0f). We grab the z-planes from the viewport.
D3DXVECTOR3 p1;
D3DXVec3Unproject(&p1, &D3DXVECTOR3(p.x, p.y, vp.MinZ), &vp, &pm, &vm, &wm);
D3DXVECTOR3 p2;
D3DXVec3Unproject(&p2, &D3DXVECTOR3(p.x, p.y, vp.MaxZ), &vp, &pm, &vm, &wm);

// We calculate an intersection of the line found previously
// with a plane z=0.0f. Equations of a line in 3-D space can
// be found on the following websites:
// http://mathforum.org/dr.math/faq/formulas/faq.ag3.html#threelines
// http://mathforum.org/library/drmath/view/65721.html
// Here, wx, wy, and wz represent coordinates in the world space.
float wz = 0.0f;
float wx = ((wz-p1.z)*(p2.x-p1.x))/(p2.z-p1.z) + p1.x;
float wy = ((wz-p1.z)*(p2.y-p1.y))/(p2.z-p1.z) + p1.y;

// w is the point in the world space corresponding to the p point
// in the screen coordinates.
D3DXVECTOR3 w(wx, wy, wz);

Have a nice day,
Tar

This topic is closed to new replies.

Advertisement