Hey all,
I wrote this routine, the function of which is to return a point in 3D space based on a mouse click. A simple pick-ray routine. In this routine, the x and y point is the point on the screen clicked, the z is a value from 0 to 1 which represents the distance along the view frustum to select the point's plane (0.0 would be on the near z plane, 1.0 would be on the far z plane).
Here's the code:
D3DXVECTOR3 LevelEditorIndoorClass::GetClosestGridPoint(int CameraNumber, float x, float y, float z)
{
D3DXVECTOR3 Pick;
D3DXMATRIX ProjectionMatrix;
D3DXMATRIX ViewMatrix;
D3DXMATRIX InvViewMatrix;
D3DXVECTOR3 PickRayDir;
D3DXVECTOR3 PickRayOrig;
//calculate the projection matrix
if (CameraType[CameraNumber] == CAMERA_3D)
D3DXMatrixPerspectiveFovLH(&ProjectionMatrix, D3DX_PI/4.0f,
ViewPort[CameraNumber].Width/ViewPort[CameraNumber].Height,
1.0f, 1000.0f);
else
D3DXMatrixOrthoLH(&ProjectionMatrix,
ViewPort[CameraNumber].Width * Camera[CameraNumber].GetCameraZoom(),
ViewPort[CameraNumber].Height * Camera[CameraNumber].GetCameraZoom(),
1.0f, 1000.0f);
//calculate a pick ray (screen space)
x -= ViewPort[CameraNumber].X;
y -= ViewPort[CameraNumber].Y;
Pick.x = (((2.0f * x) / ViewPort[CameraNumber].Width) - 1) /
ProjectionMatrix._11;
Pick.y = -(((2.0f * y) / ViewPort[CameraNumber].Height) - 1) /
ProjectionMatrix._22;
Pick.z = 1.0f;
//calculate the inverse view matrix
ViewMatrix = Camera[CameraNumber].GetViewMatrix();
D3DXMatrixInverse(&InvViewMatrix, NULL, &ViewMatrix);
// Transform the screen space pick ray into 3D space
PickRayDir.x = Pick.x*InvViewMatrix._11 + Pick.y*InvViewMatrix._21 +
Pick.z*InvViewMatrix._31;
PickRayDir.y = Pick.x*InvViewMatrix._12 + Pick.y*InvViewMatrix._22 +
Pick.z*InvViewMatrix._32;
PickRayDir.z = Pick.x*InvViewMatrix._13 + Pick.y*InvViewMatrix._23 +
Pick.z*InvViewMatrix._33;
D3DXVec3Normalize(&PickRayDir,&PickRayDir);
PickRayOrig.x = InvViewMatrix._41;
PickRayOrig.y = InvViewMatrix._42;
PickRayOrig.z = InvViewMatrix._43;
z = z*(1000.0f - 1.0f) + 1.0f;
return PickRayOrig + PickRayDir * z;
}
My interface has four cameras on it (most of which are orthogonal, but one which is perspective). In order to test this routine, I called it twice and got two points (one on the near z plane, one on the far z plane):
TempObject.StartPoint = GetClosestGridPoint(ActiveCamera, x, y, 0.0f);
TempObject.EndPoint = GetClosestGridPoint(ActiveCamera, x, y, 1.0f);
I then drew a line using these two points. I realize that (if this was working correctly) for the camera where the user clicks, you would only get a point, but the other three cameras (which show the same scene from different views) would give a line segment.
However, it's not working as I would like. What I'm actually getting is the near point being right, but the far point being utterly wrong.
Does anyone see anything wrong with my math or algorithm? Because I'm just not seeing it :)
Thanks, Ron