Skip to main content
GameDev.net gamedev.net
🔒 Locked

Picking in perspective/orthogonal views

Started by Maddibob Jun 26, 2004 at 10:15 AM 8 replies 2.5k views
Original Post
Maddibob
Maddibob
Hi I've currently got a Directx8 app which is a kind of level/mesh designer. I have 4 view types, 1 perspective and 3 orthogonal (top, side and front). In one of the orthogonal views, you can zoom in and move around the objects by using view translation and scaling which works perfectly. I basically rotate the view 90 degrees in the relevant direction first to get the side, top or front projection and then apply the required translation and rotation, etc. This all works fantastically well until I've come to picking objects. Can anyone give me some pointers or code to do this? My objects are also individually scaled, translated and rotated so it's not a case of checking the coordinates against the original object vertices, there must be a reverse logic step I have to do? Any sample code on how to do this in both perspective and orthogonal projection types would be very much appreciated as my girlfriend likes me with hair! Thanks all
Karl G
Karl G
I've had a TON of trouble trying to set up orthogonal projection matrices myself...but I can help with the picking. The easiest thing to do is check out the "Pick" demo that comes with the DirectX NINE SDK. The DX8 one is pretty bad... the dx9 version includes support for the projection and world matrices, so theoretically it could be used in both orthogonal and perpsective views. Being as you don't have that version of the SDK, though, I can post the relavent code when I get home later tonight. If you don't want to wait then you can always download it and check it out yourself :)
Endurion
Endurion
You can use one method for all kind of projections, provided you have the currently set matrices. On non-pure devices you can also call GetTransform. You will also need a viewport struct.

Look into D3DXVec3Unproject. Call it two times with your mouse coordinates and z set to 0.0f and 1.0f.

This will give you two points in object space (depending on the world matrix you insert). These two points form a ray you can use to do intersection tests.

This will work with every kind of projection matrix, so no need to hardcode every case.
Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>
Karl G
Karl G
Circlesoft, you rock :) I just realised that another post has the code that you need to do this, also:

D3DXMATRIXA16 matProj;lpd3d_device->GetTransform( D3DTS_PROJECTION, &matProj );POINT ptCursor;GetCursorPos( &ptCursor );ScreenToClient( hwnd, &ptCursor );// Compute the vector of the pick ray in screen spaceD3DXVECTOR3 v;v.x =  ( ( ( 2.0f * ptCursor.x ) / SCREEN_WIDTH  ) - 1 ) / matProj._11;v.y = -( ( ( 2.0f * ptCursor.y ) / SCREEN_HEIGHT ) -  ) / matProj._22;v.z =  1.0f;// Get the inverse of the composite view and world matrixD3DXMATRIXA16 matView, matWorld, m;lpd3d_device->GetTransform( D3DTS_VIEW, &matView );lpd3d_device->GetTransform( D3DTS_WORLD, &matWorld );m = matWorld * matView;D3DXMatrixInverse( &m, NULL, &m );// Transform the screen space pick ray into 3D spaceD3DXVECTOR3 vPickRayDir;D3DXVECTOR3 vPickRayOrig;D3DXVECTOR3 vPickRayTarget;vPickRayDir.x  = v.x*m._11 + v.y*m._21 + v.z*m._31;vPickRayDir.y  = v.x*m._12 + v.y*m._22 + v.z*m._32;vPickRayDir.z  = v.x*m._13 + v.y*m._23 + v.z*m._33;vPickRayOrig.x = m._41;vPickRayOrig.y = m._42;vPickRayOrig.z = m._43;
Maddibob
Maddibob
Guys, thanks a lot for all your great replies. I do have the Dx9 SDK but I haven't ported my Dx8 code to it yet, so I'll have to good look at the pick stuff from there.

Will post a reply tonight with my results.

Thanks again
Maddibob
Maddibob
Hey guys

My D3DTS_VIEW transform is based on scale and translation. Doing a pick using the code shown doesn't work because you can't MatrixInverse matrices with scales other than 1 or -1 (i.e. reflections only).

It works fine if I just use translation, but how do we get around this problem? For zooming into the orthogonally viewed map smoothly, I scale the view accordingly and it looks UnrealEd-like-nice.

Again, any help from you lovely guys much appreciated...

Thanks
Kibble
Kibble
Hello,

Zoom the view with the projection matrix, not the view matrix. For example, to see the entire level, set the width and height of your ortho projection matrix to the width and height of your map. Similarly, you would zoom a perspective view with the FOV, not scaling/translating the view matrix.
Maddibob
Maddibob
Ah, thanks Karl, that's working great now.

One last thing guys, I want to put a little 3 by 3 block on top of each vertex. Anyone know how to get screen coordinates for vertices?

I keep looking at the DXDVec3Unproject/Project but I can never seem to get it working. I was thinking about putting a little sprite on per vertex but I don't want it scaled, so essentially I need a 3 by 3 block ontop of each vertex no matter how far away you are. Would this be done by getting the gdi of the window and writing a block out that way? Or overlay an orthogonal view (for perspective views) and draw a block that way?

Thanks in advance
Kibble
Kibble
Getting the DC of the window and drawing them that way is probably easiest, but it could also result in flicker, since Direct3D's present logic isn't tied into the window refreshes. at best, you draw the blocks right after presenting, which still might cause flicker when updating the view near-constantly (ie when moving or something). Its probably worth it to try that first, then if that is too flickery, use a transformed vertex (D3DFVF_XYZRHW) format for quads for the 3x3 blocks. Using an orthognal view + untransformed vertices will *probably* give you 'blubbery' blocks, due to floating point inaccuracy (fluctuating between 2 and 4 pixels in each dimension), but I could be wrong here.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.