在学习场景管理之前,我们要先学习一下视锥体剔除(VFC),因为无论你使用什么空间划分算法,划分的空间都要进行视锥体剔除,被剔除的空间内部的所有物件都会被抛弃以此来加速渲染或碰撞。这也是场景管理的核心目的。

1.包围体(BV)与视锥体

包围体就是把一个模型或空间包住的最小几何体,可以是球体,AABB包围盒,OBB包围盒。视锥体是一个被远近裁减面截断的锥体(6面体)。视锥体剔除就是判断包围体和视锥体的位置关系。不同的包围体与视锥体进行相交判断,复杂度是不一样的。这里的复杂度由低到高的顺序是球体<AABB<OBB。另外如果把视锥体变成一个AABB包围体,那么相交判断也会变的非常简单。所以这里有一个优化点就是可以把复杂的包围体外面再套一个简单的包围体,比如AABB上面包裹一个球体,然后使用球体和视锥体进行测试,如果球体在视锥体内再做AABB测试。再比如可以把视锥体变成AABB然后进行测试,如果在AABB中再进行视锥体测试。这里只是提出一种优化的可能性,并不代表性能一定会提升。这取决于场景,如果一个场景中有很多节点,并且大部分节点都在视锥体之外那么这个优化应该会有一定的提升。我们应该注意到多一份包围体,就会多一份内存,天下没有免费的午餐,又一个空间换时间的优化算法。

2.位置关系

包围体和视锥体有三种位置关系

  • 包围体在视锥体外部
  • 包围体在视锥体内部
  • 包围体部分在视锥体内部(相交)

如果包围体在视锥体外部,说明这个节点下的全部物件都不在可视范围内,可以全部丢弃。

如果包围体在视锥体内部说明全部物件都在视锥体内部,这些物件都会传递到GPU中进行渲染。这里有一个问题,如果包围体在视锥体内部也就说明所有包围体中的物件都在视锥体内部。物件进入到GPU中被拆解成三角面片,这些图元在GPU中做齐次空间裁剪,但这些三角面片其实是不需要做齐次空间裁剪的,因为它们的位置关系已经确定了,一定是在视锥体内部。GPU做了重复的工作。以前VFC和三角面片裁剪都在CPU中计算那么可以做标记优化,现在cpu和gpu按照流水线的方式工作,gpu并不知道这些三角面片不需要被裁剪,甚至gpu的设计就是喜欢蛮干并行处理,根本不管你逻辑是否已经被剔除。如果能够把VFC的工作交给gpu,一方面可以降低cpu的负担,另一方面gpu也可以避免一些重复性的工作,是不是会更好,这些疑问只有等到学习完Gpu driven rendering pipelines才能给出答案了。

包围体部分在视锥体内部,这说明包围体中的物件可能在视锥体中,可能在视锥体外,这时候我们需要做进一步的判断就是用每一个物件的包围体进行VFC。如果游戏的性能压力在cpu端,通常我们不会做进一步的测试。

3.视锥体的六个面

视锥体的六个面由远近裁剪面,及上下左右四个面组成。

我们需要将这六个面用平面公式表示出来。

一个平面可以由平面上的三个点确定,也可以由平面法线和平面上的一个点确定。

我们只需要根据已知变量求解出上图中的ntl,nbl,ntr,nbr,ftl,fbl,ftr,fbr这八个点就可以确定6个平面。

平面方程的确定我简单说一下思路,具体细节网上有很多。

我们在unity中确定一个相机的参数是远近裁剪面+FOV。

FOV是水平方向的视角,比如60度就是广角摄像头。其实还应该有一个垂直方向的FOV才能确定一个锥体。如果水平方向和垂直方向的FOV角度相同,那么远近裁剪面就是一个正方形,视平面也是一个正方形。视平面是相机和近裁剪面之间的一个平面,它是用来接收投影变换的平面。这个平面的宽高比一定要和屏幕空间的宽高比一致,否则图片会发生拉伸。unity之所以没有让我们设置垂直平面的FOV是因为unity会自动根据屏幕的宽高比及水平FOV反推出垂直平面的FOV。简单的说确定一个相机需要知道它的远近裁剪面,水平FOV以及屏幕的宽高比。

