⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 frustum.cpp

📁 3D赛车游戏源代码-用Visual Studio 2005
💻 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 + -