# 游戏中鼠标拾取方法

1. 获取当前的转换矩阵，包括 projection, view, 和 world

void detect_picking()
{
// get the current transform matrices
D3DXMATRIX matProjection, matView, matWorld;
d3ddev->GetTransform(D3DTS_PROJECTION, &matProjection);
d3ddev->GetTransform(D3DTS_VIEW, &matView);
d3ddev->GetTransform(D3DTS_WORLD, &matWorld);
}

2. 把鼠标的坐标转换为鼠标的角度

GetCursorPos(&MousePos);

float xAngle = (((2.0f * MousePos.x) / SCREEN_WIDTH) - 1.0f) / matProjection(0, 0);
float yAngle = (((-2.0f * MousePos.y) / SCREEN_HEIGHT) + 1.0f) / matProjection(1, 1);

3. 找到逆转换矩阵

void detect_picking(){    // get the current transform matrices    D3DXMATRIX matProjection, matView, matWorld, matInverse;    d3ddev->GetTransform(D3DTS_PROJECTION, &matProjection);    d3ddev->GetTransform(D3DTS_VIEW, &matView);    d3ddev->GetTransform(D3DTS_WORLD, &matWorld);    // use the mouse coordinates to get the mouse angle    GetCursorPos(&MousePos);    float xAngle = (((2.0f * MousePos.x) / SCREEN_WIDTH) - 1.0f) / matProjection(0, 0);    float yAngle = (((-2.0f * MousePos.y) / SCREEN_HEIGHT) + 1.0f) / matProjection(1, 1);    D3DXVECTOR3 origin, direction;    origin = D3DXVECTOR3(0.0f, 0.0f, 0.0f);    direction = D3DXVECTOR3(xAngle, yAngle, 1.0f);    // find the inverse matrix    D3DXMatrixInverse(&matInverse, NULL, &(matWorld * matView));}
}

4. 使用逆矩阵把鼠标的方向位置转化为模型空间位置

void detect_picking()
{
// get the current transform matrices
D3DXMATRIX matProjection, matView, matWorld, matInverse;
d3ddev->GetTransform(D3DTS_PROJECTION, &matProjection);
d3ddev->GetTransform(D3DTS_VIEW, &matView);
d3ddev->GetTransform(D3DTS_WORLD, &matWorld);

// use the mouse coordinates to get the mouse angle
GetCursorPos(&MousePos);
float xAngle = (((2.0f * MousePos.x) / SCREEN_WIDTH) - 1.0f) / matProjection(0, 0);
float yAngle = (((-2.0f * MousePos.y) / SCREEN_HEIGHT) + 1.0f) / matProjection(1, 1);

D3DXVECTOR3 origin, direction;
origin = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
direction = D3DXVECTOR3(xAngle, yAngle, 1.0f);

// find the inverse matrix
D3DXMatrixInverse(&matInverse, NULL, &(matWorld * matView));

// convert origin and direction into model space
D3DXVec3TransformCoord(&origin, &origin, &matInverse);
D3DXVec3TransformNormal(&direction, &direction, &matInverse);
D3DXVec3Normalize(&direction, &direction);
}

HRESULT D3DXIntersect(LPD3DXBASEMESH pMesh,    // pointer to the mesh to check
D3DXVECTOR3* pRayPos,    // pointer to the origin
D3DXVECTOR3* pRayDir,    // pointer to the direction
BOOL* pHit,    // a boolean telling if the mesh was selected
DWORD* pFaceIndex,    // tells which selected triangle was closest
FLOAT* pU,    // tells the U coordinate of that triangle
FLOAT* pV,    // tells the V coordinate of that triangle
FLOAT* pDist,    // a value telling how far from the camera the face is
LPD3DXBUFFER* ppAllHits,    // a buffer telling all picked faces
DWORD* pCountOfHits);    // tells how many faces were picked

void detect_picking()
{
// get the current transform matrices
D3DXMATRIX matProjection, matView, matWorld, matInverse;
d3ddev->GetTransform(D3DTS_PROJECTION, &matProjection);
d3ddev->GetTransform(D3DTS_VIEW, &matView);
d3ddev->GetTransform(D3DTS_WORLD, &matWorld);

// use the mouse coordinates to get the mouse angle
GetCursorPos(&MousePos);
float xAngle = (((2.0f * MousePos.x) / SCREEN_WIDTH) - 1.0f) / matProjection(0, 0);
float yAngle = (((-2.0f * MousePos.y) / SCREEN_HEIGHT) + 1.0f) / matProjection(1, 1);

D3DXVECTOR3 origin, direction;
origin = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
direction = D3DXVECTOR3(xAngle, yAngle, 1.0f);

// find the inverse matrix
D3DXMatrixInverse(&matInverse, NULL, &(matWorld * matView));

// convert origin and direction into model space
D3DXVec3TransformCoord(&origin, &origin, &matInverse);
D3DXVec3TransformNormal(&direction, &direction, &matInverse);
D3DXVec3Normalize(&direction, &direction);

// detect picking
BOOL hit;
D3DXIntersect(meshTeapot, &origin, &direction, &hit, NULL, NULL, NULL, NULL, NULL, NULL);
if(hit)
d3ddev->SetRenderState(D3DRS_LIGHTING, FALSE);
else
d3ddev->SetRenderState(D3DRS_LIGHTING, TRUE);
}

		const ITexture* tex = pRenderSys->getRenderTargetTexture(renderTargetID);
PixelBox dstBox(w,h,1,PF_A8R8G8B8, mpData);
//tex->blitToMemory(Box(0,0,0,w,h,1), dstBox);
if( !tex->blitToMemory(Box(0,0,0,w,h,1), dstBox) )
{
memset(mpData, 0, sizeof(uint) * w * h );
}

	int Selector::rectHitTest( const Vector2& leftTop, const Vector2& rightBottom, std::vector<Result>& outList )
{
if(leftTop.x < 0 || leftTop.x > 1.0f || leftTop.y < 0 || leftTop.y > 1.0f)
return 0;

if(rightBottom.x < 0 || rightBottom.x > 1.0f || rightBottom.y < 0 || rightBottom.y > 1.0f)
return 0;

int w = sResoluctions[mLevel].x;
int h = sResoluctions[mLevel].y;

int lx = (int)(leftTop.x * w);
int ty = (int)(leftTop.y * h);
int rx = (int)(rightBottom.x * w);
int by = (int)(rightBottom.y * h);

lx = Clamp(lx, 0, w - 1);
ty = Clamp(ty, 0, h - 1);
rx = Clamp(rx, 0, w - 1);
by = Clamp(by, 0, h - 1);

std::set<uint> selSet;
for(int i = lx; i < rx; ++i)
{
for(int j = ty; j < by; ++j)
{
uint v = mpData[w * j + i];
if (v != 0 && selSet.find(v) == selSet.end())
{
Result rt;
fillResult(v, rt);
outList.push_back(rt);
selSet.insert(v);
}
}
}

return (int)outList.size();
}

Reference：

http://www.directxtutorial.com/Lesson.aspx?lessonid=9-8-4