Jump to content
  • Advertisement
Sign in to follow this  

Cant translate world coords to screen

This topic is 1028 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello. I am creatin own engine from scratch in d3d9. Lookin on forum and google i found the way to create a ray and check if it intersects given area. It works. But i cannot do it the other way. To feed a D3DXVECTOR3 and retrieve XY on the screen. I found several "solutions" on the internet but damn they give wrong results.


So from what i've read i have to:

1) create matrix from projection * view

2) use the new matrix on given D3DXVECTOR3 containing world location

3) the screen x will be (vector.x + 1) * 0.5 * width


But something is clearly wrong because i see the output values. Is it wrong alghoritm or should i show my code?

Thanks in advance


Share this post

Link to post
Share on other sites
View times projection, not projection times view.

The result will be NDC, so -1 to 1 across both axes.

Don't really understand how this relates to a ray though. If you are doing mouse picking, you need the opposite - a screen position converted into a world ray.

Share this post

Link to post
Share on other sites

Thanks for such a quick reply. I am tryin to do basic RTS game so i will obviously need to select units (so create a ray to check if it selects some object under cursor) but i will also need to draw HP bar for example over unit's head which requires the 3d unit location to be converted to screen, to draw the 2D bar just above.


So to achieve first i created a white box with edges on (-60, -13, -60), (60, -10, 60) and this piece of code detects perfectly if the ray hit (the code is called every frame when i move cusor so i see if the "ray hit" text disappears or shows up). "s" is mouse xy:

        D3DVIEWPORT9 vp;

	d3ddev->GetTransform(D3DTS_VIEW, &view);
	d3ddev->GetTransform(D3DTS_PROJECTION, &proj);

	float px = (((2.0f * s.x) / vp.Width) - 1.0f) / proj(0, 0);
	float py = (((-2.0f * s.y) / vp.Height) + 1.0f) / proj(1, 1);

	Ray ray;
	ray._origin = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
	ray._direction = D3DXVECTOR3(px, py, 1.0f);
	D3DXMATRIX viewInverse;
	D3DXMatrixInverse(&viewInverse, 0, &(view));
	D3DXVec3TransformCoord(&ray._origin, &ray._origin, &viewInverse);
	D3DXVec3TransformNormal(&ray._direction, &ray._direction, &viewInverse);

	D3DXVec3Normalize(&ray._direction, &ray._direction);

	if (D3DXBoxBoundProbe(&D3DXVECTOR3(-60, -13, -60), &D3DXVECTOR3(60, -10, 60), &ray._origin, &ray._direction))
		RECT rect = { 20, 400, 220, 450 };
		font.printf(rect, D3DCOLOR_XRGB(123, 123, 123), "RAY HIT");

I assume it is enough to loop through all objects and check if D3DXBoxBoundProbe returns true with their collision box and this way i will select unit (is it the optimal way tho?).

I understand its all about multiplying matrices, but I have to admit that i dont fully understand few d3d things. If we are in 3D world, why are matrices 4x4 and not 3x3? Lookin at functions "D3DXVec3TransformNormal" and "D3DXVec3TransformCoord" i see they differ only by "w" value 0/1. What is the magical "w" (msdn doesnt help sad.png )?





Edit: Yeah the matrix multiplication order was messed in 3d to screen :) I read also on the xyzw, i get everything now :) Thanks a lot

Edited by QQemka

Share this post

Link to post
Share on other sites

How about this? offset adjusts the world position forward or backward relative to the camera and is probably not necessary for what you need.

float4 WorldToScreen(const float4& v, 
    float offset,
    float4x4 &orientation,
    float4x4 &modelView,
    float4x4 &projection,
    float width, float height, float _near, float _far)
    float4 result = modelView * (orientation * v);
    result.z -= offset;
    result = projection * result;

    // Homogeneous divide
    const double rhw = 1 / result.w;

    return float4(
        (1 + result.x * rhw) * width / 2,
        (1 + result.y * rhw) * height / 2,  // or (1 - result.y * rhw) * height / 2,
        (result.z * rhw) * (_far - _near) + _near,
Edited by Doug Rogers

Share this post

Link to post
Share on other sites
Re w, it w is zero, translations are effectively ignored when multiplying by a 4x4 matrix so convention is to use 1 for points and 0 for directional vectors like normals

There is probably more to this that others can expand upon, but use the Coord form for positions and the Normal form for normals etc.

We use 4x4 and extend 3D vectors to 4 with w so we can encode translation and scaling into the same matrix as rotation. This is normally described as homogenous I think.

Share this post

Link to post
Share on other sites
The way to avoid looping through all the boxes would be to use some kind of spatial partitioning (broadphase) to identify the objects that might be intersected by your ray. You can then do your bounding box check on a smaller subset. This is a whole topic in itself though and, depending on the number of units involved, your approach may be fine. It just doesn't scale very well.

You might want to look into something I'm currently doing. I'm using Bullet 3D physics library but just using sections of it (broadphase, GJK etc) rather than doing a physics sim. This stuff is hard to get right yourself. Bullet is nice and modular in this respect.

So, for free, you can use the Bullet dynamic tree to give you a broadphase, use the Bullet shapes to more closely fit your units and the Bullet ray cast to get your result. Be far more robust than anything you write yourself.

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!