3D Object selection - help needed!!
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;
}
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
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
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;
}
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;
}
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement