Original Post
Hi all, I'm currently having trouble getting picking to work in my Bezier curve application. The idea is to have a sphere at each of the control points along the bezier curve and I can then click on a sphere to move its respective control point. All the bezier math etc. is fine but I can't get picking to work. I'm using the DirectX August 2007 SDK and C++. First of all each control point is defined: Then the sphere displayed at the point is created thus: and displayed: As you can see I translate to the position of each point Set the world matrix and store it then draw the point. Don't think there's any problem there. Then in my main loop I make a call to the pick function which takes in all the necessary paramaters: The view matrix is currently calculated in the camera class (taken from Frank D Luna's DirectX book) and works fine for rotation/translation of the camera etc. As you can see there is a line commented out which gets the view matrix using 'gd3dDevice->GetTransform()' this method gives different results (still doesn't work) when doing the picking calculations even though it should essentially return the camera view matrix anyway as it is updated each frame: However there must be a problem in my picking function anyway as it still doesn't work no matter which way I get the view matrix. Here's the picking function which is mostly taken from the Toymaker Picking Tutorial Now the problem I currently have is that I can click anywhere on the screen (even not over any control point) and it will always register me as having clicked on all the control points. When I click over a control point it still registers a hit on all of them. Using the second method of getting the view matrix I mentioned earlier does the exact opposite. It never registers a hit at all. I have no idea where I'm going wrong as I have followed numerous tutorials always having the same outcome, either always registering a hit or never registering one. I guess this is going to be a bit of a mammoth post but hopefully someone can suggest possible reasons for what's happening. Thanks! Here's a screenshot of my App to give you a better understanding of what it looks like, theres a curve, a number of red spheres representing the control points and an object following the curve.
struct CtrlPoint //A structure to hold data on a control point
{
D3DXVECTOR3 position; //Position of the control Point
ID3DXMesh* mesh; //A mesh which will represent the control point visually
float radius; //Radius of the sphere (of the mesh which represents the control point)
bool selected; //Whether the point has been selected by the mouse
D3DXMATRIX world; //The control point's world matrix (for calculating picking)
}ctrlPoint[NUMCTRLPOINTS]; //Creates an array of control points
D3DXCreateSphere(gd3dDevice,
ctrlPoint.radius,
20,
20,
&ctrlPoint.mesh,
0);
D3DXMatrixIdentity(&I);
//Display a sphere each control point
for(int i=0; i<NUMCTRLPOINTS; i++) //for each control point
{
D3DXMATRIX T;
//Translate the matrix to the position of the control point
D3DXMatrixTranslation(&T, ctrlPoint.position.x, ctrlPoint.position.y, ctrlPoint.position.z);
//Calculate the total movement/rotation into one matrix
S = I * T;
//Transform to the position/orientation of the matrix
gd3dDevice->SetTransform(D3DTS_WORLD, &S);
//Store the control point's world matrix
gd3dDevice->GetTransform(D3DTS_WORLD, &ctrlPoint.world);
//Set the standard red material for the control point
gd3dDevice->SetMaterial(&Material::RED_MTRL);
//Draw the Sphere
ctrlPoint.mesh->DrawSubset(0);
}
//If the left Mouse Button is clicked and wasn't down last frame
if(gDInput->mouseButtonDown(0) && mouseClicked==0)
{
POINT cursorPos;
//Get the position of the cursor
GetCursorPos(&cursorPos);
//Make it relative to the client area window
ScreenToClient(*mainWnd, &cursorPos);
D3DVIEWPORT9 vp;
//Get the current viewport
gd3dDevice->GetViewport(&vp);
D3DXMATRIX proj;
//Get the current Projection matrix
gd3dDevice->GetTransform(D3DTS_PROJECTION, &proj);
D3DXMATRIX view;
//Get the current view matrix from the camera class
camera->getViewMatrix(&view);
//gd3dDevice->GetTransform(D3DTS_VIEW, &view); //Not using this method to get view matrix currently
//Calculate Picking
pick->doPick(cursorPos, vp, proj, view,
bezier[0]->getCtrlPoints(), //Array of control point structs
bezier[0]->getNumCtrlPoints() //Number of control Points
);
}
//Update the view matrix representing the cameras new position/orientation.
D3DXMATRIX V;
camera->getViewMatrix(&V);
gd3dDevice->SetTransform(D3DTS_VIEW, &V);
void Pick::doPick(POINT cursorPos, D3DVIEWPORT9 vp, D3DXMATRIX proj, D3DXMATRIX view, Bezier::CtrlPoint* ctrlPoint1,Bezier::CtrlPoint* ctrlPoint2, int numCtrlPoints)
{
for(int i=0; i<numCtrlPoints; i++) //for each control point
{
D3DXVECTOR3 v;
v.x = ( ( (2.0f * cursorPos.x) / vp.Width) - 1 ) / proj._11;
v.y =-( ( (2.0f * cursorPos.y) / vp.Height) - 1 ) / proj._22;
v.z = 1.0f;
D3DXMATRIX m;
D3DXVECTOR3 rayOrigin,rayDir;
D3DXMatrixInverse( &m, NULL, &view );
// Transform the screen space pick ray into 3D space
ray.direction.x = v.x*m._11 + v.y*m._21 + v.z*m._31;
ray.direction.y = v.x*m._12 + v.y*m._22 + v.z*m._32;
ray.direction.z = v.x*m._13 + v.y*m._23 + v.z*m._33;
ray.origin.x = m._41;
ray.origin.y = m._42;
ray.origin.z = m._43;
// Use inverse of matrix
D3DXMATRIX matInverse;
D3DXMatrixInverse(&matInverse,NULL,&ctrlPoint1.world); //Use the world matrix stored for each control point
// Transform ray origin and direction by inv matrix
D3DXVECTOR3 rayObjOrigin,rayObjDirection;
D3DXVec3TransformCoord(&rayObjOrigin,&ray.origin,&matInverse);
D3DXVec3TransformNormal(&rayObjDirection,&ray.direction,&matInverse);
D3DXVec3Normalize(&rayObjDirection,&rayObjDirection);
//Check for an intersection between ray and control point mesh
BOOL hit=0;
D3DXIntersect(
ctrlPoint1.mesh,
&rayObjOrigin,
&rayObjDirection,
&hit, NULL, NULL, NULL, NULL, NULL, NULL);
if(hit==1) //If there is a hit
{
//Display the point we hit and the screen position which was clicked on
char buffer[256];
sprintf(buffer,"Point %d: X-%ld, Y-%ld\n", i, cursorPos.x, cursorPos.y);
::MessageBox(0, buffer, 0, 0);
ctrlPoint.selected=true; //Set the control point to have been selected
}
}
}