笔者:i_dovelemon

资源:CSDN

日期:2014 / 9 / 30

主题:View Frustum, Plane, View Matrix, Perspective Projection Matrix

引言

在3D图形学中,一种优化的手法,叫做物体剔除(Object Culling)。

这种技术的提出是基于这种策略:我们不希望将不存在View Frustum里面的物体送往流水线中进行处理。

尽管,你可能会说,如今的图形卡都已近支持了三角形剔除的技术。可是,不要忘了流水线的步骤。

我们是先进行Vertex Processing。然后才进行Geometry Processing。

而图形卡对三角形的剔除是在Geometry
Processing这个阶段进行的。

也就是说,即使可以剔除它们,我们依旧要在Vertex Processing中对这些将来须要丢弃的顶点进行Vertex Processing处理。而我们知道。Vertex Processing这个阶段往往会进行坐标变换,光照计算等等费时的操作。所以,假设可以在Vertex Processing之前。也就是在Application阶段,在我们的CPU中将这些根本不须要处理的物体剔除的话。会大大的提高程序的效率。而想要将物体剔除,我们就须要知道这个物体是否在View Frustum中。

而为了推断这个条件,我们就须要确定构成View
Frustum的6个平面的方程。

所以。本篇文章,就向大家讲述,怎样获取View Frustum的6个平面方程。

推理过程

想要获取View Frustum的6个面的方程。那么我们就须要知道,我们是怎么定义View Frustum的。

在我的博客栏目中。有一篇文章基本3D变换。在这篇文章中,我们知道,我们使用NearZ。 FarZ, Fov和Aspect这几个值来定义了View
Frustum。

而这些值都保存在Projection Matrix中。所以,突破口就在这个Projection Matrix里面。

我们来回想下上面的文章。

基本3D变换这篇文章中讲述了主要的3D变换之World Transform, View Transform和Projection Transform。而且费了非常大的篇幅证明了Projection Matrix的作用以及它的推导过程。从中我们知道,Projection
Matrix的作用是将View Frustum中的顶点。变换到一个Cubic空间中去。

这个空间的X的范围为[-1,1],Y轴的范围为[-1,1]。Z轴的范围为[0,1]。

那么,也就是说。原来View Frustum的6个平面,在经过了变换之后。变成了Cubic的6个面。

那么,我们是否能通过这6个面,来获取还原原来的View Frustum的6个面了。

答案是肯定的。可是我们并非直接获取到6个平面的方程。而是使用一种等价的方式推导出这6个面的。以下我们来看下。

我们知道,在世界坐标空间View Frustum中的一个点S,经过了M = ViewMatrix * ProjMatrix变换之后,就变换到了Cubic的空间中去了。所以。我们能够得到例如以下的结论:

T = S * M   (1)

变换后的T是一个齐次坐标。它的w分量不再是1,我们来看下T.w究竟等于什么。

在世界坐标空间中。顶点的w值都为1。所以与View Matrix相乘之后。它的w变成了 :

w' = [x,y,z,w] * [ViewM.03, ViewM.13, ViewM.23, ViewM.33] = [x,y,z,w] * [0, 0, 0, 1] = w = 1 (2)

再与Proj Matrix相乘之后,w‘变成了:

