本文大部分内容翻译自Gil Gribb和Klaus Hartmann合写的《Fast Extraction of Viewing Frustum Planes from the World-View-Projection Matrix》这篇文章,有兴趣的朋友可以搜索看下原文,里面DirectX下和OpenGL下的实现过程都说的很清楚,这里只说DirectX部分。
这里介绍的算法,可以直接从世界、观察以及投影矩阵中计算出Viewing Frustum的六个面。它快速,准确,并且允许我们在相机空间(camera space)、世界空间(world space)或着物体空间(object space)快速确定Frustum planes。
我们先仅仅从投影矩阵(project)开始,也就是假设世界矩阵(world)和观察矩阵(view)都是单位化了的矩阵。这就意味着相机位于世界坐标系下的原点,并且朝向Z轴的正方向。
定义一个顶点v(x y z w=1)和一个4*4的投影矩阵M=m(i,j),然后我们使用该矩阵M对顶点v进行转换,转换后的顶点为v'= (x' y' z' w'),可以写成这样:
转换后,viewing frustum实际上就变成了一个与轴平行的盒子,如果顶点 v' 在这个盒子里,那么转换前的顶点 v 就在转换前的viewing frustum里。在Direct3D下,如果下面的几个不等式都成立的话,那么 v' 就在这个盒子里。
                                                                     -w' < x' < w'
-w' < y' < w'
0 < z' < w'
可得到如下结论,列在下表里:
现在假设,我们要测试x'是否在左半空间内,根据上表,也就是判断 -w' < x' 是否成立。用我们开始提到的信息,可将不等式写成如下形式:
-( v * col4 ) < ( v * col1 )
即:
0 < ( v * col4 )  + ( v * col1 )
得到最后形式:
0 < v * ( col1 + col4 )
写到这里,其实已经等于描绘出了转换前的viewing frustum的左裁剪面的平面方程:
x * ( m14 + m11 ) + y * ( m24 + m21 )  + z * ( m34 + m31) + w * ( m44 + m41 ) = 0
当W = 1,我们可简单成如下形式:
x * ( m14 + m11 ) + y * ( m24 + m21 )  + z * ( m34 + m31) +  ( m44 + m41 ) = 0
这就给出了一个基本平面方程:
ax + by + cz + d = 0
其中,a = ( m14 + m11 ) , b = ( m24 + m21 ), c = ( m34 + m31) , d  =  ( m44 + m41 )
 
ok,到这里左裁剪面就得到了。重复以上几步,可推导出到其他的几个裁剪面,具体见下表:
需要注意的是:最终得到的平面方程都是没有单位化的(平面的法向量不是单位向量),并且法向量指向空间的内部。这就是说,如果要判断 v 在空间内部,那么6个面必须都满足ax + by + cz + d > 0
到目前为止,我们都是假设世界矩阵( world )和观察矩阵( view )都是单位化了的矩阵。但是,本算法并不想受这种条件的限制,而是希望可以在任何条件下都能使用。实际上,这也并不复杂,并且简单得令人难以置信。如果你仔细想一下就会立刻明白了,所以我们不再对此进行详细解释了,下面给出3个结论:
1. 如果矩阵 M 等于投影矩阵 P ( M = P ),那么算法给出的裁剪面是在相机空间(camera space)
2. 如果矩阵 M 等于观察矩阵 V 和投影矩阵 P 的组合( M = V * P ),那么算法给出的裁剪面是在世界空间(world space)
3.如果矩阵 M 等于世界矩阵 W,观察矩阵 V 和投影矩阵 P 的组合( M = W* V * P ),呢么算法给出的裁剪面是在物体空间(object space)
好,到此为止,理论知识就全部说完了,下面给出具体的实现代码:
===============================Frustum.h==============================
#ifndef __FrustumH__
#define __FrustumH__
#include <d3dx9.h>
class Frustum
{
public:
Frustum();
     ~Frustum();
// Call this every time the camera moves to update the frustum
     void CalculateFrustum( D3DXMATRIX ViewMatrix, D3DXMATRIX ProjectMatrix );
// This takes a 3D point and returns TRUE if it's inside of the frustum
     bool PointInFrustum( D3DXVECTOR3 Point );
private:
     // This holds the A B C and D values for each side of our frustum.
     D3DXPLANE FrustumPlane[6];
};
#endif // __FrustumH
=============================Frustum.cpp============================
#include "Frustum.h"
#include <D3dx9math.h>

enum FrustumSide { RIGHT, LEFT, BOTTOM, TOP, FRONT, BACK };

