CSDN博客

img John_Cash

Develop Your 3D Engine

发表于2001/12/4 10:55:00  1770人阅读

 

 

背景:

这是Delphi 3D 的3D Engine Dev.系列tutorial。(www.delphi3d.net)

This site is written and maintained by Tom Nuydens.

从基本的view system到高级的PVS(Possible Visible Set),LOD(Level of Detail)都有介绍,难能可贵的是写的深入浅出,别以为Tom Nuydens是某个传奇人物,他22岁,也是刚刚大学毕业,真是不尽牛人滚滚滚来啊!

 

我的翻译:

我最近在看Computer Graphics ,搜到这个站,发现很有用,所以本着learning by doing && share && just for fun的态度翻译(欢迎指正),并加上了一些我的理解和一些Expand(Maths ,some new figures etc.)。So,The Original Delphi 3D Engine Dev. Tutorial Series copyright by Tom Nuyden and this Translation and The Expanded Part copyright by John_Cash:).(底下没标fig 的图都是我用画板画的,苦吧?:(,so, all rights reserved )

 

这是一个长达24篇的教程...长啊...

=========================================

Issue 2 : Visibility determination algorithms(可见性判别算法)

可见性判别---3D Engine 的核心

什么是可见性判别?

3D绘制时要尽量避免重绘,如上图中六面体只有三个面可见,所以其余三个面绘制前应当删除(back face culling)。这只是简单的例子,想象一下,Quake中一关有多少面,要不用VD的话,即使是用硬件绘制也受不了,就能理解可见性判别的重要性了。

       VD的策略选择会极大的影响Engine的效率。很明显,要是每一点都重绘的话,你的Engine就会花大量的时间画看不见的面,从而导致效率的损失;另一方面,要是你追求完美,连一点也不愿意重绘的话(software  rendering 时这点的确很重要),你就要权衡VD算法和部分重绘的代价了。不仅仅是绘制需要考虑VD,在绘制前的视变换(viewing transformation,指从世界坐标系变换到用户坐标系)也很费时,就要尽量减少需要变换的面,当然我们并不需要变换那些看不见的面。

 

       又很多种删除不可见多边形的方法。下面从最基本的开始讨论,后面会涉及到一些高级技术

 

Basic algorithms

       剔除不可见多边形最直接,最简单的方法就是背面删除(back face culling)了。背面删除基于下面的假设:“多边形是封闭多面体的一个面,并且只有一面可见”。想象一下六面体的面,不可见的面有什么特点呢?――――该面的法线和用户视线夹角大于90度。可以用点积表示如图,当点积结果<0时,表示该面不可见。

下一步要做的就是,把你背后的那些面删掉。怎么删?在用户坐标下所有顶点Z<0的那些面。

      还有要做的吗?当然。最后一步就是视见体(view frustum)删除了。

图中浅灰色的即为View Frustum,老外有时管这叫view pyramid,由六个四边形围成。其中深灰色三角形1,在view Frustum 中,不被删除,而2就需要被删了。具体判断使用平面方程:

S(x,y,z)=Ax+By+Cz-D

要是你线性代数还没忘的话,就应当能理解,(A,B,C)给出了平面法线,Sx,y,z)结果就是(x,y,z)点到平面的距离。OK,把待判断的多边形的所有顶点带入S(x,y,z),根据正,负,0值,就可以判断其在平面外,内,上(这与多边形法线的定义有关),从而决定多边形是否被剔除。

       :要是你真忘了的话,我来推一下:

向量形式的平面可以记做:N*(X - P)=0  N为法线,P为平面任一点。

Xx,y,z),NABC)带入,得:Ax+By+Cz=N*P

其中*为点乘。

 Octrees(八叉树)

上面的删除算法,效率还是不高的话,就要用到高级点的技术了。八叉树,本身是二叉树的3D版本。用来将空间递归的划分成立方体子空间(和BSPBinary Space Partition)类似)。例如:(从z轴向下看)

如果可以确定一个子空间不可见的话,那该空间内的所有多边形就可以删除了。麻烦的是,对于可见的子空间内的多边形,Octree并没有提供可见性判别的方法(当然要是划分的太细的话,很可能得不偿失,递归,递规,…..,还想调试吗?)。另外,octree的划分方法很明显适合于直角坐标,你要是用几何坐标的话,可能没那么easy。:)

 

Portal rendering(入口)

 

什么是portal?

空间分割成凸多面体时,一个面切下去,有可能切空了。也就是说,这个面将原来的子空间一分为二时,没有切到多边形,这个面就成为一个portal

图中,左右两个子空间就通过一个portal连起来了(和门的作用差不多)。右图说明,portal是一个不需要绘制的多边形,不阻挡视线。

Portal Rendering 比基本算法多做的就是view frustum 中多边形的删除。由于划分得到的子空间都是凸多面体,所以不存在多边形的排序问题(想象一下,站在一个凸多面体内,当然所有面的绘制顺序没有关系,因为所有面都可见)。算法从观察者所在的区域开始,绘制所有多边形,该区域若存在portal,将这个portal剪裁到视见体内,接着绘制该portal连接的区域。当两个portal相遇时,就需要将后一个剪裁到前一个portal中。如图:

 

当然,如果一个portal最终不可见,那么它连接的区域也就不可见了。

 

Dynamic LOD

      

地形绘制的Engine中常常用到Dynamic LOD(动态 Level of  Detail),用来简化远处的几何体的绘制。比如三角洲里边,远处的地形就会绘制的粗一些,随者你走近,地形就会越来越细致(三角形越来越多)。通常可以用octree来实现,如图:

(这张图来自:www.gametutorials.com)

另一种类似的技术叫:real-time tessellation  是指模型使用不同的精细度以适应不同的要求。

实际上,这两种技术都用于减少要显示的多边形数量(/质量),而非可见性判别。

 

Conclusion

       这就是几种常用的算法,需要更详细的内容,可以去flipcode.com gamedev.net gamasutra.com gametutorials.com 看看。当然一个Engine 可以混用多种技术,比如BSPoctree的混合,octree portal 的混合,etc.

 

下一次:Portal Rendering。(著名的《Duke Nukem Forever》永远的毁灭公爵 就用的是 portal Engine)。

 

0 0

相关博文

我的热门文章

img
取 消
img