导航:首页 > 源码编译 > zbuffer算法

zbuffer算法

发布时间:2023-05-28 12:05:09

1. 数控学习

就想学一门语言,那不难

2. 编程_游戏_算法_War3游戏中的实时阴影是怎么计算的,有没有能参考的算法的代码或者可反编译的游戏例子

7.2.1 阴影体

在3D动作游戏中,GPU往往要面对绘制大量光影效果的场景,而游戏的光影效果越复杂,提供的视觉真实感就越好。但复杂的光影计算往往需要耗费大量的计算资源,导致游戏的运行速度慢如蜗牛。DOOM3就是一个典型的例子,它带来的逼近影视质量的效果令人折服,但过于复杂的光影变换极其耗费GPU的运算资源,导致现在没有几款显卡能够轻松应对。

先来看看3D游戏中阴影的生成原理。在现实世界中,阴影效应因光线被物体遮挡而产生,而在3D环境下同样通过模拟这一机制来创建阴影:将物体沿着光线的方向扩展成一个棱台,该棱台内的所有物体都处于阴影之中,它也被称为“阴影锥”或“阴影体”。那么,GPU如何判断某个物体是否在这个阴影锥内呢?这个时候,就必须用到模板缓冲。模板缓冲好比是蜡染中的蜡层,可以遮罩住3D画面的任意区域,这样,这些区域就暂时不被绘制,之后再对整个画面作光照计算。由于阴影锥内的物体被模板缓冲遮住,光照计算并不会涉及到其中的物体,体现在视觉上就是阴影锥内的物体无法被光线“照到”,阴影效果由此诞生。

实时阴影是一种相对高级的技术,在每一帧,场景中的几何体或灯光位置变动时,要计算一个叫做shadow volume 的物体。shadow volume实际是一个三维物体,是投影物体的轮廓,总是从光源方向投出。

例如飞机模型,投影的物体是一个两翼飞机,在每一帧中飞机的轮廓被计算(使用一个边检测算法,轮廓的每个边要被建立,因为相邻的多边形针对光矢量分别有相反的法线),结果边列表(轮廓的)被投影成一个沿光源方向的三维物体。这个三维物体就叫做shadow volume,而视点在volume里就是在阴影里。

接下来,shadow volume在模板缓冲区中被渲染两次,开始时仅仅正面面对的多边形被渲染,模板缓冲区每次数值被增加。然后背面面对的多边形被渲染,模板缓冲区值被减小。一般来说,所有增加的值和减少的值将互相抵消,但是,因为场景中已经具有被渲染的正常的图元(飞机和地形),当shadow volume被渲染时,一些像素将不能通过zbuffer测试,所有留在模板缓冲区中的值对应的像素处于阴影区。

最后,保留的模板缓冲区内容被用做一个模板,作为一个巨大的全包围的黑方块被alpha-blended到场景中,使用模板缓冲区作为模板,仅仅阴影中的像素是暗的。

前面所介绍的方法,即平面阴影(planar shadow),只适用于平面上。但是,除了少数的情形之外,绝大多数的情形下,根本无法预测阴影会被投射在什么样的表面上。所以需要自由度更高的方法。

在这里介绍一个较为灵活的方法,它可以将阴影投射在不规则的表面上。这个方法称为体积阴影(volumetric shadow)。这个方法的特点在于,它并不是利用“把物体投影到表面”的方式来产生阴影,而是去找出场景中,有哪些像素在阴影中。也就是说,想象一个物体挡住光时,在物体的后面会形成一个大的“阴影锥”。很明显,若一个像素在“阴影锥”之中,那它就是在阴影之中的,如图7-6所示。


3. 计算机图形学复习

