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

场景管理(三):视锥对视野的裁剪

Posted on 2011-07-04 13:21  +石头+  阅读(1224)  评论(0)    收藏  举报

场景中不是对每个物体都进行渲染,如果对摄像机后面的物体也进行渲染的换就大大降低了效率,我们把视角看成一个视锥,每次只是渲染视锥里面的物体,这样效率就大大提高了。D3D中视野矩阵和投影矩阵结合为一个Z方向为(0,1)XY方向为(-1,1)的长方体包围合。我们就以视野投影矩阵的原点为中心,Z为1的面为地面做一个视锥,如在视锥里面就确定渲染,要想把物体转换到视野投影矩阵中,首先要对视野投影矩阵进行要判断的坐标的视野投影矩阵的逆变换(相当于物体经过视野世界矩阵的变化到这个小盒子中,那么要想看一个经过变化后的世界坐标是否在视野内,可以把小盒子做此点的逆变换,相当于把盒子变化到了世界矩阵中),然后只要判断坐标是否在视锥的左右后这3个面内即可。表示视锥的结构体如下:

Struct EYECILPER

{

    D3DXPLANE[6] mPlane;            //视野投影矩阵的6个面

    D3DVECTOR[8] mVector;            //视野投影矩阵的8个顶点

    Bool    IsInEye(D3DVECTOR Pos);        //判断点Pos是否在视锥内

    Void     Update(D3DXMATRIX *EyeMat);    //根据眼睛的视野投影矩阵,把盒子做此矩阵的逆变换,变化到世界坐标系中。

}

Update函数为眼睛每次设置投影,视野矩阵时使用,每次渲染之前都调用眼睛的SetView,在SetView中调用Update函数,在眼睛创建时,创建EYECILPER。

每个物体的渲染时都要判断是否在视锥内,所以把EYECILPER写进CXWorldOBJ中写成静态变量,方便调用。

bool EYECLIPER::IsInEye( D3DVECTOR Pos )

{

    float d=0;

    d=D3DXPlaneDotCoord(&m_plane[3] ,(D3DXVECTOR3*)&Pos);

    if (d>5) return false;

    d=D3DXPlaneDotCoord(&m_plane[4] ,(D3DXVECTOR3*)&Pos);

    if (d>5) return false;

    d=D3DXPlaneDotCoord(&m_plane[5] ,(D3DXVECTOR3*)&Pos);

    if (d>5) return false;

    return true;

}

 

void EYECLIPER::Update( D3DXMATRIX *EyeMat)

{

    D3DXMATRIX matInv;

    D3DXVECTOR3 VexBox[8];

    D3DXMatrixInverse(&matInv,NULL,EyeMat);

    for(int i = 0; i < 8;++i)

    {

        D3DXVec3TransformCoord(&VexBox[i],&m_vtx[i],&matInv);

    }

    D3DXVECTOR3 m_vPos;

    m_vPos = (VexBox[0] + VexBox[5]) / 2.0f;//中心Pos

    D3DXPlaneFromPoints( &m_plane[0], VexBox+4, VexBox+7, VexBox+6 );    // 上平面(top)

    D3DXPlaneFromPoints( &m_plane[1], VexBox , VexBox+1, VexBox+2 );    // 下平面(bottom)

    D3DXPlaneFromPoints( &m_plane[2], VexBox , VexBox+4, VexBox+5 );    // 近平面(near)

    D3DXPlaneFromPoints( &m_plane[3], VexBox+2, VexBox+6, VexBox+7 );    // 远平面(far)

    D3DXPlaneFromPoints( &m_plane[4], VexBox+3, VexBox+7, VexBox+4 );    // 左平面(left)

    D3DXPlaneFromPoints( &m_plane[5], VexBox+1, VexBox+5, VexBox+6 );    // 右平面(right)

}