上面这些参数只是确定了一个视锥体的形状,它在任何一个空间中还需要确定位置和朝向。比如我们求解的六个平面方程是在世界空间中,那么我们还需要知道相机在世界空间中的位置及朝向。

我们整理一下目前已知的变量

  • 相机的位置
  • 相机的朝向
  • 相机的FOV
  • 相机的宽高比
  • 近裁剪距离
  • 远裁剪面距离

我们根据这些信息可以推导出

  • 相机的位置
  • 相机的朝向(垂直与远近裁剪面中心的向量)
  • 近裁剪面的距离
  • 近裁剪面的高度
  • 近裁剪面的宽度
  • 远裁剪面的距离
  • 远裁剪面的宽度
  • 远裁剪面的高度

有了这些信息我们就可以推导出6个平面的方程了。

4.如何判断一个点是否在视锥体内

这个很简单,只要这个点在6个平面中任意一个平面的外部那么这个点就在锥体外,反之这个点在所有平面的内部那么它就在视锥体内部。

如何判断一个点在平面内部还是外部,假定我们使用朝向锥体内部的法线确定的平面方程。那么平面的前面就是法线的方向也就是锥体内部。我们把点带入平面方程,如果大于零,点在平面的前面,也就是锥体的内部。

5.如何判断AABB包围盒是否在视锥体内部

我一开始也会很天真的以为如果AABB的8个点都在视锥体外部那么这个包围体就在视锥体外部了,事实是这样吗?

事实是打脸的,图中的黄色方块,所有点都在外部,但是它和视锥体却是相交的。

那如果所有点都在同一个平面的外部就一定在视锥体外部了吧。这个没错,但是反之错了。

事实再一次打脸,图中橙色的方块,虽然所有点没有在同一个面的外部,但是它却在视锥体的外部。

我们做的是快速判断,为了追求速度不能做更复杂的判断了,二选一选一个吧,选哪一个呢?

当然是选下面的方案了,上面的方案是错误的因为有些物件明明在视锥体中却不能显示,这是一种错误。而下面的方案虽然会额外传递一些无用的物件到gpu中但它至少是正确的,要先保证正确性才能考虑性能优化。

6.齐次空间裁剪

在投影变换后透视除法之前存在一个裁剪空间,这个空间就是齐次裁剪空间,在这个空间中的视锥体是一个以相机为原点,边长为1的立方体。如果点在世界空间中的坐标为(x,y,z),将这个点通过矩阵乘法变换到齐次裁剪空间中(x',y',z'),那么判断(x',y',z')这点是否在视锥体内会变得非常简单。

-1<x'<1 && -1<y'<1 && -1<z'<1或者是w<x'<w && w<y'<w && w<z'<w

满足上面条件的(x,y,z)就在视锥体内。

这个方法实现简单,但是效率不高,因为执行一次坐标变换需要16次乘法+12次加法。

但是如果使用平面方程只需要3次乘法+2次加法。

虽然可以使用sse指令集进行优化,但是平面方程计算也可以使用sse指令优化比如方程为:

Ax + By + Cz + D = 0可以看成是向量(A,B,C,D)和向量(x,y,z,1)的点积,如果用sse4指令集一条指令就可以计算出结果。

因此把点转换到齐次空间中进行判断实现简单,但是并不高效。

为什么这里要提到齐次裁剪空间呢,因为我们在写shader的时候会用到这个变换矩阵,如果代码中可以拿到这个矩阵,我们就可以通过这个矩阵快速的反推出视锥体6个裁剪面的方程,具体实现就不介绍了,这里只是说可以优化求解平面方程的速度。

7.每次都需要判断8个点么?

有更快的算法,首先我们要找出长方体的n点和p点,p点就是距离平面最近的顶点,n点就是最远对角线的顶点(距离p最远的顶点)

如果p在平面外侧那么可以判断这个长方体在平面外侧。

如果p点在平面内侧,n点在平面外侧,说明它们相交。

