📄 frustum.cpp
字号:
#include "StdAfx.h"
#include "Frustum.h"
#include "Sphere.h"
#include "AABB3.h"
//-------------------------------------------------------------------------------
// 平截头体面的枚举
//-------------------------------------------------------------------------------
enum FrustumSide
{
RIGHT = 0, // 右面
LEFT = 1, // 左面
BOTTOM = 2, // 下面
TOP = 3, // 上面
BACK = 4, // 后面
FRONT = 5 // 前面
};
//-------------------------------------------------------------------------------
// 平截头体全局对象
//-------------------------------------------------------------------------------
CFrustum g_Frustum;
//-------------------------------------------------------------------------------
// 每次摄像机移动后都重新计算一次平截头体每个面
//-------------------------------------------------------------------------------
void CFrustum::CalculateFrustum()
{
float proj[16]; // 保存投影矩阵
float modl[16]; // 保存视图矩阵
float clip[16]; // 保存裁剪面
// 获取投影矩阵
glGetFloatv(GL_PROJECTION_MATRIX, proj);
// 获取视图矩阵
glGetFloatv(GL_MODELVIEW_MATRIX, modl);
// 现在我们有投影和视图矩阵,如果我们结合两个矩阵,我们会得到裁剪面
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];
// 现在我们需要得到平截头体的面,我们把上面得到的裁剪矩阵抽取出面
// 提出平截头体右面
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];
// 标准化右面
PlaneNormalize(&m_Frustum[RIGHT], &m_Frustum[RIGHT]);
// 提出平截头体左面
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];
// 标准化左面
PlaneNormalize(&m_Frustum[LEFT], &m_Frustum[LEFT]);
// 提出平截头体下面
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];
// 标准化下面
PlaneNormalize(&m_Frustum[BOTTOM], &m_Frustum[BOTTOM]);
// 提出平截头体上面
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];
// 标准化上面
PlaneNormalize(&m_Frustum[TOP], &m_Frustum[TOP]);
// 提出平截头体后面
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];
// 标准化后面
PlaneNormalize(&m_Frustum[BACK], &m_Frustum[BACK]);
// 提出平截头体前面
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];
// 标准化前面
PlaneNormalize(&m_Frustum[FRONT], &m_Frustum[FRONT]);
}
//-------------------------------------------------------------------------------
// 判断一个3D点是否在平截头体内
//-------------------------------------------------------------------------------
bool CFrustum::PointInFrustum(const Vector3 &point)
{
// 遍历平截头体的每个面
for (int i = 0; i < 6; ++i)
{
// 用点和平面点乘,判断点在平面的哪一面
if (PlaneDotCoord(&m_Frustum[i], &point) < 0.f)
{
// 点在一个平面的后面,所以它不在平截头体内
return false;
}
}
// 点在平截头体内
return true;
}
//-------------------------------------------------------------------------------
// 判断一个3D球是否在平截头体内
//-------------------------------------------------------------------------------
bool CFrustum::SphereInFrustum(const CSphere &sphere)
{
float x = sphere.center.x;
float y = sphere.center.y;
float z = sphere.center.z;
float radius = sphere.radius;
// 遍历平截头体的每个面
for (int i = 0; i < 6; ++i)
{
// 用原点和平面点乘,如果原点在平面后面并超过半径的距离则表示不在平面内
if (PlaneDotCoord(&m_Frustum[i], &sphere.center) <= -sphere.radius)
{
// 球不在平截头体内
return false;
}
}
// 球在平截头体
return true;
}
//-------------------------------------------------------------------------------
// 判断一个立方体是否在平截头体内
//-------------------------------------------------------------------------------
bool CFrustum::CubeInFrustum(const AABB3& box)
{
// 遍历平截头体的每个面
for (int i = 0; i < 6; ++i)
{
Vector3 point(box.min);
// 如果有一点在平截头体里就算这个面通过了
if (PlaneDotCoord(&m_Frustum[i], &box.min) > 0.f)
continue;
point.x = box.max.x;
if (PlaneDotCoord(&m_Frustum[i], &point) > 0.f)
continue;
point.y = box.max.y;
if (PlaneDotCoord(&m_Frustum[i], &point) > 0.f)
continue;
point.z = box.max.z;
if (PlaneDotCoord(&m_Frustum[i], &point) > 0.f)
continue;
point.y = box.min.y;
point.z = box.max.z;
if (PlaneDotCoord(&m_Frustum[i], &point) > 0.f)
continue;
point.x = box.min.x;
if (PlaneDotCoord(&m_Frustum[i], &point) > 0.f)
continue;
point.y = box.max.y;
if (PlaneDotCoord(&m_Frustum[i], &point) > 0.f)
continue;
if (PlaneDotCoord(&m_Frustum[i], &box.max) > 0.f)
continue;
return false;
}
// 立方体在平截头体
return true;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -