|
|
发表于 2006-8-12 19:35:00
|
显示全部楼层
Re:求3d透视投影后对齐次齐坐标裁减算法的内容
在很多计算机图形学的书后面的附录里都有写~
透视投影生成的矩阵R(如:OpenGL中的glFrustum( l, r, b, t, n ,f) ):
| 2n/(r-l), 0, (r+l)/(r-l), 0|
R = | 0, 2n/(t-b), (t+b)/(t-b), 0|
| 0, 0, -(f+n)/(f-n), -2fn/(f-n)|
| 0, 0, -1, 0|
仅当 l != r, t != b, n != f 时, 矩阵R才存在
然后通过几个矩阵求出组成视锥的6个剪切面的平面方程的系数, 将要剪切的点分别代入6个方程, 如果值大于0,则点在视锥之外,小于0在视锥之内, 等于0则在剪切面上.
//获得剪切板6个面的方程系数
void CCamera::UpdateFrustumClipBoard()
{
GLfloat clip[16]; //用来存储剪切矩阵
GLfloat proj[16]; //用来存储投影矩阵
GLfloat modl[16]; //用来存储模型-视点矩阵
GLfloat t;
// 获得当前的投影矩阵
glGetFloatv( GL_PROJECTION_MATRIX, proj );
// 获得当前的模型-视点矩阵
glGetFloatv( GL_MODELVIEW_MATRIX, modl );
//用模型矩阵乘以投影矩阵得到剪切矩阵
clip[ 0] = modl[ 0] * proj[ 0];
clip[ 1] = modl[ 1] * proj[ 5];
clip[ 2] = modl[ 2] * proj[10] + modl[ 3] * proj[14];
clip[ 3] = modl[ 2] * proj[11];
clip[ 4] = modl[ 4] * proj[ 0];
clip[ 5] = modl[ 5] * proj[ 5];
clip[ 6] = modl[ 6] * proj[10] + modl[ 7] * proj[14];
clip[ 7] = modl[ 6] * proj[11];
clip[ 8] = modl[ 8] * proj[ 0];
clip[ 9] = modl[ 9] * proj[ 5];
clip[10] = modl[10] * proj[10] + modl[11] * proj[14];
clip[11] = modl[10] * proj[11];
clip[12] = modl[12] * proj[ 0];
clip[13] = modl[13] * proj[ 5];
clip[14] = modl[14] * proj[10] + modl[15] * proj[14];
clip[15] = modl[14] * proj[11];
// 获得右剪切面的系数
m_Frustum[0][0] = clip[ 3] - clip[ 0];
m_Frustum[0][1] = clip[ 7] - clip[ 4];
m_Frustum[0][2] = clip[11] - clip[ 8];
m_Frustum[0][3] = clip[15] - clip[12];
// 把结果单位化
t = GLfloat(sqrt( m_Frustum[0][0] * m_Frustum[0][0] + m_Frustum[0][1] *
m_Frustum[0][1] + m_Frustum[0][2] * m_Frustum[0][2] ));
m_Frustum[0][0] /= t;
m_Frustum[0][1] /= t;
m_Frustum[0][2] /= t;
m_Frustum[0][3] /= t;
// 获得左剪切面的系数
m_Frustum[1][0] = clip[ 3] + clip[ 0];
m_Frustum[1][1] = clip[ 7] + clip[ 4];
m_Frustum[1][2] = clip[11] + clip[ 8];
m_Frustum[1][3] = clip[15] + clip[12];
// 把结果单位化
t = GLfloat(sqrt( m_Frustum[1][0] * m_Frustum[1][0] + m_Frustum[1][1] *
m_Frustum[1][1] + m_Frustum[1][2] * m_Frustum[1][2] ));
m_Frustum[1][0] /= t;
m_Frustum[1][1] /= t;
m_Frustum[1][2] /= t;
m_Frustum[1][3] /= t;
// 获得下剪切面的系数
m_Frustum[2][0] = clip[ 3] + clip[ 1];
m_Frustum[2][1] = clip[ 7] + clip[ 5];
m_Frustum[2][2] = clip[11] + clip[ 9];
m_Frustum[2][3] = clip[15] + clip[13];
// 把结果单位化
t = GLfloat(sqrt( m_Frustum[2][0] * m_Frustum[2][0] + m_Frustum[2][1] *
m_Frustum[2][1] + m_Frustum[2][2] * m_Frustum[2][2] ));
m_Frustum[2][0] /= t;
m_Frustum[2][1] /= t;
m_Frustum[2][2] /= t;
m_Frustum[2][3] /= t;
// 获得上剪切面的系数
m_Frustum[3][0] = clip[ 3] - clip[ 1];
m_Frustum[3][1] = clip[ 7] - clip[ 5];
m_Frustum[3][2] = clip[11] - clip[ 9];
m_Frustum[3][3] = clip[15] - clip[13];
// 把结果单位化
t = GLfloat(sqrt( m_Frustum[3][0] * m_Frustum[3][0] + m_Frustum[3][1] *
m_Frustum[3][1] + m_Frustum[3][2] * m_Frustum[3][2] ));
m_Frustum[3][0] /= t;
m_Frustum[3][1] /= t;
m_Frustum[3][2] /= t;
m_Frustum[3][3] /= t;
// 获得远剪切面的系数
m_Frustum[4][0] = clip[ 3] - clip[ 2];
m_Frustum[4][1] = clip[ 7] - clip[ 6];
m_Frustum[4][2] = clip[11] - clip[10];
m_Frustum[4][3] = clip[15] - clip[14];
// 把结果单位化
t = GLfloat(sqrt( m_Frustum[4][0] * m_Frustum[4][0] + m_Frustum[4][1] *
m_Frustum[4][1] + m_Frustum[4][2] * m_Frustum[4][2] ));
m_Frustum[4][0] /= t;
m_Frustum[4][1] /= t;
m_Frustum[4][2] /= t;
m_Frustum[4][3] /= t;
// 获得近剪切面的系数
m_Frustum[5][0] = clip[ 3] + clip[ 2];
m_Frustum[5][1] = clip[ 7] + clip[ 6];
m_Frustum[5][2] = clip[11] + clip[10];
m_Frustum[5][3] = clip[15] + clip[14];
// 把结果单位化
t = GLfloat(sqrt( m_Frustum[5][0] * m_Frustum[5][0] + m_Frustum[5][1] *
m_Frustum[5][1] + m_Frustum[5][2] * m_Frustum[5][2] ));
m_Frustum[5][0] /= t;
m_Frustum[5][1] /= t;
m_Frustum[5][2] /= t;
m_Frustum[5][3] /= t;
}
//判断点是否在视锥之内,是则返回TRUE
bool CCamera: ointInFrustum(GLfloat x, GLfloat y, GLfloat z, GLfloat fRadius, int nMode)
{
for(int i = 0; i < 6; i++)
{
//判断点与平面的关系
if(m_Frustum[0] * x + m_Frustum[1] * y + m_Frustum[2] * z +
m_Frustum[3] <= -fRadius)
{
return(FALSE);
}
}
return(TRUE);
}
就是这样了, 如果你数学不错的话, 那么你可以把那两个矩阵写出来,然后按照这种法则写一下,应该会弄懂, 如果你知道了为什么要这样写, 请告诉我, 我到现在也每弄明白呢. |
|