第一章
1. 计算机图形:用数学方法描述,通过计算机生成、处理、存储和显示的对象。
2. 图形和图像的主要区别是表示方法不同:图形是用矢量表示;图像是用点阵表示的。图形和图像也可以通过光栅显示器(或经过识别处理)可相互转化。
3. 于计算机图形学紧密相关的学科主要包括 图像处理、计算几何和计算机视觉模式识别。它们的共同点是 以图形/图像在计算机中的表示方法为基础。
4. 交互式计算机图形系统的发展可概括为以下4个阶段:字符、矢量、二维光栅图形、三维图形。
5. 图形学研究的主要内容有:①几何造型技术 ②图形生成技术 ③图形处理技术 ④图形信息的存储、检索与交换技术 ⑤人机交互技术 ⑥动画技术 ⑦图形输入输出技术 ⑧图形标准与图形软件包的研发。
6. 计算机辅助设计和计算机辅助制造 是计算机图形学最广泛最活跃的应用领域。
7. 计算机图形学的基本任务:一是如何利用计算机硬件来实现图形处理功能;二是如何利用好的图形软件;三是如何利用数学方法及算法解决实际应用中的图行处理问题。
8. 计算机图形系统是由硬件系统和软件系统组成的。
9. 计算机图形系统包括处理、存储、交互、输入和输出五种基本功能。
10. 键盘和鼠标是最常用的图形输入设备。鼠标根据测量位移部件的不同,分为光电式、光机式和机械式3种。
11. 数字化仪分为电子式、超声波式、磁伸缩式、电磁感应式等。小型的数字化仪也称为图形输入板。
12. 触摸屏是一种 定位设备,它是一种对于触摸能产生反应的屏幕。
13. 扫描仪由3部分组成:扫描头、控制电路和移动扫描机构。扫描头由光源发射和光鲜接收组成。按移动机构的不同,扫描仪可分为平板式和滚筒式2种。
14. 显示器是计算机的标准输出设备。彩色CRT的显示技术有2种:电子穿透法和荫罩法。
15. 随机扫描是指电子束的定位及偏转具有随意性,电子束根据需要可以在荧光屏任意方向上连续扫描,没有固定扫描线和扫描顺序限制。它具有局部修改性和动态性能。
16. 光栅扫描显示器是画点设备。
17. 点距是指相邻像素点间的距离,与分辨指标相关。
18. 等离子显示器一般有三层玻璃板组成,通常称为等离子显示器的三层结构。
19. 用以输出图形的计算机外部设备称为硬拷贝设备。
20. 打印机是廉价的硬拷贝设备,从机械动作上常为撞击式和非撞击式2种。
21. 常用的喷墨头有:压电式、气泡式、静电式、固体式。
22. 绘图仪分为静电绘图仪和笔式绘图仪。
23. 图形软件的分层。由下到上分别是:①图形设备指令、命令集、计算机操作系统 ②零级图形软件 ③一级图形软件 ④二级图形软件 ⑤三级图形软件。
24. 零级图形软件是面向系统的、最底层的软件,主要解决图形设备与主机的通信与接口问题,又称设备驱动程序。
25. 一级图形软件即面向系统又面向用户,又称基本子系统。
26. 图形应用软件是系统的核心部分。
27. 从物理学角度,颜色以主波长、色纯度和辉度来描述;从视觉角度来看,颜色以色彩、饱和度和亮度来描述。
28. 用适当比列的3种颜色混合,可以获得白色,而且这3种颜色中的任意2种的组合都不能生成第三种颜色,称为三原色理论。
29. RGB模型的匹配表达式是:c=rR+gG+bB。
30. 常用颜色模型
颜色模型名称 使用范围
RGB 图形显示设备(彩色CRT和光栅显示器)
CMY 图形打印、绘制设备
HSV 对应画家本色原理、直观的颜色描述
HSL 基于颜色参数的模型
用基色青、品红、黄定义的CMY颜色模型用来描述硬拷贝设备的输出颜色。它从白光中滤去某种颜色,故称为减色性原色系统。