如果p点和n点都在内侧,则说明长方体在平面内侧。

之前我们需要判断8个点现在只需要判断2个点,多么好的优化。

如何求p点和n点如果是AABB包围盒的话,求法很简单

p = (xmin,ymin,zmin) if (normal.x >= 0) p.x = xmax; if (normal.y >=0)) p.y = ymax; if (normal.z >= 0) p.z = zmax:

n = (xmax,ymax,zmax) if (normal.x >= 0) n.x = xmin; if (normal.y >=0)) n.y = ymin; if (normal.z >= 0) n.z = zmin:

这里的normal是平面的法线向量。

8.还能再快么

这个算法在Game Programming Gems 5 中提到名字叫做Radar Approach - Testing Points 。它使用的算法和之前的算法完全不一样,大体思路是这样的。

首先我们为相机构建一个坐标系,这个坐标系的原点就是相机的位置z轴就是相机的朝向。假定这个坐标系的基向量为x,y,z。

图中红色的点p是被测试的点,蓝色的点是p在z轴的投影。

v = p - cc

p.z =  v • z

v向量是p点的向量表示,z是单位基向量,所以p点的z坐标的值就是v向量和z向量的点积。

如果近裁剪面 < p.z < 远裁剪面,那么这个点在z轴上就在视锥体中了。

同理我们可以求出p.x和p.y,然后拿这两个值和一个平面的长和宽做对比,这个平面就是通过p点且和视线垂直的平面,假想成和远近裁剪面平行的平面。

a为垂直方向的fov,那么h = p.z * 2 * tan(a/2)

-h/2 < pc.y < h/2

(这里的图是h,如果是unity3d的话可以变成w = p.z * 2 * tan(a/2)那么-w/2 < p.x < w/2)

根据宽高比我们可以求出w = h * ratio;则-w/2 < p.x < w/2

这个方法和上面np点的算法到底谁快,我没有测试过。等到后面实现的时候可以做一下性能测试,但是测试的前提是我的demo能加载一个复杂的场景。。。

9.还能再快么

对于基础测试目前我掌握的信息就这些了,如果有大牛还请赐教更快的算法。如果把这些放到gpu计算是个不错的想法。

10.平移旋转一致性测试

这是逻辑上的优化,不是算法层面上的优化,我们假定相机移动的很慢,如果一个AABB被一个平面拒绝,那么下一帧这个平面被拒绝的可能性就会很大,所以我们下次进行测试的时候可以先从这个平面进行。

11.八分测试

这个算法就是把视锥体切成八部分,然后巴拉巴拉,我总觉得这个算法有把简单问题复杂化的意思而且它还有限制所以就没有仔细研究,限制如下图:

使用八分测试来检测包围盒,需要包围盒满足它的中心到它的顶点距离必须小于视锥体中心到视锥体平面的最小距离。也就是图中的d2要小于d1,我总觉得这个算法有把简单问题复杂化的意思。所以就没有仔细研究。