Frustum::Frustum()
{
}
Frustum::~Frustum()
{
}
/ CALCULATE FRUSTUM \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
/
/ This extracts our frustum from the projection and view matrix.
/
/ CALCULATE FRUSTUM \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
void Frustum::CalculateFrustum( D3DXMATRIX ViewMatrix, D3DXMATRIX ProjectMatrix )
{
 D3DXMATRIX ComboMatrix;
 D3DXMatrixMultiply( &ComboMatrix, &ViewMatrix, &ProjectMatrix );
//right clipping plane
 FrustumPlane[RIGHT].a = ComboMatrix._14 - ComboMatrix._11;
 FrustumPlane[RIGHT].b = ComboMatrix._24 - ComboMatrix._21;
 FrustumPlane[RIGHT].c = ComboMatrix._34 - ComboMatrix._31;
 FrustumPlane[RIGHT].d = ComboMatrix._44 - ComboMatrix._41;
 
 //normalize
 D3DXPlaneNormalize( &FrustumPlane[RIGHT], &FrustumPlane[RIGHT] );
//left clipping plane
 FrustumPlane[LEFT].a = ComboMatrix._14 + ComboMatrix._11;
 FrustumPlane[LEFT].b = ComboMatrix._24 + ComboMatrix._21;
 FrustumPlane[LEFT].c = ComboMatrix._34 + ComboMatrix._31;
 FrustumPlane[LEFT].d = ComboMatrix._44 + ComboMatrix._41;
 
//normalize
 D3DXPlaneNormalize( &FrustumPlane[LEFT], &FrustumPlane[LEFT] );
 
//bottom clipping plane
 FrustumPlane[BOTTOM].a = ComboMatrix._14 + ComboMatrix._12;
 FrustumPlane[BOTTOM].b = ComboMatrix._24 + ComboMatrix._22;
 FrustumPlane[BOTTOM].c = ComboMatrix._34 + ComboMatrix._32;
 FrustumPlane[BOTTOM].d = ComboMatrix._44 + ComboMatrix._42;
 
//normalize
 D3DXPlaneNormalize( &FrustumPlane[BOTTOM], &FrustumPlane[BOTTOM] );
 
//top clipping plane
 FrustumPlane[TOP].a = ComboMatrix._14 - ComboMatrix._12;
 FrustumPlane[TOP].b = ComboMatrix._24 - ComboMatrix._22;
 FrustumPlane[TOP].c = ComboMatrix._34 - ComboMatrix._32;
 FrustumPlane[TOP].d = ComboMatrix._44 - ComboMatrix._42;
 
//normalize
 D3DXPlaneNormalize( &FrustumPlane[TOP], &FrustumPlane[TOP] );
//near clipping plane
 FrustumPlane[FRONT].a = ComboMatrix._14 + ComboMatrix._13;
 FrustumPlane[FRONT].b = ComboMatrix._24 + ComboMatrix._23;
 FrustumPlane[FRONT].c = ComboMatrix._34 + ComboMatrix._33;
 FrustumPlane[FRONT].d = ComboMatrix._44 + ComboMatrix._43;
 
//normalize
 D3DXPlaneNormalize( &FrustumPlane[FRONT], &FrustumPlane[FRONT] );
 
//far clipping plane
 FrustumPlane[BACK].a = ComboMatrix._14 - ComboMatrix._13;
 FrustumPlane[BACK].b = ComboMatrix._24 - ComboMatrix._23;
 FrustumPlane[BACK].c = ComboMatrix._34 - ComboMatrix._33;
 FrustumPlane[BACK].d = ComboMatrix._44 - ComboMatrix._43;
 
//normalize
 D3DXPlaneNormalize( &FrustumPlane[BACK], &FrustumPlane[BACK] );
}

/ POINT IN FRUSTUM \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
/
/ This determines if a point is inside of the frustum
/
/ POINT IN FRUSTUM \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
bool Frustum::PointInFrustum( D3DXVECTOR3 Point )
{
 for( int i = 0; i < 6; i++ )
 {
  float x = D3DXPlaneDotCoord( &FrustumPlane[i], & Point );
  if( x < 0 )
   return false;
 }
 // The point was inside of the frustum (In front of ALL the sides of the frustum)
 return true;
}

转载于:https://blog.51cto.com/xiaoxiang/26928

