c ++ pick功能不起作用

时间:2010-11-15 20:21:52

标签: c++ winapi visual-c++ directx

我有这个拣选功能,但它似乎不起作用。如果函数与对象发生碰撞但返回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

2 个答案:

答案 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函数)。