场景中不是对每个物体都进行渲染,如果对摄像机后面的物体也进行渲染的换就大大降低了效率,我们把视角看成一个视锥,每次只是渲染视锥里面的物体,这样效率就大大提高了。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)
}