(原、整)BSP的江湖传说
@author:黑袍小道
查看随缘,当苦无妨,良人可归。
引言
为什么叫江湖传说,因为实现了第一人是卡马克,就这么简单。(不接受那啥)
Quake3:http://www.mralligator.com/q3/#Nodes
必备
点积和叉积
点积 |
向量乘法的一种形式,它的计算结果是一个标量值;由于这一原因,有时也将点积称为标量积(scalar product)。设u=(ux,uy,uz),v=(vx,vy,vz),则点积定义 简言之点积等于两个向量对应分量的乘积之和。 点积的定义不存在任何明显的几何含义。但是,使用余弦定理可以发现存在如下关系:
|
叉积 |
是向量数学定义的第二种乘法形式。它与点积不同,点积的计算结果是一个标量,而叉积的计算结果是一个向量; 叉积只能用于3D 向量(2D 向量没有叉积)。通过对两个3D 向量u 和v 计算叉积,可以得到第3 个向量w,该向量同时垂直于u 和v。
|
BSP的最小说明
bsp树是一种空间分割树,它主要用于游戏中的场景管理,尤其是室内场景的管理。
它的本质是二叉树,也就是用一个面把空间分割成两部分,分割出的空间则继续用面分割,以此类推,直到到达特定递归深度,或者空间中不再有物体或只剩下一个物体(得到凸包/凸多面体)。
最终,叶结点对应场景中的物体,内部结点存储分割面。物体被"收纳"到各个包围盒中。
BSP的简化说明
简化部分 :
(1) 使用二维,而不是三维。
(2) 手工输入包围盒,而不是自动生成。包围盒为AABB包围盒(轴向),不支持上图中的凹多边形。
(3) 叶结点和内部结点共用一个数据结构。其中内部结点存储了方向(水平或竖直)以及分割线;叶结点存储了对应场景为实心还是空心。
(4) 沿着包围盒的边界进行分割(和图中所示相同),选择分割线的方法比较简单:
首先 |
分别选出水平和竖直方向的最优分割线。(判断标准:与空间中心最接近的包围盒边界线) |
然后 |
|
|
如果都相交或都不相交,那么优先选择距离中心点更近的(按相对比例来算) 如果选择的分割线与包围盒相交,那么把这个包围盒根据分割线拆成两个包围盒。 |
退出条件(或): |
|
|
达到最大分割层数,直接生成两个叶结点,返回。 |
|
空间里没有物体了,返回空叶结点。 |
|
空间里只剩下一个物体了,返回满叶结点。 |
蓝线:第一次分割 ; 紫线:第二次分割 ; 黄线:第三次分割
包围盒:
(4,10,4,16)
(10,24,4,9)
(7,19,23,27)
(22,28,13,24)
bsp树
BSP用于3D游戏
问题:
在当前的摄像机位置使用正确的渲染顺序去渲染所有的将要渲染的几何体的每一帧。
你可能会说.别忘了我可以使用ZBuffer来解决顺序问题.你当然可以使用Zbuffer 但是是在没有透明物体的情况下。
如果有半透明物体.那么你将无法正确的渲染使他正确的显示出来.(ZBuffer是一个深度缓冲相关。如果打开.渲染的时候就会根据渲染点的z值来决定那个点最后显示出来.从而呈现出遮挡的关系.如果是模型中有半透明的部分那么就必须要排序之后进行混合.关键问题就出在blender的顺序上.不透明的必定要先渲染.透明的必定要后渲染)
通过camera到每一个多边形的正确顺序来处理每一帧渲染循环都去解决排序和层次问题.
深度排序问题
上面的图片的渲染情况会出一个问题.当你尝试去从后往前画这两个多边形的时候(画家算法)。两个多边形会不能正确的被画出来,先画红的后画绿的绿色的会把红色的覆盖掉…通过Zbuffer是可以解决这种问题的.但是效率不太好。如果没有硬件加速是非常废系统资源的,但是Zbuffer也不是全能的,它并不能解决半透明问题。
通过BspTree技术可以轻松的解决上述的所有问题,不单如此,还可以处理其他领域的问题如碰撞检测(因为通过BSP渲染技术之后,一帧要渲染哪些多边形是知道的所以计算诸如FPS类型的游戏打枪到墙壁的时候碰撞检测会很简单遍历当前的多边形进行计算就可以了), 多边形剔除算法。
创建一个BspTree是一个离线的过程.你可以在游戏一开始就把bsptree预计算出来。然后游戏里面使用,所有的多边形排序都是预处理出来的。这是Bsp编辑器的工作,传入一个所有的多边形的列表来然后预先排序他们.处理出来的数据可以存到硬盘上.然后游戏运行的时候可以加载进来在游戏循环环境下快速的遍历。
不但BspTree可以用来正确的渲染所有多边形在场景里.而且可以超快速的来剔除当前视点看不见的多边形。
这是因为可以简单的测试多边形在实景,这样所有的后面被遮挡的多边形就会在你的游戏中被剔除掉。
可以简单的就剔除掉成千上万的多边形,我们还将使用bsptree快速的进行碰撞检测。
如何工作的?
看下下面的例图A.他显示了一个从上面看的简单的游戏层级.这些黑色的线就游戏视图里看到的墙.那些黑色的箭头描述了墙的面向的方向.可以理解成2d线的法线.
上面的Ca Cb Cc是三个实例.它表明游戏里的3个位置(相机的位置).通过摄像机的位置先渲染最远的墙.然后渲染最近的墙.我们应该取以下的顺序.
Camera Position |
Correct Drawing Order |
Ca |
D or E in any order, A , C & B is Unclear |
Cb |
D or E in any order, A , B & C is Unclear |
Cc |
C & B is Unclear , A , D or E in any order |
BspTree存储这所有多边形的层级关系,里面都是后面前面或者相邻的多边形。
但是有一个问题就是C和B墙,我们不能明确的描述C在B的前面还是后面。这个问题使我们无法在所有的位置来使用正确顺序来渲染.
因为我们不能描述墙C是在B的前还是后。BSPTree算法将写不出来.我们必须解决这个问题让BspTree能识别这个"前后"处理.这就是二分法…(我们延长B, C会被切割成两个我们叫C1 C2. 之后C1就是B的前 C2就是B的后.BSPTree就适应了)..后面细说.这块还有点抽象.
BSPTree存储多边形的的信息是把世界切成两半.所有的多边形检测哪个在多边形的哪边。
如果相交就切开.成多个之后进行记录.也就说原来的多边形被切成了新的两个多边形。所以我们的第一次分割完成了,我们拥有了两个新的多边形,相当于第一分割出了两个世界。
这两个世界里只有绝对的前面的多边形和绝对的后面的多边形,不会再有模糊的概念,之后这两个世界里的多边形选取一个继续分割。
最后当没有可以分割的就结束该过程了.(如何选取分割的面也是一门科学.)
Front List of split (A) |
Back List of Split (A) |
B , C |
D , E |
Front List of split (B) |
Back List of Split (B) |
Ca |
Cb |
Front List of split (D) |
Back List of Split (D) |
E |
Nothing |
第一次通过A来刨分生成两个空间.后面有 DE 前面有BC..先说前面的B之后继续刨分A前面的世界、
然后把C切分成了Ca Cb.Ca就在B的前世界,Cb就在B的后世界,Ca再分已经没东西了截止。
Cb再分也没东西了截止.
再看A的后面的世界,有D和E,我们选D来刨分,之后D的后面没有东西。
D的前面有E,之后E再分已经没有东西了。结束此过程, BSP创建成功。
最新文章
- bat脚本参数 if goto choice for使用的学习笔记。
- gTest详解
- HTML meta 标签用法(转)
- easyUI datagraid的列排序
- SpringMVC从Controller跳转到另一个Controller
- JSP 和 Servlet 有哪些相同点和不同点,他们之间的联系是什么?
- serv-u and hway3.0
- java 读取mysql库表数据
- 用VSCode开发一个基于asp.net core 2.0/sql server linux(docker)/ng5/bs4的项目(1)
- nyoj 韩信点兵
- 【Java集合系列】---ArrayList
- 【转】Xposed出现 java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
- C++ 引用 指针 使用举例
- 第八章 ArrayBlockingQueue源码解析
- 常用算法的C++实现
- msyql的内存计算
- 关于Quartz 2D绘图的简单使用
- 【树状数组】【P3608】平衡的照片
- 【BZOJ1576】[Usaco2009 Jan]安全路经Travel 最短路+并查集
- Keen Team