第二章
31. 直线生成的3个常用算法:数值微分法(DDA)、中点划线法和Bresenham算法。
32. DDA算法的C语言实现:
DDA算法生成直线,起点(x0,y0),终点(x1,y1).
Void CMy View ::OnDdaline()
{
CDC *pDC=GetDC(); //获得设备指针
int x0=100,y0=100,x1=300,y1=200,c=RGB(250,0,0);//定义直线两端点和直线颜色
int x,y,i;
float dx,dy,k;
dx=(float)(x1-x0);
dy=(float)(y1-y0);
k=dy/dx;
x=x0;
y=y0;
if(abs(k)<1)
{ for(;x<=x1;x++)
{pDC—>SetPixel(x,int(y+0.5),c);
y=y+k;}
}
if(abs(k)>=1)
{ for(;y<=y1;y++)
{pDC—>SetPixel(int(x+0.5),y,c);
x=x+1/k;}
}
ReleaseDC(pDC); //释放设备指针
}
33. 任何影响图元显示方法的参数称为属性参数。图元的基本表现是线段,其基本属性包括线型、线宽和色彩。
34. 最常见的线型包括实线、虚线、细线和点划线等,通常默认的线型是实线。
35. 线宽控制的实线方法:垂直线刷子、水平线刷子、方形线刷子。生成具有宽度的线条还可以采用区域填充算法。
36. 用离散量表示连续量时引起的失真现象称为走样。为了提高图形显示质量,减少或消除走样现象的技术称为反走样。
37. 反走样技术有:提高分辨率(硬件方法和软件方法)、简单区域取样、加权区域取样。
38. 区域连通情况分为四连通区域和八连通区域。四连通区域是指从区域上某一点出发,可通过上下左右4个方向移动,在不越出区域的前提下到达区域内的任意像素;八连通区域是指从区域内某一像素出发,可通过上下左右、左上左下、右上右下8个方向的移动,在不越出区域的前提下到达区域内的任意像素。
39. 字符的图形表示可以分为点阵式和矢量式两种形式。
40. 在图形软件中,除了要求能生成直线、圆等基本图形元素外,还要求能生成其他曲线图元、多边形及符号等多种图元。
41. 在扫描线填充算法中,对水平边忽略而不予处理的原因是实际处理时不计其交点。
42. 关于直线生成算法的叙述中,正确的是:Bresenham算法是对中点画线算法的改进。
43. 在中点画圆算法中叙述错误的是:为了减轻画圆的工作量,中点画圆利用了圆的四对称性性质。
44. 多边形填充时,下列论述错误的是:在判断点是否在多边形内时,一般通过在多变形外找一点,然后根据该线段与多边形的交点数目为偶数即可认为在多边形内部,若为奇数则在多边形外部,且不考虑任何特殊情况。
第三章
1. Cohen-Sutherland算法,也称编码裁剪法。其基本思想是:对于每条待裁剪的线段P1P2分三种情况处理:①若P1P2完全在窗口内,则显示该线段,简称“取”之;②若P1P2完全在窗口外,则丢弃该线段,简称“舍”之;③若线段既不满足“取”的条件也不满足“舍”的条件,则求线段与窗口边界的交点,在交点处把线段分为两段,其中一段 完全在窗口外,可舍弃之,然后对另一段重复上述处理。
2. Sutherland-Hodgman算法,又称逐边裁剪算法。其基本思想是用窗口的四条边所在的直线依次来裁剪多边形。多边形的每条边与裁剪线的位置关系有4种情况(假设当前处理的多边形的边为SP):a>端点S在外侧,P在内侧,则从外到内输出P和I;b>端点S和P都在内侧,则从内到内输出P;c>端点S在内侧,而P在外侧,则从内到外输出I;d>端点S和P都在外侧,无输出。
3. 按裁剪精度的不同,字符裁剪可分为三种情况:字符串裁剪、字符裁剪和笔画裁剪。
4. 在线段AB的编码裁剪算法中,如A、B两点的码逻辑或运算全为0,则该线段位于窗口内;如AB两点的码逻辑与运算结果不为0,则该线段在窗口外。
5. n边多边形关于矩形窗口进行裁剪,结果多边形最多有2n个顶点,最少有n个顶点。
6. 对一条等长的直线段裁剪,编码裁剪算法的速度和中点分割算法的裁剪速度哪一个快,无法确定。(√)
7. 多边形裁剪可以看做是线段裁剪的组合。(X)
8. 对于线段来说,中点分割算法要比其他线段裁剪算法的裁剪速度快。(X)
9. 多边形的Weiler-Atherton裁剪算法可以实现对任意多边形的裁剪。(√)
第四章
1. 几何变换是指改变几何形状和位置,非几何变换是指改变图形的颜色、线型等属性。变换方法有对象变换(坐标系不动)和坐标变换(坐标系变化)两种。
2. 坐标系可以分为以下几种:世界坐标系(是对计算机图形场景中所有图形对象的空间定位和定义,是其他坐标系的参照)、模型坐标系(用于设计物体的局部坐标系)、用户坐标系(为了方便交互绘图操作,可以变换角度、方向)、设备坐标系(是绘制或输出图形的设备所用的坐标系,采用左手系统)。
3. 将用户坐标系中需要进行观察和处理的一个坐标区域称为窗口,将窗口映射到显示设备上的坐标区域称为视区。从窗口到视区的变换,称为规格化变换。(eg.4-1)
4. 所谓体素,是指可以用有限个尺寸参数定位和定形的体,如长方体、圆锥体。
5. 所谓齐次坐标表示,就是用n+1维向量表示n维的向量。
6. 二维点(x,y)的齐次坐标可以表示为:(hx hy h),其中h≠0。当h=1时称为规范化的齐次坐标,它能保证点集表示的唯一性。
7. 旋转变换公式的推导、对称变换

第五章
1. 交互绘图技术是一种处理用户输入图形数据的技术,是设计交互绘图系统的基础。常见的交互绘图技术有:定位技术、橡皮筋技术、拖曳技术、定值技术、拾取技术、网格与吸附技术。
2. 常用的橡皮筋技术有:橡皮筋直线、橡皮筋矩形、橡皮筋圆。
3. 拖曳技术是将形体在空间移动的过程动态地、连续地表示出来,直到用户满意。
4. 定值技术有2种:一种是键入数值,另一种是改变电位计阻值产生要求的数量,可以用模拟的方式实现电位计功能。
5. 拾取一个基本的对象可以通过:指定名称法、特征点发、外界矩阵法、分类法、直接法。

第六章
1. 点、线、面是形成三维图形的基础,三维变换是从点开始。
2. 三维图形变换分类:三维图形变换包括三维几何变换和平面几何变换,三维几何变换包括基本几何变换和复合变换;平面几何变换包括平行投影和透视投影,平行投影包括正投影和轴测投影,透视投影包括一点透视、二点透视、三点透视。
3. 投影中心与投影面之间的距离是无限的投影叫做平行投影,它包括正投影和轴测投影。
4. 正投影形成的视图包括:主视图、俯视图和左视图。轴测投影形成的视图为轴测图。
5. 透视投影也称为中心投影,其投影中心与投影面之间的距离是有限的。其特点是产生近大远小的视觉效果
6. 对于透视投影,不平行于投影面的平行线的投影会汇聚到一个点,这个点称为灭点。透视投影的灭点有无限多个,与坐标轴平行的平行线在投影面上形成的灭点称为主灭点。主灭点最多有3个,其对应的透视投影分别称为一点透视、二点透视、三点透视。

