得到View Frustum的6飞机

得到View Frustum的6飞机,第1张

得到View Frustum的6飞机

笔者: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外用。


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


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/589180.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-12
下一篇 2022-04-12

发表评论

登录后才能评论

评论列表(0条)

保存