3d position to 2d position

Started by
7 comments, last by Anddos 12 years ago
I want to convert a 3d position to a 2d screen coordinate. But i'm not really sure how to do that.

I know i need the view, projection and world matrix for the calculations. So i managed to get those. But what next? How can i calculate the 3d position of an object to a 2d screen position?

This is how i get the matrices:

[size="2"]D3DXVECTOR3 vector_2d, vector_3d(0,0,0);
[size="2"]D3DXMATRIX view_matrix, proj_matrix, world_matrix;
[size="2"]D3DVIEWPORT9 d3dvp;

[size="2"]dev->GetTransform( D3DTS_VIEW, &view_matrix );
[size="2"]dev->GetTransform( D3DTS_PROJECTION, &proj_matrix );
[size="2"]dev->GetTransform( D3DTS_WORLD, &world_matrix );
[size="2"]dev->GetViewport( &d3dvp );
[size="2"]D3DXVec3Project( &vector_2d, &vector_3d, &d3dvp, &proj_matrix, &view_matrix, &world_matrix );
[size="2"]D3DXVec3Unproject( &vector_3d, &vector_2d, &d3dvp, &proj_matrix, &view_matrix, &world_matrix );
[size="2"]
Advertisement
The WordViewProjection matrix is what your looking for. that is the objects position in screen space, where x is -1 to 1, y is -1 to 1 and z is (assuming it's actually on the screen) 0 to 1, which is the depth.

to get the WVP, you just have to multiply the objects world space matrix with the view matrix, then with the projection matrix (in that order, World * View * Projection)

The world matrix stores the objects position (translation), orientation (rotation), and size (scale) in world space, or in other words, all the transformations you do on the model.

The View matrix stores the cameras position, target (what its looking at, or direction it's facing), and up (which is the direction that should be orthogonal to the target, so they make a right angle. it's the cameras "up" direction, and not the worlds up direction) You can get the view matrix from 3 vectors describing it like this:


D3DXMATRIX View;
D3DXVECTOR3 Position = D3DXVECTOR3(0.0f, 0.0f, 0.0f); // Position of your camera
D3DXVECTOR3 Target = D3DXVECTOR3(0.0f, 0.0f, 1.0f); // Cameras target
D3DXVECTOR3 Up = D3DXVECTOR3(0.0f, 1.0f, 0.0f); // Cameras up, should be a unit vector, and orthogonal to Target

D3DXMatrixLookAtLH( &View, &Position, &Target, &Up );


The projection matrix is like a pyramid, where the camera is the point or top of the pyramid, and everything inside the pyramid is what the camera sees. The near and far planes decide how close to the camera and how far away from the camera objects should be clipped, or not rendered. You could look at the far plane as the base of the pyramid and the near plane like cutting the tip off of the pyramid, so that anything that's left inside the pyramid is rendered to the screen. The projection is defined by two floats that describe the near and far planes, an aspect ratio (width/height) and a vertical field of view (FOV, in radians). We can get the projection matrix like this: (notice the (float) next to Width/Height. This is because Width and Height are most likely integers, so without the (float) this would be an integer division, and the result would most likely be a 1 instead of a real aspect ratio)

D3DXMATRIX Projection;
D3DXMatrixPerspectiveFovLH(&Projection, 0.4f*3.14f, (float)Width/Height, 1.0f, 1000.0f);


Finally, after you have all three matrices, you can create the WVP, or world view projection matrix:

D3DXMATRIX WVP;
WVP = World * View * Projection;


The WVP matrix is the objects position in screen space. As i mentioned,above, screen space's x and y are between -1 and 1, and z is 0 to 1. If your looking to turn this into 0 to the width and height of your screen, you will have to do an extra calculation, which i will show you in a minute. Now that we have the WVP, we can get the objects screen space position like this:

D3DXVECTOR3 screenCoord = D3DXVECTOR3(0.0f, 0.0f, 0.0f); // Position of object in screen space
D3DVec3TransformCoord(&screenCoord, &screenCoord, &WVP);


So now how do we turn the screen space from -1 to 1, to 0 to the width and height of your window? easy, just add 1 to x and y, divide it by two, and multiply it by the screen width or height, like this:

screenCoord.x = ((screenCoord.x + 1.0f) / 2.0f) * Width;
screenCoord.y = ((screenCoord.y + 1.0f) / 2.0f) * Height;


Maybe you already knew how to get the world, view, and projection matrices, but i thought i would be thorough and make sure you understand exactly how to do what you want ;)