第七章
1. 型值点是曲面或曲线上的点,而控制点不一定在曲线曲面上,控制点的主要目的是用来控制曲线曲面的形状。
2. 插值和逼近是曲线曲面设计中的两种不同方法。插值—生成的曲线曲面经过每一个型值点,逼近—生成的曲线曲面靠近每一个控制点。
3. 曲线曲面的表示要求:唯一性、统一性、几何不变性、几何直观、易于界定、易于光滑连接。
4. 曲线曲面有参数和非参数表示,但参数表示较好。非参数表示又分为显式和隐式两种。
5. 对于一个平面曲线,显式表示的一般形式是:y=f(x)。一个x与一个y对应,因此显式方程不能表示封闭或多值曲线。例不能用显式方程表示一个圆。
6. 如果一个曲线方程表示为f(x,y)=0的形式,我们称之为隐式表示。其优点是易于判断函数f(x,y)是否大于、小于或等于零,即易于判断是落在所表示曲线上还是在曲线的哪一侧。
7. 参数连续与几何连续的区别:参数连续性是传统意义上的、严格的连续,而几何连续性只需限定两个曲线段在交点处的参数导数成比例,不必完全相等,是一种更直观、易于交互控制的连续性。
8. 在曲线曲面造型中,一般只用到C1(1阶参数连续)、C2(2阶参数连续)、G1(1阶几何连续)、G2(2阶几何连续)。切矢量(一阶导数)反映了曲线对参数t的变化速递,曲率(二阶导数)反映了曲线对参数t变化的加速度。
9. 通常C1连续必能保证G1的连续,但G1的连续并不能保证C1连续。
10. 对于三次Hermite曲线,用于描述曲线的可供选择的条件有:端点坐标、切矢量和曲率。
11. 三次Hermite曲线特点:①可局部调整,因为每个曲线段仅依赖于端点约束;②基于Hermite样条的变化形式有Cardinal样条和Kochanek-Bartels样条;③具有几何不变性。
12. Bezier曲线的性质:①端点性质②端点切矢量③端点的曲率④对称性⑤几何不变性⑥凸包性⑦变差缩减性。
13. 一次Bezier曲线是连接起点P0和终点P1的直线段,二次Bezier曲线对应一条起点P0终点在P2处的抛物线。
14. B样条曲线的性质:①局部性②连续性或可微性③几何不变性④严格凸包性⑤近似性⑥变差缩减性。
15. NURRS曲线具有以下性质:①局部性②可微性③仿射不变性④严格保凸性⑤一般性⑥变差缩减性⑦端点性质。

第八章
1. 要把三维物体的信息显示在二维显示设备中,必须通过投影变换。由于投影变换失去了深度信息,往往会导致二义性,要消除二义性,就必须在绘制时消除实际不可见的线和面,称作消除隐藏线和隐藏面,简称消隐。
2. 面消隐常用算法有:深度缓冲区(Z-buffer)算法和深度排序算法(画家算法)。
3. 深度缓冲区算法和深度排序算法的区别:

4. 3D游戏和2D游戏的制作方面那个难

你说的异常的难是指哪方面?

个人浅见:
2D难在素材和算法。

比如说isometric对大物体的遮挡关系处理等,3D有了zbuffer,处理起来很简单,2D算法虽然速度比3D快,但因为缺少一个维度的数据,不存在完美的算法,所以处理起来比较复杂。

即便是纯2D,素材也是一个问题。因为手绘2D素材需要美术功力,成本比3D要高得多。虽然可以从3D生成2D, 但是可能达不到2D素材的质量。不过因为没有硬件上的限制,渲染速度快,2D图形可以做得看起来比3D的更为精美。

如果是引擎上的比较,一般只同2D和3D引擎做得是否易用有关,同2D/3D无关。

5. 等值面的等值面生成算法

