在上一节通过简单的几步操作,就将3d场景显示在在2维屏幕里了。在这里可以将场景渲染到一张贴图里,如何实现呢?
1. 在Tex目录通过如下方式新建一个RenderTexture,取名为HelloRender,
建好后如下图所示
2. 将Main Camera的TargetTexture属性设置为HelloRender,设置好后,如下图所示
然后运行程序,3D场景不在渲染在屏幕里,而是渲染到HelloRender这个贴图里,如下图所示。
3D场景无论是渲染到屏幕还是渲染到贴图里,最终3D场景将转化为2D图形。那么Unity是如何将3D场景转换为2d图形的呢?实际上是通过渲染管线来实现的。渲染管线可以简单的理解为渲染流程。渲染流程分为3个阶段:应用程序阶段,几何阶段,光栅化阶段。下面的图形可以很清楚的展示这三个阶段:
1. 应用程序阶段
这个阶段主要是告诉CPU需要渲染的物体,以及物体的属性。这个阶段的末端将物体顶点数据,贴图,通过数据总线传送给GPU,让GPU进行下一阶段的处理。
接下来创建一个脚本Test.cs,并在Start()方法加上如下语句GameObject.CreatePrimitive(PrimitiveType.Cube);然后在MainCamera添加Test组件。当运行程序时,将会在场景添加一个Cube,这条语句执行阶段就是应用程序执行阶段。
2. 几何阶段
这个阶段主要完成2件事:顶点坐标变换,光照计算。
2.1.顶点坐标变换:
从上面的图可以看出,顶点的坐标系分为对象坐标系,世界坐标系,视图坐标系,投影坐标系。
a.对象坐标系是物体自身的坐标系,提交给GPU的顶点数据都是基于对象坐标系,因此需要进行坐标变换。
b.世界坐标系是场景所有物体的参考坐标系。
c.视图坐标系是以摄像机的位置为原点,观察方向为z轴,视椎体上下面的交界线为x轴,视椎体左右面的交界线为Y轴。
d.投影坐标系,是一个单位立方体。
坐标变换实际上是将顶点坐标原来表示是参照对象坐标系里,现在需要将坐标表示为参照投影坐标系。
这个过程是一个数学计算的过程,这个过程计算比较复杂,如果需要深入学习的话,可以参照书籍<<3d数学基础 图形与游戏开发>>。
2.2.primitive assembly(图元装配)和triangle setup(三角形处理)
到目前为止我们得到了一堆顶点的数据,这一步就是根据这些顶点的原始连接关系还原出网格结构。网格由顶点和索引组成,这个阶段就是根据索引将顶点链接到一起,组成线、面单元,然后进行剪裁,如果一个三角形超出屏幕以外,例如两个顶点在屏幕内,一个顶点在屏幕外,这时我们在屏幕上看到的就是一个四边形,然后把这个四边形切成两个小的三角形。
现在我们得到了一堆在屏幕坐标上的三角形面片,这些面片是用于光栅化的。
3. 光栅化阶段。
经过上面的步骤之后,我们得到了每个点的屏幕坐标值,和我们需要绘制的图元,但此时还有两个问题:
(1)屏幕坐标是浮点数,但像素是用整数来表示的,如何确定屏幕坐标值所对应的像素?
(2)如何根据已确定位置的点,在屏幕上画出线段或者三角形?
对于问题1,绘制的位置只能接近两指定端点间的实际线段位置,例如,一条线段的位置是(8.13, 20.12),转换为像素位置就是(8,20)。
问题2,涉及到具体的画线和填充算法,有兴趣的话可以研究。
这个过程结束后,顶点和图元已经对应到像素,之后的流程就是如何处理像素,即给像素赋予颜色值。
给像素赋予颜色的阶段称为Pixel Operation,是在更新帧缓存之前,执行最后一系列针对每个片段的操作,其目的是计算出每个像素的颜色值。在这个阶段,被遮挡的面通过一个被称为深度测试的过程消除。
pixel operation包含下面这些流程:
(1)ZTest深度检测;
(2)Texture operation,纹理操作,根据像素的纹理坐标,查询对应的纹理值;
(3)Blending,通常称为alpha blending,根据目前已经画好的颜色,与正在计算的颜色的alpha值混合,形成新的颜色。