w'' = [x',y',z',w'] * [ProjM.03, ProjM.13, ProjM.23, ProjM.33] = [x, y, z , w'] * [ 0, 0, 1, 0] = z' (3)

也就是说,顶点在经过了View Transform 和 Projection Transform之后,它的w分量变成了顶点在相机空间中的z值。

我们将T化成U。当中U.w = 1。而如今的U就处在Cubic空间中。

我们知道Cubic空间的X范围为[-1,1],那么就是说:

-1 <= U.x <= T.x / T.w (4)

通过公式(3),我们知道T.w = z'。即等于在相机空间中的z值。

而View Frustum中的顶点在相机坐标空间中的z值都是大于0的。所以又能够得到例如以下的公式:

T.x + T.w >= 0 (5)

通过公式(1),我们能够知道例如以下:

T.x = S * Mcol0 , T.w = S * Mcol3 (6)

将公式(6)带入公式(5)。得到例如以下:

S*Mcol0 + S*Mcol3 >= 0  ==>  S * (Mcol0 + Mcol3) >= 0 (7)

因为Mcol0和Mcol3都是一个向量,他们的和也能够用一个向量N来表示,所以就变成了

S * N >= 0  ==> S.x * N.x + S.y * N.y + S.z * N.z + S.w * N.w >= 0 ==> S.x*N.x + S.y*N.y + S.z*N.z + N.w >= 0 (8)

我们来回忆下,在DirectX中,平面是怎样保存的。在DirectX中,D3DXPLANE中有两个属性来唯一确定。它们各自是平面的法向向量N'。以及原点到这个平面的有向距离d来表示。

假设一个点S’在平面的正半空间中,那么我们将这个点带入到DirectX的平面方程中:

S' * N' + d > 0 ==> S'.x*N'.x + S'.y*N'.y + S'.z*N‘.z + d >= 0 (9)

读者自己比对下公式(8)和公式(9)。就会发现,它们是惊人的相似。仅仅只是这里的d,变成了N.w而已。所以。我们全然能够将公式(8)中的N和N.w抽取出来。作为D3DXPLNE中的N和d,来构成一个平面。而这个平面就是View Frustum的Left平面。在上面,我们已经如果了U.x>=-1。也就是说,这里的情况下,得到的Left平面,它的法向向量是指向View Frustum里面的。如果想要指向外面仅仅要将公式(8)中的N反向就可以。

相同的方法,我们能够推导出其它几个面的方程。

总结

通过上面的推导,我们就能够得到例如以下的结论:

Left平面: 0 =( Mcol3 + Mcol0) * [x,y,z,w]

Right平面: 0 = (Mcol3 - Mcol0) * [x,y,z,w]

NearZ平面: 0 = Mcol2 * [x,y,z,w]

FarZ平面: 0 = (Mcol3 - Mcol2) * [x,y,z,w]

Top平面: 0 = (Mcol3 - Mcol1) * [x,y,z,w]

Bottom平面:  0 = (Mcol3 + Mcol1) * [x,y,z,w]

只是注意,上面的平面都是没有进行归一化的平面。使用的时候。最好使用D3DXNormalizePlane进行归一化操作。

好了,今天就到这里。

下一篇文章,会向大家讲述。怎样进行检測,推关闭对象是否View Frustum外用。

版权声明:本文博主原创文章,博客,未经同意不得转载。

得到View Frustum的6飞机的更多相关文章

  1. 【翻译】View Frustum Culling --3 Clip Space Approach – Extracting the Planes

    3.使用裁剪空间的方法提取平面 上一篇中,我们讨论了通过几何的方法提取视锥体的六个片面.在这一篇中,我们继续讨论通过裁剪空间的方法来提取视锥体的平面. 假设现在在世界坐标系中有一点p=(x,yz,1) ...

  2. 【翻译】View Frustum Culling --2 Geometric Approach – Extracting the Planes

    在上一篇中,我们知道了视锥体的形状,并且也确定了我们进行裁剪时的步骤.那我们接下来要走的就是确定视锥体的六个平面: near, far, top, bottom, left and right 2.计 ...

  3. 【翻译】 View Frustum Culling --1 View Frustum’s Shape

    这是一些列来自lighthouse3d的视锥体裁剪教程.旨在学习总结,及便于查阅. 1.视锥体的形状 在OpenGL中,透视投影是由两个函数定义的gluPerspective和gluLookAt.我们 ...

  4. 简单的Viewing Frustum Culling

    Viewing Frustum Culling是图形绘制流水线中,将不可见物体(即不在视锥体内的物体)提前剔除的操作. 在实践中,精确判断物体的可见性开销较大,因而通常用物体包围球或包围盒与视锥体(平 ...

  5. JavaScript—飞机大战2版

    前面的思路对了  BUG 出在了计时器和没有加判断页面是否存在元素 <!DOCTYPE html> <html lang="en"> <head> ...

  6. JavaScript—飞机大战

    今天来写个游戏,飞机大战 1,布局 2,思路 1,动态创建自己的飞机 让它在规定的区域,跟着鼠标运动. 2,在自己飞机的上方,间隔1s生成子弹.子弹往上移动 当top:0 子弹消失 3,每隔1s 产生 ...

  7. Forward+ Rendering Framework

    近几天啃各种新技术时又一个蛋疼的副产品...额,算是把AMD的Forward+ Sample抄了一遍吧. 其实个人感觉这个AMD大肆宣传的Forward+跟Intel很早之前提的Tiled-Based ...

  8. [比较老的文章]三维渲染引擎 OGRE 与 OSG 的比较综述

    1 .引言随着计算机可视化.虚拟现实技术的飞速发展,人们对实时真实感渲染以及场景复杂度提出了更高的要求.传统的直接使用底层图形接口如OpenGL.DirectX开发图形应用的模式越来越暴露出开发复杂性 ...

  9. 【OPENGL】第三篇 着色器基础(一)

    在这一章,我们会学习什么是着色器(Shader),什么是着色器语言(OpenGL Shading Language-GLSL),以及着色器怎么和OpenGL程序交互. 首先我们先来看看什么叫着色器. ...

随机推荐

  1. 应用层open(read、write、close)怎样调用驱动open(read、write、close)函数的?

    应用层open(read.write.close)怎样调用驱动open(read.write.close)函数的? 华清远见2014-09-29   北京海淀区 张俊浩 三大数据结构关系图

  2. 《TCP/IP作品详细解释2:实现》笔记--Radix树路由表

    通过IP完整的路由是路由机制,它通过搜索路由表来确定从哪个分组被发送的接口执行此,它是不一样的路由策略,路由策略 它是一组规则,这些规则可以被用来确定哪些路由编程到路由表,Net/3内核实现的路由机制 ...

  3. hdu4341(分组背包)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4341 题意:一个人在原点(0,0)抓金子,每块金子有一个获得需要的时间t和价值v.而且有的金子可能在一 ...

  4. dsbskrhkme看么哦么

    http://pan.baidu.com/share/link?shareid=3011665141&uk=338692646&third=15                http ...

  5. 遇过的坑(2)—MyISAM表类型不支持事务操作

    最近需要通过JDBC对数据库做事务型操作,实践时发现,并没有达到想要的效果,表现在:1.每次执行executeUpdate()后,数据就马上能在DB中查到.但按理来说,我还没执行commit(),DB ...

  6. poj 3311 状压DP

    经典TSP变形 学到:1.floyd  O(n^3)处理随意两点的最短路 2.集合的位表示,我会在最后的总结出写出.注意写代码之前一定设计好位的状态.本题中,第0位到第n位分别代表第i个城市,1是已经 ...

  7. HDU ACM 2586 How far away ?LCA-&gt;并查集+Tarjan(离线)算法

    题意:一个村子有n个房子,他们用n-1条路连接起来,每两个房子之间的距离为w.有m次询问,每次询问房子a,b之间的距离是多少. 分析:近期公共祖先问题,建一棵树,求出每一点i到树根的距离d[i],每次 ...

  8. hdu3570, 超级简单的斜率优化dp

    dp[i] = dp[j] + (a[i] - a[j])^2 + m;展开得 dp[i] = min{dp[j] + a[i]^2 + a[j]^2 - 2*a[i]*a[j] + m}其中a[i] ...

  9. CSDN的SDCC大会(2013)中使用的PPT分享

    SDCC大会今天开完个.呵呵~ PPT下载链接在最后面,对内幕不感兴趣的可以直接无视下面的种种啰嗦直接“嗖”到最后. 这里说说这个大会中我的Topic. 此前CSDN向我约了一个主题,我回复说, 我可 ...

  10. 飘逸的python - 发送带各种类型附件的邮件

    上一篇博文演示了如何发送简单的邮件,这一篇将演示如何发送各种类型的附件. 基本思路就是,使用MIMEMultipart来标示这个邮件是多个部分组成的,然后attach各个部分.如果是附件,则add_h ...