Cuberille方法
· Cuberrille等值面方法又称Opaque Cube算法,最初由Herman等人提出,后来又多次改进。算法主要分为两个步骤:
· (1) 确定边界单元
对于规则网格数据,其网格单元可看成是正六面体单元,整个三维数据就是由这种正六面体组成的,这种组成三维图象的基本正六面体单元称为体元。对于给定的阈值Ft,遍历体数据中的各个单元,将组成体元8个顶点上的值与Ft进行比较,找出顶点值跨越Ft的所有体元,即体元中有的顶点值大于阈值,有的顶点值小于阈值,因此体元内包含等值面片,这就是边界单元。
(2) 绘制各边界单元的6个多边形面,即将等值面看成是由各单元的六个外表面拼合而成
每个单元均为一正六面体,包括6个多边形面。对组成所有边界体元的多边形面进行绘制,即可产生最终的图象结果。在绘制多边形过程中应采用合适的光照模型和消隐技术。
如果在具有硬件深度缓存(Z-buffer)功能的计算机上运行立方体方法,可以将这组多边形不分次序地提交给硬件,由硬件完成消除隐藏面的任务。如果以软件方式执行立方体方法,在算法中必须考虑多边形的遮挡问题。一个有效的方法是把遍历体元集合与显示两个步骤合二为一,遍历体元集合时采用从后至前的次序。发现一个边界体元,就立刻显示它的6个面。后显示到屏幕上去的多边形将覆盖先显示的多边形,这样就达到了消除隐藏面的目的,这就是画家算法的思想。
Marching Cubes(MC)方法
Marching Cubes(移动立方体)方法是由W.E.Lorenson和H.E.Cline在1987年提出来的。由于这一方法原理简单,易于实现,目前已经得到了较为广泛的应用,成为三维数据等值面生成的经典算法,Marching Cubes算法又简称为MC算法。MC方法的原理如下:
在Marching Cubes方法中,假定原始数据是离散的三维空间规则数据,一个体元定义为由相邻层上的8个顶点组成的一个长方体。为了在三维数据中构造等值面,应先给定所求等值面的值,该方法的基本原理是逐个处理所有的体元,将体元各顶点处的值与给定的阈值进行比较,首先找出与等值面相交的体元,然后通过插值求等值面与体元棱边的交点,并将各交点连成三角形来构成等值面片,所有体元中的三角形集合就构成了等值面。由于这一方法是逐个处理所有的体元,因此被称为Marching Cubes方法。 在W.E.Lorenson和H.E.Cline于1987年提出Marching Cubes方法之后不久,他们就发现,当离散三维数据的密度很高时,由Marching Cubes方法在体元中产生的小三角面片常常很小,在图像空间中的投影面积与屏幕上一个像素点的大小差不多,甚至还要小,因此,通过插值来计算小三角面片是不必要的。随着新一代CT和MRI等设备的出现,二维切片中图象的分辨率不断提高,断层不断变薄,已经接近并超过计算机屏幕显示的分辨率。在这种情况下,常用于三维表面生成的Marching Cubes方法已不适用。于是,在1988年,仍由W.E.Lorenson和H.E.Cline两人提出了剖分立方体(Dividing Cubes)方法。

6. Unity Shader-渲染队列,ZTest,ZWrite,Early-Z(转)

简介

在渲染阶段,引擎所做的工作是把所有场景中的对象按照一定的策略(顺序)进行渲染。最早的是画家算法,顾名思义,就是像画家画画一样,先画后面的物体,如果前面还有物体,那么就用前面的物体把物体覆盖掉,不过这种方式由于排序是针对物体来排序的,而物体之间也可能有重叠,所以效果并不好。所以目前更加常用的方式是z-buffer算法,类似颜色缓冲区缓冲颜色,z-buffer中存储的是当前的深度信息,对于每个像素存储一个深度值,这样,我们屏幕上显示的每个像素点都会进行深度排序,就可以保证绘制的遮挡关系是正确的。而控制z-buffer就是通过ZTest,和ZWrite来进行。但是有时候需要更加精准的控制不同类型的对象的渲染顺序,所以就有了渲染队列。今天就来学习一下渲染队列,ZTest,ZWrite的基本使用以及分析一下Unity为了Early-Z所做的一些优化。

Unity中的几种渲染队列

首先看一下Unity中的几种内置的渲染队列,按照渲染顺序,从先到后进行排序,队列数越小的,越先渲染,队列数越大的,越后渲染。

Unity中设置渲染队列也很简单,我们不需要手动创建,也不需要写任何脚本,只需要在shader中增加一个Tag就可以了,当然,如果不加,那么就是默认的渲染队列Geometry。比如我们需要我们的物体在Transparent这个渲染队列中进行渲染的话,就可以这样写:

我们可以直接在shader的Inspector面板上看到shader的渲染队列:

另外,我们在写shader的时候还经常有个Tag叫RenderType,不过这个没有Render Queue那么常用,这里顺便记录一下:
Opaque : 用于大多数着色器(法线着色器、自发光着色器、反射着色器以及地形的着色器)。
Transparent :用于半透明着色器(透明着色器、粒子着色器、字体着色器、地形额外通道的着色器)。
TransparentCutout : 蒙皮透明着色器(Transparent Cutout,两个通道的植被着色器)。
Background : 天空盒着色器。
Overlay : GUITexture,镜头光晕,屏幕闪光等效果使用的着色器。
TreeOpaque : 地形引擎中的树皮。
TreeTransparentCutout : 地形引擎中的树叶。
TreeBillboard : 地形引擎中的广告牌树。
Grass : 地形引擎中的草。
GrassBillboard : 地形引擎何中的广告牌草。

相同渲染队列中不透明物体的渲染顺序

拿出Unity,创建三个立方体,都使用默认的bump diffuse shader(渲染队列相同),分别给三个不同的材质(相同材质的小顶点数的物体引擎会动态合批),用Unity5带的Frame Debug工具查看一下Draw Call。(Unity5真是好用得多了,如果用4的话,还得用NSight之类的抓帧)

