Sign in to follow this  
stewypeza

pick ray in reverse

Recommended Posts

Hi. i have pick ray working now and what i want is that when a onject is clicked on the mouse will be position over the center of the object. I thought of doing this by finding the ray direction between the origin and the meshs center position in 3D space. Then reverse the usual pick ray sequence to find the co-ordinates of the mouse. Below is the code i have used for this
void Engine::positionMouseForPicked(LPDIRECT3DDEVICE9 g_pd3dDevice, D3DXVECTOR3 meshPos)
{

	D3DVIEWPORT9 m_mainViewport; 
	g_pd3dDevice->GetViewport( &m_mainViewport );
	
    D3DXMATRIX matProj;
    g_pd3dDevice->GetTransform( D3DTS_PROJECTION, &matProj );

    POINT ptCursor;
    GetCursorPos( &ptCursor );
    ScreenToClient( h_Wnd, &ptCursor );

	D3DXVECTOR3 rayOrigin,rayDir, v;
	D3DXMATRIX matView, m;

	if ( currentCamState == state_cam_deck1 )
	{
		rayOrigin.x = 0.0f; rayOrigin.y = 150.0f; rayOrigin.z = 0.0f;
	}

	float tempDiffX = meshPos.x - rayOrigin.x; 
	float tempDiffY = meshPos.y - rayOrigin.y; 
	float tempDiffZ = meshPos.z - rayOrigin.z;

	while ( tempDiffX > 1.0f || tempDiffX < -1.0f || tempDiffY > 1.0f || tempDiffY < -1.0f || tempDiffZ > 1.0f || tempDiffZ < -1.0f )
	{
		tempDiffX /= 1.005; tempDiffY /= 1.005; tempDiffZ /= 1.005;
	}
	
	rayDir.x = tempDiffX; rayDir.y = tempDiffY; rayDir.z = tempDiffZ;

	g_pd3dDevice->GetTransform( D3DTS_VIEW, &matView );
	D3DXMatrixInverse( &m, NULL, &matView );

	v.x = rayDir.x/m._11;
	v.y = (rayDir.y - m._32)/m._22;

	ptCursor.x = (((v.x * matProj._11) + 1)*m_mainViewport.Width)/2.0f; 
	ptCursor.y = ( m_mainViewport.Height * ( 1 - (v.y * matProj._22) ) ) / 2.0f;

	SetCursorPos( ptCursor.x, ptCursor.y );

}
The problem seems to be getting the ray direction correct. At present im dividing each vector component by 1.05 until each part is less than 1.0. This is inefficient and means that neither of the direction components can be greater than 1 which in some cases when ray picking it can be. I believe this to be the only reason why the function does not work. Is there a method to get a ray direction vector from two co-ordinates? It needs to be done in reverse so it obviously can not be found in the same way as the ray picking. Thank you Stuart EDIT: Please remember to use [source] tags... [Edited by - jollyjeffers on May 22, 2006 5:46:38 AM]

Share this post


Link to post
Share on other sites
I dont think your approach will work - purely from a mathematical standpoint.

Transforming from world->screen requires you to go World*View*Proj*ViewPort; going the other way around requires you use the inverse of that.

How about keeping it simple and using D3DXVec3Project() (Projects a 3D vector from object space into screen space.) and D3DXVec3Unproject() (Projects a vector from screen space into object space.)... you can then completely ignore the maths [grin]

Oh, and one other thing... careful with the GetTransform() calls - they wont work on a device created with the D3DCREATE_PUREDEVICE.

hth
Jack

Share this post


Link to post
Share on other sites
jollyjeffers thanks for the reply. Ive tried the project function and have created the new function for this mouse problem. The code is below

void Engine::positionMouseForPicked(LPDIRECT3DDEVICE9 g_pd3dDevice, D3DXVECTOR3 meshPos)
{

D3DXVECTOR3 vecScreen, vecSource(0.0f, 150.0f, 0.0f);
D3DXMATRIX matWorld, matProjection, matView, inv_matWorld, inv_matProjection, inv_matView;
D3DVIEWPORT9 vpScreen;

matWorld = pSlider[0].getWorldMatrix();
g_pd3dDevice->GetTransform(D3DTS_VIEW, &matView);
D3DXMatrixInverse(&inv_matView,NULL,&matView);
g_pd3dDevice->GetTransform(D3DTS_PROJECTION, &matProjection);
g_pd3dDevice->GetViewport(&vpScreen);

D3DXVec3Project(&vecScreen, &vecSource, &vpScreen, &matProjection, &inv_matView, &matWorld);

vecScreen.x;
vecScreen.y;

SetCursorPos( vecScreen.x, vecScreen.y );

}

The x co-ordinate for the mouse works perfectly but the y value keeps returning a negative number whic is incorrect. I have tried inversing the matrixs to see if that works but to no provail. Have i missed anything obvious or doing something wrong?

Cheers

Stuart

Share this post


Link to post
Share on other sites
If i dont inverse the view matrix i get massive values for x and y co-ords such as 107140. Whereas when i inverse it the x-value is correct

Share this post


Link to post
Share on other sites
As Endurion posted - you shouldn't be inversing that matrix. Something else is wrong...

You aren't checking the return codes on your GetTransform() calls - it could be that one of them is failing (remember what I originally said about pure devices [wink]) and returning junk.

Also, are you definitely 110% sure that the matrices and coordinates you're using are correct?

It is possible to get coordinates like you suggested, but they're often indicative of a world coordinate that is not actually visible (e.g. behind the camera or just simply out of view)....

One other minor thing - Please remember to use [source]...[/source] tags for your code fragments. I added them to your original post.

hth
Jack

Share this post


Link to post
Share on other sites
Quote:
Original post by stewypeza
sorry for the noob question but how else can you get the matrices without using GetTransform() calls
Store copies in system memory - at one point you're going to call SetTransform(), so just keep a copy of whatever you pass to it...

Bare in mind that Get**() calls are only a problem with pure devices, so if you're not using PD's then you've not got a problem.

hth
Jack

Share this post


Link to post
Share on other sites
Hey jolly, thanks for the help, got it working. The only problem now is that it doesn't take into account for rotation of the object. To select an object with the mouse works with the rotation but, to position the mouse on an object doesn;t work with rotation. The code positioning the mouse on the object where the problem is is shown below


D3DXVECTOR3 vecScreen;
D3DVIEWPORT9 vpScreen;
g_pd3dDevice->GetViewport(&vpScreen);

D3DXMATRIX matWorld, matProjection, matView;
g_pd3dDevice->GetTransform(D3DTS_WORLD, &matWorld);
g_pd3dDevice->GetTransform(D3DTS_VIEW, &matView);
g_pd3dDevice->GetTransform(D3DTS_PROJECTION, &matProjection);

vecPickSource = meshPos;
D3DXVec3Project(&vecScreen, &vecPickSource, &vpScreen, &matProjection, &matView, &matWorld);

SetCursorPos( vecScreen.x, vecScreen.y );




[Edited by - stewypeza on May 23, 2006 11:05:43 AM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this