我有这个拣选功能,但它似乎不起作用。如果函数与对象发生碰撞但返回0,则该函数应返回true;它永远不会改变 这是我的选择功能
BOOL D3dDevice::Picking(HWND hWnd, LPDIRECT3DDEVICE9 d3ddev, CXFileEntity *entity)
{
D3DXVECTOR3 v;
D3DXMATRIX matProj;
POINT pt;
D3DVIEWPORT9 vp;
GetCursorPos(&pt);
ScreenToClient(hWnd, &pt);
d3ddev->GetTransform(D3DTS_PROJECTION, &matProj);
d3ddev->GetViewport(&vp);
v.x = ( ( ( 2.0f * pt.x ) / vp.Height ) - 1 ) / matProj._11;
v.y = -( ( ( 2.0f * pt.x ) / vp.Width ) - 1 ) / matProj._22;
v.z = 1.0f;
D3DXMATRIX m;
D3DXVECTOR3 rayOrigin,rayDir;
D3DXMATRIX matView;
d3ddev->GetTransform(D3DTS_VIEW, &matView);
D3DXMatrixInverse( &m, NULL, &matView );
// Transform the screen space pick ray into 3D space
rayDir.x = v.x*m._11 + v.y*m._21 + v.z*m._31;
rayDir.y = v.x*m._12 + v.y*m._22 + v.z*m._32;
rayDir.z = v.x*m._13 + v.y*m._23 + v.z*m._33;
rayOrigin.x = m._41;
rayOrigin.y = m._42;
rayOrigin.z = m._43;
// Use inverse of matrix
D3DXMATRIX matInverse, matWorld;
d3ddev->GetTransform(D3DTS_WORLD, &matWorld);
// Use inverse of matrix
D3DXMatrixInverse(&matInverse,NULL,&matWorld);
// Transform ray origin and direction by inv matrix
D3DXVECTOR3 rayObjOrigin,rayObjDirection, rayDirection;
D3DXVec3TransformCoord(&rayObjOrigin,&rayOrigin,&matInverse);
D3DXVec3TransformNormal(&rayObjDirection,&rayDirection,&matInverse);
D3DXVec3Normalize(&rayObjDirection,&rayObjDirection);
BOOL hasHit;
float distanceToCollision;
D3DXIntersect(entity->pDrawMesh, &rayObjOrigin, &rayObjDirection, &hasHit, NULL, NULL, NULL, &distanceToCollision, NULL, NULL);
return hasHit;
}
注意:我的pDrawMesh是可变的LPD3DXMESH而不是LPD3DXBASEMESH会有什么不同? 的更新
BOOL D3dDevice::Picking(HWND hWnd, LPDIRECT3DDEVICE9 d3ddev, CXFileEntity *entity)
{
D3DXVECTOR3 v;
D3DXMATRIX matProj;
POINT pt;
D3DVIEWPORT9 vp;
D3DXMATRIX matInverse, matWorld;
D3DXMATRIX m;
D3DXVECTOR3 rayOrigin,rayDir;
D3DXMATRIX matView;
D3DXVECTOR3 rayObjSpace;
D3DXVECTOR3 rayObjOrigin,rayObjDirection, rayDirection;
GetCursorPos(&pt);
ScreenToClient(hWnd, &pt);
d3ddev->GetTransform(D3DTS_PROJECTION, &matProj);
d3ddev->GetViewport(&vp);
d3ddev->GetTransform(D3DTS_VIEW, &matView);
// Use inverse of matrix
d3ddev->GetTransform(D3DTS_WORLD, &matWorld);
D3DXVECTOR3 vec3( pt.x, pt.y, 1.0f );
D3DXVec3Unproject( &rayObjSpace, &vec3, &vp, &matProj, &matView, &matWorld );
// Transform ray origin and direction by inv matrix
D3DXMATRIX invWorld;
D3DXMatrixInverse( &invWorld, NULL, &matWorld );
D3DXVECTOR3 camObjSpace;
D3DXVECTOR3 camPos(0.0, 0.0, -14.0f);
D3DXVec3TransformCoord( &camObjSpace, &camPos, &invWorld );
rayDir = rayObjSpace - camObjSpace;
BOOL hasHit;
float distanceToCollision;
if(FAILED(D3DXIntersect(entity->pDrawMesh, &rayObjSpace, &rayDir, &hasHit, NULL, NULL, NULL, &distanceToCollision, NULL, NULL)))
{
PostQuitMessage(0);
};
if(hasHit==1)
{
PostQuitMessage(0);
}
return hasHit;
}
更新2: 现在它不相交; /。 BOOL D3dDevice :: Picking(HWND hWnd,LPDIRECT3DDEVICE9 d3ddev,CXFileEntity * entity,int z) { D3DXVECTOR3 v; POINT pt; D3DVIEWPORT9 vp; D3DXMATRIX matInverse,matWorld,m,matView,matProj;
GetCursorPos(&pt);
ScreenToClient(hWnd, &pt);
d3ddev->GetTransform(D3DTS_PROJECTION, &matProj);
d3ddev->GetViewport(&vp);
d3ddev->GetTransform(D3DTS_WORLD, &matWorld);
d3ddev->GetTransform(D3DTS_VIEW, &matView);
// Use inverse of matrix
D3DXVECTOR3 rayPos(pt.x, pt.y,0); // near-plane position
D3DXVECTOR3 rayDir(pt.x, pt.x,1); // far-plane position
D3DXVec3Unproject(&rayPos,&rayPos,&vp,&matProj,&matView,&matWorld);
D3DXVec3Unproject(&rayDir,&rayDir,&vp,&matProj,&matView,&matWorld);
rayDir -= rayPos; // make a direction from the 2 positions
D3DXVec3Normalize(&rayDir,&rayDir); // don't know if this is necessary.
// Transform ray origin and direction by inv matrix
BOOL hasHit;
float distanceToCollision;
if(FAILED(D3DXIntersect(entity->pDrawMesh, &rayPos, &rayDir, &hasHit, NULL, NULL, NULL, &distanceToCollision, NULL, NULL)))
{
PostQuitMessage(0);
};
if(hasHit!=0)
PostQuitMessage(0);
return hasHit;
}
更新3: 好了,它总是相交; /在更改此函数中的值之后
D3DXMatrixPerspectiveFovLH(&matProjection,
D3DXToRadian(45), // the horizontal field of view
(FLOAT)Width / (FLOAT)Height, // aspect ratio
0.0f, // the near view-plane
1.0f); // the far view-plane
答案 0 :(得分:4)
Ray采摘很有趣。您基本上需要通过将屏幕坐标转换为投影空间来开始。由于DirectX投影空间(对于x,y)在x和y中的范围是-1到1,因此您需要执行以下操作。
float px = (((float)mousex / SCREEN_WIDTH) * 2.0f) - 1.0f;
float py = -(((float)mousey / SCREEN_HEIGHT) * 2.0f) - 1.0f;
不是py在前面有负数,因为屏幕坐标从上到下,投影空间相反。
您现在拥有投影空间的位置。所以你需要沿着这一点创建一个向量。值得庆幸的是,这也很好。
float pz = 1.0f;
现在我们可以将其反投影回对象空间:
D3DXVECTOR3 rayObjSpace;
D3DXVec3Unproject( &rayObjSpace, &rayOut, &viewport, &projectionMatrix, &viewMatrix, &worldMatrix );
最后将其插入D3DXIntersect并准备好了:)
编辑:我确实发现上面的解释存在错误。事实上,使用D3DXVec3Unproject,您可以传入实际屏幕坐标x,y,其中z为1。
所以:
D3DXVECTOR3 vec3( mousex, mousey, 1.0f );
D3DXVECTOR3 rayObjSpace;
D3DXVec3Unproject( &rayObjSpace, &vec3, &viewport, &projectionMatrix, &viewMatrix, &worldMatrix );
更简单。因为它是视图端口转换应用两次。
那说你真的看过你回来的光线向量吗?他们甚至指向对象吗?
编辑2:好吧我会更具体。现在,您拥有点击点的世界位置,您可以通过执行以下操作来计算光线方向。
D3DXMATRIX invWorld;
D3DXMatrixInverse( &invWorld, NULL, &world );
D3DXVECTOR3 camObjSpace;
D3DXVec3TransformCoord( &camObjSpace, &camPos, &invWorld );
D3XVECTOR3 rayDir = rayObjSpace - camObjSpace;
BOOL bHit = FALSE;
float distToHit = true;
HRESULT hr = D3DXIntersect( pMesh, &rayObjSpace, &rayDir, &bHit, NULL, NULL, NULL, &distToHit, NULL, NULL );
答案 1 :(得分:0)
设置hasHit的逻辑在D3DXIntersect中,我们看不到。还有一些我们看不到的其他函数(看起来像C函数)。