可以看出,Unity中对于不透明的物体,是采用了从前到后的渲染顺序进行渲染的,这样,不透明物体在进行完vertex阶段,进行Z Test,然后就可以得到该物体最终是否在屏幕上可见了,如果前面渲染完的物体已经写好了深度,深度测试失败,那么后面渲染的物体就直接不会再去进行fragment阶段。(不过这里需要把三个物体之间的距离稍微拉开一些,本人在测试时发现,如果距离特别近,就会出现渲染次序比较乱的情况,因为我们不知道Unity内部具体排序时是按照什么标准来判定的哪个物体离摄像机更近,这里我也就不妄加猜测了)

相同渲染队列中半透明物体的渲染顺序

透明物体的渲染一直是图形学方面比较蛋疼的地方,对于透明物体的渲染,就不能像渲染不透明物体那样多快好省了,因为透明物体不会写深度,也就是说透明物体之间的穿插关系是没有办法判断的,所以半透明的物体在渲染的时候一般都是采用从后向前的方法进行渲染,由于透明物体多了,透明物体不写深度,那么透明物体之间就没有所谓的可以通过深度测试来剔除的优化,每个透明物体都会走像素阶段的渲染,会造成大量的Over Draw。这也就是粒子特效特别耗费性能的原因。

我们实验一下Unity中渲染半透明物体的顺序,还是上面的三个立方体,我们把材质的shader统一换成粒子最常用的Particle/Additive类型的shader,再用Frame Debug工具查看一下渲染的顺序:

半透明的物体渲染的顺序是从后到前,不过由于半透相关的内容比较复杂,就先不在这篇文章中说了,打算另起一篇。

自定义渲染队列

Unity支持我们自定义渲染队列,比如我们需要保证某种类型的对象需要在其他类型的对象渲染之后再渲染,就可以通过自定义渲染队列进行渲染。而且超级方便,我们只需要在写shader的时候修改一下渲染队列中的Tag即可。比如我们希望我们的物体要在所有默认的不透明物体渲染完之后渲染,那么我们就可以使用Tag{“Queue” = “Geometry+1”}就可以让使用了这个shader的物体在这个队列中进行渲染。

还是上面的三个立方体,这次我们分别给三个不同的shader,并且渲染队列不同,通过上面的实验我们知道,默认情况下,不透明物体都是在Geometry这个队列中进行渲染的,那么不透明的三个物体就会按照cube1,cube2,cube3进行渲染。这次我们希望将渲染的顺序反过来,那么我们就可以让cube1的渲染队列最大,cube3的渲染队列最小。贴出其中一个的shader:

其他的两个shader类似,只是渲染队列和输出颜色不同。

通过渲染队列,我们就可以自由地控制使用该shader的物体在什么时机渲染。比如某个不透明物体的像素阶段操作较费,我们就可以控制它的渲染队列,让其渲染更靠后,这样可以通过其他不透明物体写入的深度剔除该物体所占的一些像素。

PS:这里貌似发现了个问题,我们在修改shader的时候一般不需要什么其他操作就可以直接看到修改后的变化,但是本人改完渲染队列后,有时候会出现从shader的文件上能看到渲染队列的变化,但是从渲染结果以及Frame Debug工具中并没有看到渲染结果的变化,重启Unity也没有起到作用,直到我把shader重新赋给材质之后,变化才起了效果...(猜测是个bug,因为看到网上还有和我一样的倒霉蛋被这个坑了,本人的版本是5.3.2,害我差点怀疑昨天是不是喝了,刚实验完的结果就完全不对了...)

**ZTest(深度测试)和ZWrite(深度写入) **

上一个例子中,虽然渲染的顺序反了过来,但是物体之间的遮挡关系仍然是正确的,这就是z-buffer的功劳,不论我们的渲染顺序怎样,遮挡关系仍然能够保持正确。而我们对z-buffer的调用就是通过ZTest和ZWrite来实现的。

