博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

射线碰撞

Posted on 2011-04-22 20:29  +石头+  阅读(1129)  评论(0)    收藏  举报

检查射线碰撞主要用到的是Direct中的D3DXIntersect函数。

HRESULT D3DXIntersect(

__in LPD3DXBASEMESH pMesh,            //碰撞模型的Mesh

__in const D3DXVECTOR3 *pRayPos,    //射线的位置

__in const D3DXVECTOR3 *pRayDir,        //射线的方向

__out BOOL *pHit,                //是否碰撞到

__out DWORD *pFaceIndex,            //碰撞到面的索引    

__out FLOAT *pU,                //面的U坐标

__out FLOAT *pV,                //面的V坐标

__out FLOAT *pDist,                //射线到碰撞点的距离

__out LPD3DXBUFFER *ppAllHits,        //如果碰撞到多个点,返回这些点缓存的头指针(D3DXINTERSECTINFO类型的结构体)

__out DWORD *pCountOfHits            //碰撞到多少个点

);

我在CMeshBaseOBJ类中重新封装了检测碰撞的函数,返回的结构体CInterSect比D3DXINTERSECTINFO多了法线的结构,用来解决当物体上坡时,多个退的物体移动时需要改变上方向的问题。

struct CInterSect

{

    DWORD FaceIndex;

    float Dist;

    D3DXVECTOR3 FaceNormal;

    float u, v;

};

//参数分别为射线位置,方向,是否计算法线,返回碰撞的结果体

bool CMeshBaseOBJ::CheckInterSect( D3DXVECTOR3 Pos, D3DXVECTOR3 Dir, bool CanComputerNormal, CInterSect *pInterSect )

{

    if(!mMesh)

    {

        return false;

    }

    if(!pInterSect)

    {

        return false;

    }

    BOOL bRes;

    HRESULT hr = D3DXIntersect(mMesh, &Pos, &Dir,

                    &bRes,&pInterSect->FaceIndex,

                    &pInterSect->u, &pInterSect->v,

                    &pInterSect->Dist, NULL, NULL);

    if(FAILED(hr))

    {

        return bRes;

    }

    D3DVECTOR V[3];

    DWORD I[3];

    if(!mMeshForVector)

    {

        ResetMeshForVector();

    }

    if(CanComputerNormal)

    {

        if(mMeshForVector)

        {

            DWORD *pIB;

            hr = mMeshForVector->LockIndexBuffer(D3DLOCK_READONLY, (void**)&pIB);

            if(FAILED(hr))

            {

                return bRes;

            }

            I[0] = pIB[pInterSect->FaceIndex*3+0];

            I[1] = pIB[pInterSect->FaceIndex*3+1];

            I[2] = pIB[pInterSect->FaceIndex*3+2];

 

            mMeshForVector->UnlockIndexBuffer();

            D3DVECTOR *pVB;

            hr = mMeshForVector->LockVertexBuffer(D3DLOCK_READONLY, (void**)&pVB);

            if(FAILED(hr))

            {

                return bRes;

            }

            V[0] = pVB[I[0]];

            V[1] = pVB[I[1]];

            V[2] = pVB[I[2]];

            mMeshForVector->UnlockVertexBuffer();

            D3DXVECTOR3 V1, V2, Norm;

            V1 = D3DXVECTOR3(V[1]) - D3DXVECTOR3(V[0]);

            V2 = D3DXVECTOR3(V[2]) - D3DXVECTOR3(V[0]);

            D3DXVec3Cross(&Norm, &V1, &V2);

            D3DXVec3Normalize(&Norm, &Norm);

            pInterSect->FaceNormal = (D3DVECTOR)Norm;

 

        }

    }

    return bRes;

}    

这时在物体的渲染时,就可以加入检查和地图的碰撞。先用ForceOnMap函数来把一个物体固定在一个地图上

//pForceMap为地图的指针,ForeHeight为地图的高度,UWM为枚举类型表示是否物体的上方向随地形变化

void CXVisOBJ::ForceOnMap( void* pForceMap, float ForecHeight, UpOnWithMap UWM)

{

    mForcedMap = pForceMap;

    mForcedHeight = ForecHeight;

    mUWM = UWM;

}

然后再调用CXVisOBJ的Update方法来时时检查和地形的碰撞,并且根据枚举类型来决定物体是否上方向发生改变

void CXVisOBJ::Update( float fPass )

{

    //强制地的物理逻辑

    if(mForcedMap)

    {

        D3DXVECTOR3 Pos(mXPos.mPos.x, mXPos.mPos.y+50, mXPos.mPos.z), Dir(0, -1, 0);

        CInterSect InterSect;

        bool bHit = ((CMapCell*)mForcedMap)->CheckInterSect(Pos, Dir, mUWM == uwmMap, &InterSect);

        if(bHit)

        {

            float y = mXPos.mPos.y + 50 - InterSect.Dist+mForcedHeight;

            mXPos.mPos.y = y;

            if(mUWM == uwmAlways)

            {

                mXPos.SetUpWithDir(mUpWithMap);

            }

            else

            {

                mXPos.SetUpWithDir(InterSect.FaceNormal);

            }

            

        }

        

    }

}