LOD地形设计(五)

视截体是计算机图形学的关键内容之一,涉及裁剪、投影等内容,视截体分为长方体和平头椎体两种,前者关乎平行投影,后者关乎透视投影。但不论是哪一种,视截体都有六个面,在上节内容中,我介绍了视截体6个面求解的数学推导,这一节实现视截体的实际编程。

视截体类应该至少包含计算6个面的函数,判断一个正方体,球体,点是否在视截体内部的函数,平面法线标准化的函数,以及存储视截体各个面的系数的二维矩阵。

下面是视截体类的简单定义:

/*****************************************************************************************
*    Copyright Reserved By QingeSoftware
*    Author : QinGe
*    Filename : Frustum.h 1.0
*    Date: 2008-01-10
****************************************************************************************/

#pragma once
enum FrustumSide
{
    RIGHT = 0,                 //Right side
    LEFT  = 1,                 //left side
    BOTTOM= 2,                 //top side
    TOP   = 3,                 // back side
    BACK  = 4,                 //back side
    FRONT = 5                 // front side
};

enum PlaneNormal
{
    A = 0,                    // x value of normal ;
    B = 1,                    // y value of normal;
    C = 2,                    // z value of normal
    D = 3                    // distance of point to plane.
}  ;
class CFrustum
{
public:
    CFrustum(void);
    virtual ~CFrustum(void);
public:
    void CalculateFrustum();                                                      //计算视截体的6个面。
    BOOL CubeInFrustum(float x, float y, float z, float size);     //判断一个正方体是否在视截体内
    void NormalizePlane(float Frustum[6][4],int side);               //把法线标准化
private:
    float m_Frustum[6][4];                                                          //视截体6个面的方程

};

 

视截体类的实现文件:

/*****************************************************************************************
*    Copyright Reserved By QingeSoftware
*    Author : QinGe
*    Filename : Frustum.cpp 1.0
*    Date: 2008-01-10
****************************************************************************************/

#include "StdAfx.h"
#include "Frustum.h"
#include
CFrustum::CFrustum(void)
{

}

CFrustum::~CFrustum(void)
{
}

void CFrustum::NormalizePlane(float Frustum[6][4],int side)
{  

    //获取法线的模
    float manatude =sqrtf(Frustum[side][0]*Frustum[side][0]+   
                                       Frustum[side][1]*Frustum[side][1]+
                                       Frustum[side][2]*Frustum[side][2]);

    //单位化
    Frustum[side][0]/=manatude;
    Frustum[side][1]/=manatude;
    Frustum[side][2]/=manatude;
    Frustum[side][3]/=manatude;
}

 

//判断正方体是否在视截体内
BOOL CFrustum::CubeInFrustum(float x, float y, float z, float size)
{  
   //循环判断正方体的八个顶点是否全部在视截体一个面的后部
   //如果是,那么正方体肯定在视截体外部,返回FALSE;循环遍历六个面,如果找不到这样的面
   //则说明正方体至少有一个点在视截体内部。返回TRUE。
   for(int i = 0; i < 6; i++ )
    {
        if(m_Frustum[i][A] * (x - size) + m_Frustum[i][B] * (y - size) + m_Frustum[i][C] * (z - size) + m_Frustum[i][D] > 0)
           continue;
        if(m_Frustum[i][A] * (x + size) + m_Frustum[i][B] * (y - size) + m_Frustum[i][C] * (z - size) + m_Frustum[i][D] > 0)
           continue;
        if(m_Frustum[i][A] * (x - size) + m_Frustum[i][B] * (y + size) + m_Frustum[i][C] * (z - size) + m_Frustum[i][D] > 0)
           continue;
        if(m_Frustum[i][A] * (x + size) + m_Frustum[i][B] * (y + size) + m_Frustum[i][C] * (z - size) + m_Frustum[i][D] > 0)
           continue;
        if(m_Frustum[i][A] * (x - size) + m_Frustum[i][B] * (y - size) + m_Frustum[i][C] * (z + size) + m_Frustum[i][D] > 0)
           continue;
        if(m_Frustum[i][A] * (x + size) + m_Frustum[i][B] * (y - size) + m_Frustum[i][C] * (z + size) + m_Frustum[i][D] > 0)
           continue;
        if(m_Frustum[i][A] * (x - size) + m_Frustum[i][B] * (y + size) + m_Frustum[i][C] * (z + size) + m_Frustum[i][D] > 0)
           continue;
        if(m_Frustum[i][A] * (x + size) + m_Frustum[i][B] * (y + size) + m_Frustum[i][C] * (z + size) + m_Frustum[i][D] > 0)
           continue;

        // If we get here, it isn't in the frustum
        return false;
    }

    return true;

}

