Archived

This topic is now archived and is closed to further replies.

strahan

3D Object selection - help needed!!

Recommended Posts

My routine to select an object in 3D is failing. I am using the same code you can find in directx SDK sample "pick". Can anyone know what I might be doing wrong? Here is my function: Thanks in advance for your help! HRESULT CObject::SelectObject(HWND hWnd) { D3DXMATRIX matProj; D3DXVECTOR3 vPickRayDir; D3DXVECTOR3 vPickRayOrig; D3DXMATRIX matView; D3DXMATRIX m; BOOL bHit; DWORD dwFace; FLOAT fBary1; FLOAT fBary2; FLOAT fDist; HRESULT hr = E_FAIL; LPDIRECT3DSURFACE8 pBackBuffer; D3DSURFACE_DESC d3dsdBackBuffer; m_pD3DDevice->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer); pBackBuffer->GetDesc(&d3dsdBackBuffer); pBackBuffer->Release(); m_pD3DDevice->GetTransform(D3DTS_PROJECTION, &matProj); m_pD3DDevice->GetTransform(D3DTS_VIEW, &matView); // Get the inverse view matrix D3DXMatrixInverse(&m, NULL, &matView); POINT ptCursor; GetCursorPos(&ptCursor); ScreenToClient(hWnd, &ptCursor); int nCursorX = ptCursor.x; int nCursorY = ptCursor.y; // Compute the vector of the pick ray in screen space D3DXVECTOR3 v; v.x = (((2.0f * nCursorX) / d3dsdBackBuffer.Width) - 1) / matProj._11; v.y = -(((2.0f * nCursorY) / d3dsdBackBuffer.Height) - 1) / matProj._22; v.z = 1.0f; // 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; LPD3DXBASEMESH pMesh = m_pMesh->GetMesh(); hr = D3DXIntersect(pMesh, &vPickRayOrig, &vPickRayDir, &bHit, &dwFace, &fBary1, &fBary2, &fDist, NULL, NULL); // BUG BUG - bHit is ALWAYS FALSE if(SUCCEEDED(hr) && bHit == TRUE) { // Toggle Selection m_bSelected = !m_bSelected; } return hr; }

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Hi!

Make sure you are not running in PUREDEVICE mode - "GetTransform" doesn''t work in this mode. I use the same code in a project but i create the view- and projection matrix myself, so i don''t need "GetTransform" to obtain the matrices.

The code for "D3DXIntersect" is missing, so i dont know what you are doing there. I know the source from the DX9 SDK, but your parameters are a bit different.
Well, the routine i know checks against the untransformed mesh at x=0,y=0,z=0 w/o rotation or move (rotating only the camera). If you placed your mesh i.e. at x=2,y=2,z=2 and you want to "click it on the screen", then you have to transform the mesh''s vertices (pMesh in your code) with the world matrix in this routine before you can "select" it, or a face, with the "vPickRay".

Hope it helps,

Codex

Share this post


Link to post
Share on other sites
You are a genius! My routine now works thanks!

I set the world transform to my objects world matrix before testing selection on the object:

hr = m_pD3DDevice->SetTransform(D3DTS_WORLD, GetMatrix(m_pD3DDevice));

This, however, by itself did not do it. I also had to add this code (i found this in someone''s demo):

D3DXVECTOR3 vNear,vDir;
D3DXMATRIX invMat;
D3DXMatrixInverse(&invMat,NULL,GetMatrix(m_pD3DDevice));
D3DXVec3TransformCoord(&vNear,&vPickRayOrig,&invMat);
D3DXVec3TransformNormal(&vDir,&vPickRayDir,&invMat);

I''m not certain why this is necessary though. Any ideas?

Total code snipet:


HRESULT CObject::SelectObject(HWND hWnd)
{
D3DXMATRIX matProj;
D3DXVECTOR3 vPickRayDir;
D3DXVECTOR3 vPickRayOrig;
D3DXMATRIX matView;
D3DXMATRIX m;
BOOL bHit;
HRESULT hr = E_FAIL;

LPDIRECT3DSURFACE8 pBackBuffer;
D3DSURFACE_DESC d3dsdBackBuffer;
m_pD3DDevice->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer);
pBackBuffer->GetDesc(&d3dsdBackBuffer);
pBackBuffer->Release();

hr = m_pD3DDevice->SetTransform(D3DTS_WORLD, GetMatrix(m_pD3DDevice));

m_pD3DDevice->GetTransform(D3DTS_PROJECTION, &matProj);
m_pD3DDevice->GetTransform(D3DTS_VIEW, &matView);

// Get the inverse view matrix
D3DXMatrixInverse(&m, NULL, &matView);

POINT ptCursor;
GetCursorPos(&ptCursor);
ScreenToClient(hWnd, &ptCursor);
int nCursorX = ptCursor.x;
int nCursorY = ptCursor.y;

// Compute the vector of the pick ray in screen space
D3DXVECTOR3 v;
v.x = (((2.0f * nCursorX) / d3dsdBackBuffer.Width) - 1) / matProj._11;
v.y = -(((2.0f * nCursorY) / d3dsdBackBuffer.Height) - 1) / matProj._22;
v.z = 1.0f;

// 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;

LPD3DXBASEMESH pMesh = m_pMesh->GetMesh();

D3DXVECTOR3 vNear,vDir;
D3DXMATRIX invMat;
D3DXMatrixInverse(&invMat,NULL,GetMatrix(m_pD3DDevice));
D3DXVec3TransformCoord(&vNear,&vPickRayOrig,&invMat);
D3DXVec3TransformNormal(&vDir,&vPickRayDir,&invMat);

// test for intersection
DWORD dwIndex;
float b1,b2;
float dist;
D3DXIntersect(pMesh,&vNear,&vDir,&bHit,&dwIndex,&b1,&b2,&dist,NULL,NULL);

if(SUCCEEDED(hr) && bHit == TRUE)
{
m_bSelected = !m_bSelected;
}
else
{
hr = E_FAIL;
}

return hr;
}


Share this post


Link to post
Share on other sites