游戏场景管理(二)视锥体剔除相关推荐

  1. 游戏场景管理(四)遮挡剔除

    1.画家算法 早期的gpu是没有z-buffer的,为了得到正确的图像,必须使用画家算法,也就是从后往前绘制几何体.几何体每帧都需要根据摄像机的位置进行排序,进而实现从后往前的绘制.画家算法不仅低效, ...

  2. 游戏场景管理(五)空间划分

    一 前言 空间划分算法有很多,比如均匀网格,四/八叉树,k-d树,Bsp树,每一种算法都有自己的优缺点,我们需要从理论上理解这些算法,然后在实际项目中进行灵活的运用. 游戏中经常使用空间划分算法来优化 ...

  3. 【unity】性能优化之——视锥体剔除(Frustum Culling)(一)

    一.应用背景 在现代游戏中,游戏资源越来越多,游戏场景也越来越大越来越复杂,虽说硬件设备更新迭代很快,性能也日渐强大,但这还远不能缓解复杂繁多的资源带来的性能压力,因而性能优化仍然很有必要.场景资源的 ...

  4. 【Unity】相机视锥体剔除算法

    视锥体剔除是Unity常用的剔除方法,其原理就是通过判定目标包围盒与组成相机视锥体的6个平面进行同侧判定,只要在6个平面之间的包围盒即为可见. 具体原理可见参考以下文章: 视锥体剔除(Frustum ...

  5. 3D游戏场景管理概述

    参考文章 http://www.cnblogs.com/kex1n/archive/2012/08/26/2657054.html 关于场景管理概述 http://www.cnblogs.com/wa ...

  6. 游戏场景管理—四叉树

    内容会持续更新,有错误的地方欢迎指正,谢谢! 场景管理:把不同的物体归属到不同类别里,而相似性的判断是根据物体的空间相干性. 把物体分类的目的:希望下次能快速找到所需的物体,所以更偏向于用四叉树来管理 ...

  7. webgl 视锥体剔除不可见的物体

    这里新的东西就是 包围盒,就是把物体用盒子装起来,这样只需要计算面到这个是否相交,在外边,减少了很多计算量: 这个其实就是计算问题, 视锥体求的那个几个面的公式,自己用就可以了,不要问为什么,推导很麻 ...

  8. 线性八叉树_游戏场景管理的八叉树算法是怎样的?

    最近正好在看吧.就谈一下数据结构. 八叉树特别适合进行空间划分.在需要邻近点信息做参考时,利用八叉树做搜索会非常高效. 八叉树必备的元素:尺寸:一般就是自己限定的空间(有的地方也叫bounding b ...

  9. BSP场景管理方法简介

    BSP(Binary Space Partition,二叉空间分割)方法,在大型3d游戏场景管理方面,可以认为是已经证明了的,最成熟的,最经得起考验的场景管理方法.诸如虚幻系列引擎(Unreal 1, ...

最新文章

  1. 终于有人把Python讲清楚了!
  2. android button背景图片自适应,Android开发之给你的Button加个背景
  3. DBProvider 连接 Oracle 10g 数据库的问题
  4. [ICPC 北京 2017 J题]HihoCoder 1636 Pangu and Stones
  5. 如何找到Angular应用的某个directive是属于哪一个Angular module
  6. java设置框架位置_怎样设置label的位置啊?求指导
  7. 测开5 - Python(模块、操作数据库、操作Excel、加密)
  8. 全球 JavaScript 开发者薪酬揭晓,你拖后腿了吗?
  9. 自学python买什么教材-从自学到编写大学python教材——低调quot;虫师”谢乾坤
  10. 千寻位置 开发demo_CICV2019:博世相对高精度定位与千寻绝对高精度定位
  11. PHP点餐系统源码附小程序点餐系统
  12. 盘点:2012中国互联网大会十大亮点
  13. matlab 文本分析工具,MATLAB,Simulink. - Text Analytics , 文本分析工具箱-鈦思科技
  14. 使用C++实现FC红白机模拟器 概述
  15. Redhat8: SCTP: type= 5 errno= <0x5e> Socket type not supported
  16. js 打开选择本地文件对话框 及 获取选择文件中的内容
  17. 计算机网络-哈尔滨工业大学mooc-第2周作业解答
  18. 实验一 |彩色空间rgb和yuv的相互转换
  19. Regionals 2014 Asia - Daejeon
  20. Cadence基础知识4(焊盘制作比较重要的3点以及热风焊盘的作用和制作 )

热门文章

  1. 开放式激光振镜+运动控制器(一):硬件接口
  2. F1V3.0-图形-OpenLayers2体系分析
  3. OSPF及一类LSA、二类LSA
  4. 欧姆龙PLC协议网关
  5. 2020年第十七届中国研究生数学建模竞赛B题 汽油辛烷值建模
  6. 判断两条线段/直线相交,并求交点
  7. 虚拟机web服务器配置ppt,在Linux虚拟机下配置apache构建web服务器.doc
  8. 图新地球:高中地理教学新大陆(快速查看介绍各种地理地貌、河流百川、行政地区)---带学生领略祖国大好河山
  9. Java开发与Python开发优劣比较
  10. html如何转换成中文,HTML实体与网页编码(汉字转化为了html实体)