首先看一下ZTest,ZTest即深度测试,所谓测试,就是针对当前对象在屏幕上(更准确的说是frame buffer)对应的像素点,将对象自身的深度值与当前该像素点缓存的深度值进行比较,如果通过了,本对象在该像素点才会将颜色写入颜色缓冲区,否则否则不会写入颜色缓冲。ZTest提供的状态较多。 ZTest Less(深度小于当前缓存则通过, ZTest Greater(深度大于当前缓存则通过),ZTest LEqual(深度小于等于当前缓存则通过),ZTest GEqual(深度大于等于当前缓存则通过),ZTest Equal(深度等于当前缓存则通过),ZTest NotEqual(深度不等于当前缓存则通过),ZTest Always(不论如何都通过)。注意,ZTest Off等同于ZTest Always,关闭深度测试等于完全通过。

下面再看一下ZWrite,ZWrite比较简单,只有两种状态, ZWrite On(开启深度写入)和ZWrite Off(关闭深度写入) 。当我们开启深度写入的时候,物体被渲染时针对物体在屏幕(更准确地说是frame buffer)上每个像素的深度都写入到深度缓冲区;反之,如果是ZWrite Off,那么物体的深度就不会写入深度缓冲区。但是,物体是否会写入深度,除了ZWrite这个状态之外,更重要的是需要深度测试通过,也就是ZTest通过,如果ZTest都没通过,那么也就不会写入深度了。就好比默认的渲染状态是ZWrite On和ZTest LEqual,如果当前深度测试失败,说明这个像素对应的位置,已经有一个更靠前的东西占坑了,即使写入了,也没有原来的更靠前,那么也就没有必要再去写入深度了。所以上面的ZTest分为通过和不通过两种情况,ZWrite分为开启和关闭两种情况的话,一共就是四种情况:

1.深度测试通过,深度写入开启:写入深度缓冲区,写入颜色缓冲区;
2.深度测试通过,深度写入关闭:不写深度缓冲区,写入颜色缓冲区;
3.深度测试失败,深度写入开启:不写深度缓冲区,不写颜色缓冲区;
4.深度测试失败,深度写入关闭:不写深度缓冲区,不写颜色缓冲区;

Unity中默认的状态(写shader时什么都不写的状态)是ZTest LEqual和ZWrite On,也就是说默认是开启深度写入,并且深度小于等于当前缓存中的深度就通过深度测试,深度缓存中原始为无限大,也就是说离摄像机越近的物体会更新深度缓存并且遮挡住后面的物体。如下图所示,前面的正方体会遮挡住后面的物体:

写几个简单的小例子来看一下ZTest,ZWrite以及Render Queue这几个状态对渲染结果的控制。

让绿色的对象不被前面的立方体遮挡,一种方式是关闭前面的蓝色立方体深度写入:

通过上面的实验结果,我们知道,按照从前到后的渲染顺序,首先渲染蓝色物体,蓝色物体深度测试通过,颜色写入缓存,但是关闭了深度写入,蓝色部分的深度缓存值仍然是默认的Max,后面渲染的绿色立方体,进行深度测试仍然会成功,写入颜色缓存,并且写入了深度,因此蓝色立方体没有起到遮挡的作用。
另一种方式是让绿色强制通过深度测试:

这个例子中其他立方体的shader使用默认的渲染方式,绿色的将ZTest设置为Always,也就是说不管怎样,深度测试都通过,将绿色立方体的颜色写入缓存,如果没有其他覆盖了,那么最终的输出就是绿色的了。

那么如果红色的也开了ZTest Always会怎么样?

在红色立方体也用了ZTest Always后,红色遮挡了绿色的部分显示为了红色。如果我们换一下渲染队列,让绿色在红色之前渲染,结果就又不一样了:

更换了渲染队列,让绿色的渲染队列+1,在默认队列Geometry之后渲染,最终重叠部分又变回了绿色。可见,当ZTest都通过时,上一个写入颜色缓存的会覆盖上一个,也就是说最终输出的是最后一个渲染的对象颜色。

再看一下Greater相关的部分有什么作用,这次我们其他的都使用默认的渲染状态,绿色的立方体shader中ZTest设置为Greater:

这个效果就比较好玩了,虽然我们发现在比较深度时,前面被蓝色立方体遮挡的部分,绿色的最终覆盖了蓝色,是想要的结果,不过其他部分哪里去了呢?简单分析一下,渲染顺序是从前到后,也就是说蓝色最先渲染,默认深度为Max,蓝色立方体的深度满足LEqual条件,就写入了深度缓存,然后绿色开始渲染,重叠的部分的深度缓存是蓝色立方体写入的,而绿色的深度值满足大于蓝色深度的条件,所以深度测试通过,重叠部分颜色更新为绿色;而与红色立方体重合的部分,红色立方体最后渲染,与前面的部分进行深度测试,小于前面的部分,深度测试失败,重叠部分不会更新为红色,所以重叠部分最终为绿色。而绿色立方体没有与其他部分重合的地方为什么消失了呢?其实是因为绿色立方体渲染时,除了蓝色立方体渲染的地方是有深度信息的,其他部分的深度信息都为Max,蓝色部分用Greater进行判断,肯定会失败,也就不会有颜色更新。
有一个好玩的效果其实就可以考ZTest Greater来实现,就是游戏里面经常出现的,当玩家被其他场景对象遮挡时,遮挡的部分会呈现出X-光的效果;其实是在渲染玩家时,增加了一个Pass,默认的Pass正常渲染,而增加的一个Pass就使用Greater进行深度测试,这样,当玩家被其他部分遮挡时,遮挡的部分才会显示出来,用一个描边的效果渲染,其他部分仍然使用原来的Pass即可。

Early-Z技术

传统的渲染管线中,ZTest其实是在Blending阶段,这时候进行深度测试,所有对象的像素着色器都会计算一遍,没有什么性能提升,仅仅是为了得出正确的遮挡结果,会造成大量的无用计算,因为每个像素点上肯定重叠了很多计算。因此现代GPU中运用了Early-Z的技术,在Vertex阶段和Fragment阶段之间(光栅化之后,fragment之前)进行一次深度测试,如果深度测试失败,就不必进行fragment阶段的计算了,因此在性能上会有很大的提升。但是最终的ZTest仍然需要进行,以保证最终的遮挡关系结果正确。前面的一次主要是Z-Cull为了裁剪以达到优化的目的,后一次主要是Z-Check,为了检查,如下图:

Early-Z的实现,主要是通过一个Z-pre-pass实现,简单来说,对于所有不透明的物体(透明的没有用,本身不会写深度),首先用一个超级简单的shader进行渲染,这个shader不写颜色缓冲区,只写深度缓冲区,第二个pass关闭深度写入,开启深度测试,用正常的shader进行渲染。其实这种技术,我们也可以借鉴,在渲染透明物体时,因为关闭了深度写入,有时候会有其他不透明的部分遮挡住透明的部分,而我们其实不希望他们被遮挡,仅仅希望被遮挡的物体半透,这时我们就可以用两个pass来渲染,第一个pass使用Color Mask屏蔽颜色写入,仅写入深度,第二个pass正常渲染半透,关闭深度写入。

关于Early-Z技术可以参考ATI的论文Applications of Explicit Early-Z Culling以及PPT,还有一篇Intel的文章。

Unity渲染顺序总结

如果我们先绘制后面的物体,再绘制前面的物体,就会造成over draw;而通过Early-Z技术,我们就可以先绘制较近的物体,再绘制较远的物体(仅限不透明物体),这样,通过先渲染前面的物体,让前面的物体先占坑,就可以让后面的物体深度测试失败,进而减少重复的fragment计算,达到优化的目的。Unity中默认应该就是按照最近距离的面进行绘制的,我们可以看一下Unity官方的文档中显示的:

从文档给出的流程来看,这个Depth-Test发生在Vertex阶段和Fragment阶段之间,也就是上面所说的Early-Z优化。
简单总结一下Unity中的渲染顺序: 先渲染不透明物体,顺序是从前到后;再渲染透明物体,顺序是从后到前

Alpha Test(Discard)在移动平台消耗较大的原因

从本人刚刚开始接触渲染,就开始听说移动平台Alpha Test比较费,当时比较纳闷,直接discard了为什么会费呢,应该更省才对啊?这个问题困扰了我好久,今天来刨根问底一下。还是跟我们上面讲到的Early-Z优化。正常情况下,比如我们渲染一个面片,不管是否是开启深度写入或者深度测试,这个面片的光栅化之后对应的像素的深度值都可以在Early-Z(Z-Cull)的阶段判断出来了;而如果开启了Alpha Test(Discard)的时候,discard这个操作是在fragment阶段进行的,也就是说这个面片光栅化之后对应的像素是否可见,是在fragment阶段之后才知道的,最终需要靠Z-Check进行判断这个像素点最终的颜色。其实想象一下也能够知道,如果我们开了Alpha Test并且还用Early-Z的话,一块本来应该被剃掉的地方,就仍然写进了深度缓存,这样就会造成其他部分被一个完全没东西的地方遮挡,最终的渲染效果肯定就不对了。所以,如果我们开启了Alpha Test,就不会进行Early-Z,Z Test推迟到fragment之后进行,那么这个物体对应的shader就会完全执行vertex shader和fragment shader,造成over draw。有一种方式是使用Alpha Blend代替Alpha Test,虽然也很费,但是至少Alpha Blend虽然不写深度,但是深度测试是可以提前进行的,因为不会在fragment阶段再决定是否可见,因为都是可见的,只是透明度比较低罢了。不过这样只是权宜之计,Alpha Blend并不能完全代替Alpha Test。

关于Alpha Test对于Power VR架构的GPU性能的影响,简单引用一下官方的链接以及一篇讨论帖:

最后再附上两篇参考文章

http://blog.csdn.net/candycat1992/article/details/41599167
http://blog.csdn.net/arundev/article/details/7895839

阅读全文

与zbuffer算法相关的资料

热点内容
小城与小妈去北京旅游叫什么小说 浏览:230
pdf阅读器推荐 浏览:81
能免费看英语电影的软件 浏览:125
有部电影女主半夜出去卖淫 浏览:628
西门子编程试题 浏览:82
android转动360 浏览:334
服务器为什么要重装系统 浏览:438
华为尝鲜怎么还是原来的安卓系统 浏览:595
女主是警察的小说 浏览:792
魔兽宏命令是什么 浏览:250
《法国空姐》啄木鸟种子 浏览:95
超清播放网站 浏览:39
索尼传送app为什么华为用不了 浏览:225
linux命令at 浏览:221
阿里程序员厉害 浏览:195
iappqq飞车美化源码 浏览:389
51单片机跑马灯c程序 浏览:930
adm压缩及解压代码 浏览:853
xp如何制作打印机服务器 浏览:24
张天佑小说蛇 浏览:23