• 12
• 12
• 9
• 10
• 13

# Mouse Pick

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

## Recommended Posts

I am trying to pick the closest face of my terrain using the mouse. I know there is the Pick200# example that does this, but it uses a mesh which I am not using. My terrain class, has all the verticies/indicies data, which I can use to form triangles. Ultimately preforming a ray-triangle test. The terrain data is in local space, and I am not sure what space the ray is in. I think I am looking to put them into a common space so that I can do the ray-triangle test, but I cant figure it out. I use the code below (from the Pick200% example) to get a ray.
        POINT ptCursor;
GetCursorPos( &ptCursor );
ScreenToClient( DXUTGetHWND(), &ptCursor );

// Compute the vector of the Pick ray in screen space
D3DXVECTOR3 v;
v.x =  ( ( ( 2.0f * ptCursor.x ) / pd3dsdBackBuffer->Width  ) - 1 ) / pmatProj->_11;
v.y = -( ( ( 2.0f * ptCursor.y ) / pd3dsdBackBuffer->Height ) - 1 ) / pmatProj->_22;
v.z =  1.0f;

// Get the inverse view matrix
const D3DXMATRIX matView = *g_Camera.GetViewMatrix();
const D3DXMATRIX matWorld = *g_Camera.GetWorldMatrix();
D3DXMATRIX mWorldView = matWorld * matView;
D3DXMATRIX m;
D3DXMatrixInverse( &m, NULL, &mWorldView );

// Transform the screen space Pick ray into 3D space
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;


##### Share on other sites
The code you posted undoes that view and world transforms, so puts the ray into object space.

The pick sample has a code path that uses its own function to test a ray against a triangle, instead of using the mesh function, so you can use that.

Though in case of the terrain what I did was just traverse the ray and see where it hit the ground. Assuming that your terrain is a grid, that's a lot more efficient than testing triangles. If you keep for each NxN terrain tiles the maximum and minimum height it's easy to speed this even further. (Using a quadtree should be even more efficient, though as I stated elsewhere I always prefer the simplest solution that's fast enough.)

##### Share on other sites
You should break it up into steps. Step 1: Convert the mouse screen point into a picking ray that is in World Space. Step 2: Transform the ray's starting point and direction vector into model space.

Step 1:

POINT ptCursor;GetCursorPos( &ptCursor );ScreenToClient( DXUTGetHWND(), &ptCursor );// Convert from screen to view space:D3DXVECTOR3 RayDirection;RayDirection.x =  ( ( ( 2.0f * ptCursor.x ) / pd3dsdBackBuffer->Width  ) - 1 ) / pmatProj->_11;RayDirection.y = -( ( ( 2.0f * ptCursor.y ) / pd3dsdBackBuffer->Height ) - 1 ) / pmatProj->_22;RayDirection.z =  1.0f;// Convert from view to world space:const D3DXMATRIX matView = *g_Camera.GetViewMatrix();D3DXMATRIX m;D3DXMatrixInverse( &m, NULL, &matView );// transform the ray's direction, w = 0.D3DXVec3TransformNormal(	&RayDirection,	&RayDirection,	&m);// normalize the directionD3DXVec3Normalize(&RayDirection, &RayDirection);// I am improvising here, since you don't have this code.// Set the picking ray's starting point to your camera's position:D3DXVECTOR3 RayPos = *g_Camera.GetPosition();

Step 2:

// Convert the picking ray direction and position into the local space of the object to be tested using the world matrix of the object (note this is not the inverse!!):const D3DXMATRIX matWorld = *g_Camera.GetWorldMatrix();D3DXVECTOR3 RayDirectionLocal, RayPosLocal;D3DXVec3TransformCoord(&RayPosLocal, &RayPos, &matWorld);D3DXVec3TransformNormal(&RayDirectionLocal, &RayDirection, &matWorld);

Now the ray's position and direction are in the same space as the object.