Jump to content
  • Advertisement
Sign in to follow this  
John Matrix

Problems with Picking using D3DXIntersect()

This topic is 3907 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

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:
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
Then the sphere displayed at the point is created thus:
D3DXCreateSphere(gd3dDevice,
		 ctrlPoint.radius,
		 20,
		 20,
		 &ctrlPoint.mesh,
		 0);
and displayed:
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);
}
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:
//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
                     );
}
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:
//Update the view matrix representing the cameras new position/orientation.
D3DXMATRIX V;
camera->getViewMatrix(&V);
gd3dDevice->SetTransform(D3DTS_VIEW, &V);
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
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
		}
	} 
}
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. Screenshot

Share this post


Link to post
Share on other sites
Advertisement
Regarding GetTransform, if you use a pure device (D3DCREATE_PUREDEVICE), many 'get' methods, including this one, won't work. That's probably what's happening.

Regarding the picking, I'd suggest looking in the debugger at the rays you're testing in D3DXIntersect. If they look the same or similar for all your objects, then you're doing something wrong with the transform.

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!