void CFrustum::CalculateFrustum()
{
    /* 这部分是我自己写的,但是运行效率较低,请高手指教!
    float ModelView[4][4];
    float Projective[4][4];
    float Clip[4][4];

    glGetFloatv(GL_MODELVIEW_MATRIX,*(ModelView+0));
    glGetFloatv(GL_PROJECTION_MATRIX,*(Projective+0));

    for(int i=0; i<4; i++)                                  //M=模型矩阵A*投影矩阵B。
    {   
        for(int j=0;j<4; j++)
        {
            Clip[i][j]=0;
            for( int k=0; k<4; k++)
            {
              Clip[i][j] += ModelView[i][k]*Projective[k][j];
            }
        }
    }
    //数学推导出来的东西,没什么好注释的。想说明白的话,注释肯定得比代码还多
    //建议看看3D数学。
    m_Frustum[RIGHT][0] = Clip[0][3] - Clip[0][0];
    m_Frustum[RIGHT][1] = Clip[1][3] - Clip[1][0];
    m_Frustum[RIGHT][2] = Clip[2][3] - Clip[2][0];
    m_Frustum[RIGHT][3] = Clip[3][3] - Clip[3][0];
    NormalPlane(m_Frustum,RIGHT);

    m_Frustum[LEFT][0] = Clip[0][3] + Clip[0][0];
    m_Frustum[LEFT][1] = Clip[1][3] + Clip[1][0];
    m_Frustum[LEFT][2] = Clip[2][3] + Clip[2][0];
    m_Frustum[LEFT][3] = Clip[3][3] + Clip[3][0];
    NormalPlane(m_Frustum,LEFT);

    m_Frustum[BOTTOM][0] = Clip[0][3] + Clip[0][1];
    m_Frustum[BOTTOM][1] = Clip[1][3] + Clip[1][1];
    m_Frustum[BOTTOM][2] = Clip[2][3] + Clip[2][1];
    m_Frustum[BOTTOM][3] = Clip[3][3] + Clip[3][1];
    NormalPlane(m_Frustum,BOTTOM);

    m_Frustum[TOP][0] = Clip[0][3] - Clip[0][1];
    m_Frustum[TOP][1] = Clip[1][3] - Clip[1][1];
    m_Frustum[TOP][2] = Clip[2][3] - Clip[2][1];
    m_Frustum[TOP][3] = Clip[3][3] - Clip[3][1];
    NormalPlane(m_Frustum,TOP);

    m_Frustum[BACK][0] = Clip[0][3] - Clip[0][2];
    m_Frustum[BACK][1] = Clip[1][3] - Clip[1][2];
    m_Frustum[BACK][2] = Clip[2][3] - Clip[2][2];
    m_Frustum[BACK][3] = Clip[3][3] - Clip[3][2];
    NormalPlane(m_Frustum,BACK);

    m_Frustum[FRONT][0] = Clip[0][3] + Clip[0][2];
    m_Frustum[FRONT][1] = Clip[1][3] + Clip[1][2];
    m_Frustum[FRONT][2] = Clip[2][3] + Clip[2][2];
    m_Frustum[FRONT][3] = Clip[3][3] + Clip[3][2];
    NormalPlane(m_Frustum,FRONT);

   
    */  自己写的部分到此结束,

 

 

 

   //由于自己写的部分运行效率较低,故下面采用书上的代码,效率明显提高!


    float   proj[16];                                // This will hold our projection matrix
    float   modl[16];                                // This will hold our modelview matrix
    float   clip[16];                                // This will hold the clipping planes

    //获得投影矩阵,模型变换矩阵
    glGetFloatv( GL_PROJECTION_MATRIX, proj );
    glGetFloatv( GL_MODELVIEW_MATRIX, modl );

    //利用前面两个矩阵得到世界变幻矩阵,利用该矩阵得到视截体6个面的系数
    //视截体平面的法向量都是指向视截体内部的
    clip[ 0] = modl[ 0] * proj[ 0] + modl[ 1] * proj[ 4] + modl[ 2] * proj[ 8] + modl[ 3] * proj[12];
    clip[ 1] = modl[ 0] * proj[ 1] + modl[ 1] * proj[ 5] + modl[ 2] * proj[ 9] + modl[ 3] * proj[13];
    clip[ 2] = modl[ 0] * proj[ 2] + modl[ 1] * proj[ 6] + modl[ 2] * proj[10] + modl[ 3] * proj[14];
    clip[ 3] = modl[ 0] * proj[ 3] + modl[ 1] * proj[ 7] + modl[ 2] * proj[11] + modl[ 3] * proj[15];

    clip[ 4] = modl[ 4] * proj[ 0] + modl[ 5] * proj[ 4] + modl[ 6] * proj[ 8] + modl[ 7] * proj[12];
    clip[ 5] = modl[ 4] * proj[ 1] + modl[ 5] * proj[ 5] + modl[ 6] * proj[ 9] + modl[ 7] * proj[13];
    clip[ 6] = modl[ 4] * proj[ 2] + modl[ 5] * proj[ 6] + modl[ 6] * proj[10] + modl[ 7] * proj[14];
    clip[ 7] = modl[ 4] * proj[ 3] + modl[ 5] * proj[ 7] + modl[ 6] * proj[11] + modl[ 7] * proj[15];

    clip[ 8] = modl[ 8] * proj[ 0] + modl[ 9] * proj[ 4] + modl[10] * proj[ 8] + modl[11] * proj[12];
    clip[ 9] = modl[ 8] * proj[ 1] + modl[ 9] * proj[ 5] + modl[10] * proj[ 9] + modl[11] * proj[13];
    clip[10] = modl[ 8] * proj[ 2] + modl[ 9] * proj[ 6] + modl[10] * proj[10] + modl[11] * proj[14];
    clip[11] = modl[ 8] * proj[ 3] + modl[ 9] * proj[ 7] + modl[10] * proj[11] + modl[11] * proj[15];

    clip[12] = modl[12] * proj[ 0] + modl[13] * proj[ 4] + modl[14] * proj[ 8] + modl[15] * proj[12];
    clip[13] = modl[12] * proj[ 1] + modl[13] * proj[ 5] + modl[14] * proj[ 9] + modl[15] * proj[13];
    clip[14] = modl[12] * proj[ 2] + modl[13] * proj[ 6] + modl[14] * proj[10] + modl[15] * proj[14];
    clip[15] = modl[12] * proj[ 3] + modl[13] * proj[ 7] + modl[14] * proj[11] + modl[15] * proj[15];
    // Now we actually want to get the sides of the frustum.  To do this we take
    // the clipping planes we received above and extract the sides from them.

    // This will extract the RIGHT side of the frustum
    m_Frustum[RIGHT][A] = clip[ 3] - clip[ 0];
    m_Frustum[RIGHT][B] = clip[ 7] - clip[ 4];
    m_Frustum[RIGHT][C] = clip[11] - clip[ 8];
    m_Frustum[RIGHT][D] = clip[15] - clip[12];

    // Now that we have a normal (A,B,C) and a distance (D) to the plane,
    // we want to normalize that normal and distance.

    // Normalize the RIGHT side
    NormalizePlane(m_Frustum, RIGHT);

    // This will extract the LEFT side of the frustum
    m_Frustum[LEFT][A] = clip[ 3] + clip[ 0];
    m_Frustum[LEFT][B] = clip[ 7] + clip[ 4];
    m_Frustum[LEFT][C] = clip[11] + clip[ 8];
    m_Frustum[LEFT][D] = clip[15] + clip[12];

    // Normalize the LEFT side
    NormalizePlane(m_Frustum, LEFT);

    // This will extract the BOTTOM side of the frustum
    m_Frustum[BOTTOM][A] = clip[ 3] + clip[ 1];
    m_Frustum[BOTTOM][B] = clip[ 7] + clip[ 5];
    m_Frustum[BOTTOM][C] = clip[11] + clip[ 9];
    m_Frustum[BOTTOM][D] = clip[15] + clip[13];

    // Normalize the BOTTOM side
    NormalizePlane(m_Frustum, BOTTOM);

    // This will extract the TOP side of the frustum
    m_Frustum[TOP][A] = clip[ 3] - clip[ 1];
    m_Frustum[TOP][B] = clip[ 7] - clip[ 5];
    m_Frustum[TOP][C] = clip[11] - clip[ 9];
    m_Frustum[TOP][D] = clip[15] - clip[13];

    // Normalize the TOP side
    NormalizePlane(m_Frustum, TOP);

    // This will extract the BACK side of the frustum
    m_Frustum[BACK][A] = clip[ 3] - clip[ 2];
    m_Frustum[BACK][B] = clip[ 7] - clip[ 6];
    m_Frustum[BACK][C] = clip[11] - clip[10];
    m_Frustum[BACK][D] = clip[15] - clip[14];

    // Normalize the BACK side
    NormalizePlane(m_Frustum, BACK);

    // This will extract the FRONT side of the frustum
    m_Frustum[FRONT][A] = clip[ 3] + clip[ 2];
    m_Frustum[FRONT][B] = clip[ 7] + clip[ 6];
    m_Frustum[FRONT][C] = clip[11] + clip[10];
    m_Frustum[FRONT][D] = clip[15] + clip[14];

    // Normalize the FRONT side
    NormalizePlane(m_Frustum, FRONT);
}

//可以加入判断别的形体是否在视截体内部的函数,在此仅举正方体的例子!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值