hope this helps! good luck!
Aloha,


Finally, after you have all three matrices, you can create the WVP, or world view projection matrix:

D3DXMATRIX WVP;
WVP = World * View * Projection;


The WVP matrix is the objects position in screen space. As i mentioned,above, screen space's x and y are between -1 and 1, and z is 0 to 1. If your looking to turn this into 0 to the width and height of your screen, you will have to do an extra calculation, which i will show you in a minute. Now that we have the WVP, we can get the objects screen space position like this:

D3DXVECTOR3 screenCoord = D3DXVECTOR3(0.0f, 0.0f, 0.0f); // Position of object in screen space
D3DVec3TransformCoord(&screenCoord, &screenCoord, &WVP);


So now how do we turn the screen space from -1 to 1, to 0 to the width and height of your window? easy, just add 1 to x and y, divide it by two, and multiply it by the screen width or height, like this:

screenCoord.x = ((screenCoord.x + 1.0f) / 2.0f) * Width;
screenCoord.y = ((screenCoord.y + 1.0f) / 2.0f) * Height;



This is exactly what D3DXVec3Project does. But for starters it is nice to see what is actually going on behind the scenes, so thumbs up for the time you spend. smile.png Besides, if you do those transformations in shaders you have to do it manually anyway.

Oh, and don't forget the flipping of the y coordinate, since the origin of the window is in a different corner:
screenCoord.y = ((-screenCoord.y + 1.0f) / 2.0f) * Height;
(Only necessary in D3D, not in GL as a side note...)

Greetings!
oh my bad! thanks for mentioning the flipping of y in screenspace!

i'm not going to lie, i wasn't even aware of D3DXVec3Project, haha, so thanks for that too, i'm pretty sure that's exactly what he's looking for, no sense recreating the wheel ;)
Thanks alot guys. Thanks for the indept explanation, very much appreciated! :)
Hi i still have a question. I though i had everything working but for some reason the screen coordinates are wrong.

This is my function:

D3DXMATRIX view_matrix, proj_matrix, world_matrix;
D3DVIEWPORT9 d3dvp;
D3DXVECTOR2 screen;

m_pD3Ddev->GetTransform( D3DTS_VIEW, &view_matrix );
m_pD3Ddev->GetTransform( D3DTS_PROJECTION, &proj_matrix );
m_pD3Ddev->GetTransform( D3DTS_WORLD, &world_matrix );
m_pD3Ddev->GetViewport( &d3dvp );
D3DXMATRIX WVP;
WVP = world_matrix * proj_matrix * view_matrix;

// Position of object in world
D3DXVECTOR3 screenCoord = D3DXVECTOR3(pos.x, pos.y, pos.z);

// Position of object in screen space
D3DXVec3TransformCoord(&screenCoord, &screenCoord, &WVP);

screenCoord.x = ((screenCoord.x + 1.0f) / 2.0f) * d3dvp.Width;
//screenCoord.y = ((screenCoord.y + 1.0f) / 2.0f) * d3dvp.Height;s
creenCoord.y = ((-screenCoord.y + 1.0f) / 2.0f) * d3dvp.Height;

// Put coords back in vector2s
creen.x = screenCoord.x;
screen.y = screenCoord.y;

return screen;


I position in my game is:
x:1211.037354 y:-411.112854 z:232.125015

The screen result is:
620563.125000 y:158251.343750

[size=2]Which i weird, because the object was exactly infront of me. Any idea where it goes wrong?

The transformation order should be:
WVP = world_matrix * view_matrix * proj_matrix;

You can compare the result to what D3DXVec3Project is giving you. It should yield the same.
need to divide by the w coordinate also, as in:




vec4f v4Position(v3ObjectPos.x, v3ObjectPos.y, v3ObjectPos.z, 1.f);
v4ScreenPosition = v4Position * WorldViewProjectionMatrix;
v4ScreenPosition.x /= v4ScreenPosition.w;
v4ScreenPosition.y /= v4ScreenPosition.w;
v4ScreenPosition.x = fScreenWidth * (v4ScreenPosition.x+1.0f)/2.f;
v4ScreenPosition.y = fSreenHeight * (1.0f-((v4ScreenPosition.y+1.f)/2.f));
try setting the world matrix to the indentity
:)

This topic is closed to new replies.

Advertisement