首先,让我们了解一下三维成像的基本原理。
stage3D的坐标系是右手坐标系,同openGL,面对屏幕时,x轴指向右,y轴指向上,z轴指向屏幕外(你)。
这个坐标系是模型世界的坐标系,你可以将“1”当作任何单位来制定比例,但为了便于GPU计算,实际用于显示的立体区域,是一个x轴-1至1,y轴-1至1,z轴0至1的立方体,只有在这个立方体内的面片才会被后续步骤计算并显示在屏幕上,并且无论设置的后备缓存面有多大,它的坐标范围都是x轴-1至1,y轴-1至1,z轴0至1的,超出这个范围的内容将被裁剪。
因此,为了将我们的3D世界展现在屏幕上,就必须应用透视矩阵,将世界坐标系缩放转换到上述的立体区域中。
如上,透视矩阵的作用是将世界坐标转化到立体区域中,经过透视矩阵的变换,你会:
——将世界坐标系缩放到立体区域中,并确保你设定的可视范围与立体区域的xy范围对应。
——将你设定的近裁剪面等比缩放为立体区域的0,而远裁剪面缩放为立体区域的1,以确保可视区域的深度与立体区域的z范围对应。
——单轴缩放坐标系,以确保将立方体区域的可视区域坐标系(xy相等,正方形),投影到后备缓存面的实际可视区域坐标系(屏幕,一般是长方形)后,模型不会被拉伸。
——按透视设置,将三角面们投影到二维屏幕上,确保近大远小的关系。
之后,GPU便会按照这个透视矩阵进行计算,以确保达到以上效果了。但是,GPU具体怎么应用这个矩阵取决于着色器。着色器可以在上述基本投影的基础上进行额外的修饰而不影响原始数据,顶点着色器可以修改顶点的最终位置(比如波纹),而像素着色器可以修改贴图的投影方式(比如倒影)。利用着色器,就可以用一个简单的平面实现水波反射的效果了(前提是顶点足够多)。
接下来,让我们探讨一下优化的问题。
很明显,被计算的顶点和像素越少,渲染一帧所用的时间就越少,因此,在不影响用户视觉的前提下,最大限度地减少被渲染的内容,效率也就越高。
也就是说,我们需要剔除用户看不到和不需要看到的内容,而stage3D的API已经为我们准备了一些方式。
首先是背面剔除,你可以在stage3D中设置剔除的三角面朝向。我们通常选择剔除背面,因为背面意味着它背向我们的眼睛。一个模型通常是一个“体”而不是一个“片”,因此有背面就会有正面,而正面应该当完全遮盖住了背面,因此,背面是不需要被渲染的,因为我们看不到它。
在stage3D中,朝向是这样定义的:将构成一个面片的三个顶点正交投影到可视区域的平面上(也就是忽略深度压扁它们),如果它们构成三角面的顺序是顺时针,那么这个三角面是正面,反之,如果是逆时针,那么它是背面。
随后是深度测试,你可以在stage3D中设置深度测试的方式,默认是“小于”。如果在后备缓存面的设置中允许进行深度和模具的测试,那么,GPU将会进行深度测试以确认三角面的遮挡关系。在说明实现方式前,需要注意一个问题,那就是之前提的立方体区域,其z轴是指向屏幕内的,也就是和stage3D坐标系的z轴相反,因为这个z轴表示的是深度,而深度没有必要是负值(负值表示在你身后,那显然是看不到的,这么做没有意义)。这个相反的z轴不会影响模型的正常z轴坐标排序,如果没有应用透视矩阵,而是使用没有经过设置的单位矩阵,那么你一定会发现,将三角面移出0至1的范围后便不会被显示了,因为坐标在数值上是直接对应的。但你要清楚,(0,0,1)是比(0,0,0)要靠近你的,尽管投影到立体区域后,最远的点将位于(0,0,1),而最近的点将位于(0,0,0)。
深度测试的流程是这样的,首先,要确保你在后备缓存面的设置中开启了测试,然后,在清除后备缓存面时重设最初的深度(默认是1,也就是最远的深度),之后,每当有像素被渲染时,便会用它的深度(也就是投影到立体区域后的z轴值)和同样位置(xy坐标)上的原有像素深度做比较,如果满足在stage3D中设置深度测试的条件(默认是小于,也就是比已有的像素更靠近眼睛),才会输出这个像素(默认还会更新这个像素的深度为当前深度,也就是更近的深度),反之弃掉。
这样,通过默认的深度测试,我们就实现了从最远处开始渲染像素,逐层推进到眼前,用离眼睛更近的像素覆盖原有像素,以实现深度排序,并节约了被遮挡的像素的渲染时间。
最后是模具。模具相当于是自定的深度,它的工作原理和深度测试很相似,但它比较的不是深度值,而是自定的模具值,通过设置模具值,我们可以方便地决定哪些像素显示在哪些像素前,而哪些像素根本不显示。在渲染时,模具的值可以多次设置,模具的行为方式也可以自定,具体实现请参考帮助文件,里面有很直观的范例代码。
stage3D的坐标系是右手坐标系,同openGL,面对屏幕时,x轴指向右,y轴指向上,z轴指向屏幕外(你)。
这个坐标系是模型世界的坐标系,你可以将“1”当作任何单位来制定比例,但为了便于GPU计算,实际用于显示的立体区域,是一个x轴-1至1,y轴-1至1,z轴0至1的立方体,只有在这个立方体内的面片才会被后续步骤计算并显示在屏幕上,并且无论设置的后备缓存面有多大,它的坐标范围都是x轴-1至1,y轴-1至1,z轴0至1的,超出这个范围的内容将被裁剪。
因此,为了将我们的3D世界展现在屏幕上,就必须应用透视矩阵,将世界坐标系缩放转换到上述的立体区域中。
如上,透视矩阵的作用是将世界坐标转化到立体区域中,经过透视矩阵的变换,你会:
——将世界坐标系缩放到立体区域中,并确保你设定的可视范围与立体区域的xy范围对应。
——将你设定的近裁剪面等比缩放为立体区域的0,而远裁剪面缩放为立体区域的1,以确保可视区域的深度与立体区域的z范围对应。
——单轴缩放坐标系,以确保将立方体区域的可视区域坐标系(xy相等,正方形),投影到后备缓存面的实际可视区域坐标系(屏幕,一般是长方形)后,模型不会被拉伸。
——按透视设置,将三角面们投影到二维屏幕上,确保近大远小的关系。
之后,GPU便会按照这个透视矩阵进行计算,以确保达到以上效果了。但是,GPU具体怎么应用这个矩阵取决于着色器。着色器可以在上述基本投影的基础上进行额外的修饰而不影响原始数据,顶点着色器可以修改顶点的最终位置(比如波纹),而像素着色器可以修改贴图的投影方式(比如倒影)。利用着色器,就可以用一个简单的平面实现水波反射的效果了(前提是顶点足够多)。
接下来,让我们探讨一下优化的问题。
很明显,被计算的顶点和像素越少,渲染一帧所用的时间就越少,因此,在不影响用户视觉的前提下,最大限度地减少被渲染的内容,效率也就越高。
也就是说,我们需要剔除用户看不到和不需要看到的内容,而stage3D的API已经为我们准备了一些方式。
首先是背面剔除,你可以在stage3D中设置剔除的三角面朝向。我们通常选择剔除背面,因为背面意味着它背向我们的眼睛。一个模型通常是一个“体”而不是一个“片”,因此有背面就会有正面,而正面应该当完全遮盖住了背面,因此,背面是不需要被渲染的,因为我们看不到它。
在stage3D中,朝向是这样定义的:将构成一个面片的三个顶点正交投影到可视区域的平面上(也就是忽略深度压扁它们),如果它们构成三角面的顺序是顺时针,那么这个三角面是正面,反之,如果是逆时针,那么它是背面。
随后是深度测试,你可以在stage3D中设置深度测试的方式,默认是“小于”。如果在后备缓存面的设置中允许进行深度和模具的测试,那么,GPU将会进行深度测试以确认三角面的遮挡关系。在说明实现方式前,需要注意一个问题,那就是之前提的立方体区域,其z轴是指向屏幕内的,也就是和stage3D坐标系的z轴相反,因为这个z轴表示的是深度,而深度没有必要是负值(负值表示在你身后,那显然是看不到的,这么做没有意义)。这个相反的z轴不会影响模型的正常z轴坐标排序,如果没有应用透视矩阵,而是使用没有经过设置的单位矩阵,那么你一定会发现,将三角面移出0至1的范围后便不会被显示了,因为坐标在数值上是直接对应的。但你要清楚,(0,0,1)是比(0,0,0)要靠近你的,尽管投影到立体区域后,最远的点将位于(0,0,1),而最近的点将位于(0,0,0)。
深度测试的流程是这样的,首先,要确保你在后备缓存面的设置中开启了测试,然后,在清除后备缓存面时重设最初的深度(默认是1,也就是最远的深度),之后,每当有像素被渲染时,便会用它的深度(也就是投影到立体区域后的z轴值)和同样位置(xy坐标)上的原有像素深度做比较,如果满足在stage3D中设置深度测试的条件(默认是小于,也就是比已有的像素更靠近眼睛),才会输出这个像素(默认还会更新这个像素的深度为当前深度,也就是更近的深度),反之弃掉。
这样,通过默认的深度测试,我们就实现了从最远处开始渲染像素,逐层推进到眼前,用离眼睛更近的像素覆盖原有像素,以实现深度排序,并节约了被遮挡的像素的渲染时间。
最后是模具。模具相当于是自定的深度,它的工作原理和深度测试很相似,但它比较的不是深度值,而是自定的模具值,通过设置模具值,我们可以方便地决定哪些像素显示在哪些像素前,而哪些像素根本不显示。在渲染时,模具的值可以多次设置,模具的行为方式也可以自定,具体实现请参考帮助文件,里面有很直观的范例代码。