DirectX下 Viewing Frustum 的详细实现相关推荐

  1. linux系统退出当前计算节点命令,Linux下60个系统命令详细解.doc

    Linux下60个系统命令详细解 嵌入式学习指引--Linux下60个系统命令详细解 Linux为用户提供了大量的命令,利用它可以有效地完成大量的工作,如磁盘操作.文件存取.目录操作.进程管理.文件权 ...

  2. Win10 Anaconda下TensorFlow-GPU环境搭建详细教程(包含CUDA+cuDNN安装过程)(转载)...

    win7(win10也适用)系统安装GPU/CPU版tensorflow Win10 Anaconda下TensorFlow-GPU环境搭建详细教程(包含CUDA+cuDNN安装过程) 目录 2.配置 ...

  3. linux下安装DB2的详细步骤

    我也是才学习,在网上找了一个在linux下安装DB2 的步骤,共享给大家看看了. linux下安装DB2的详细步骤! 第一步:检查程序包及其版本 在软件包管理中查看下列软件包是否安装,如没有安装,先安 ...

  4. svn安装教程 mysql_CentOS6.4 下安装SVN的详细教程(超详细)

    1.检查系统是否已经安装如果安装就卸载 rpm -qa subversion yum remove subversion 2.安装 yum install subversion 3.建立SVN库 mk ...

  5. iis服务器部署项目,IIS环境下部署项目的详细教程

    分享IIS环境下部署项目的详细教程 1.环境部署 1.1安装IIS7 进入控制面板,选择"程序和功能",进入如下页面后 找到World Wide Web Services,确保选中 ...

  6. mysql8.018安装教程_mysql8.0.18下安装winx64的详细教程(图文详解)

    到网站 下载mysql数据库 解压后进入目录 d:\program files\mysql-8.0.18 创建my.ini文件 [mysql] # 设置mysql客户端默认字符集 default-ch ...

  7. linux操作系统adsl 上网设置,Linux操作系统下ADSL拨号上网详细步骤 -电脑资料

    本指南将帮助你在Ubuntu 6.06 LTS (Dapper Drake)下用PPPoE以太网modem建立ADSL网络连接, 1. 简介 虽然用路由器联网很常见,我们有时也需要用PPPoE直接连接 ...

  8. 【Linux】CentOS7下安装Ngnix代理服务器详细过程 附Linux 64位 Ngnix压缩包百度云盘分享

    [Linux]CentOS7下安装Ngnix代理服务器详细过程 附Linux 64位 Ngnix压缩包百度云盘分享 Ngnix基本概况 Nginx (读作"engine X") 由 ...

  9. Linux下卸载nginx的详细步骤,亲测有效

    1.检查nginx服务是否运行,如果正在运行则关闭服务. ps -ef|grep nginx /usr/local/nginx/sbin/nginx -s stop 2.查找并删除nginx相关文件. ...

最新文章

  1. Linux驱动程序编写
  2. 最短路径问题-Dijkstra算法的python实现
  3. 组合测试法是什么 软件测试,组合测试法中的全对偶测试法
  4. JDK源码分析-TreeMap(1)
  5. 在新的固态硬盘只装ubuntu16.04系统,重启后无启动项解决方案
  6. C++:51---继承中的构造函数、析构函数、拷贝控制一系列规则
  7. 敏捷开发中asp.net MVC的开发次序感受(先开发View?先开发Model?先开发Controller!)...
  8. Redis - 在电商购物车场景下的实战分析
  9. Mac小技巧:在mac上怎么把png转换成jpg
  10. 链表例题2:链表的倒数第k个节点是多少
  11. 如何使用FireBug插件查询元素的xPath属性
  12. 风物长宜放眼量,人间正道是沧桑 - 一位北美 IT 技术人破局
  13. cat 常用的日志分析架构方案_深度剖析|数据库生产常用架构方案
  14. 鸿蒙无锡有什么特产,无锡太湖鼋头渚十大特产
  15. 测试相机的软件叫什么,测年龄的app叫什么(测年龄的相机软件app)
  16. 8个精挑细选的适用App,全是黑科技,用起来超爽
  17. Spring Boot 注解原理
  18. 一个强化学习 Q-learning 算法的简明教程
  19. 为listview、或者recyclerView的item增加进场动画
  20. AWS S3 and Glacier

热门文章

  1. 动态调用有关的方法?
  2. 从AppStore提取ipa
  3. tinyxml 内存泄露_有关TinyXML使用的简单总结
  4. numa节点_漫步云端NUMA调度
  5. EEGNet: 神经网络应用于脑电信号
  6. 想体验从活火山上滑下来的刺激感?VR来成全你
  7. AI创业公司最佳「开发工具」指南火了,还发现了个可挑战Jupyter的「杀手」
  8. 让电影动漫统统变丝滑,480帧也毫无卡顿,交大博士生开源插帧软件DAIN
  9. 姚班学霸蝉联第一,清华再霸榜,湘潭大学表现亮眼,第四届 CCF CCSP落下帷幕...
  10. 官方资源帖!手把手教你在TensorFlow 2.0中实现CycleGAN,推特上百赞