Unity 是一款跨平台的 3D 引擎,有着强大的渲染功能,并主要用于游戏开发。
谈到 Unity 的渲染功能,我们不得不提及到 着色器(Shader)——3D 游戏引擎中最重要的一个因素,它在游戏效果以及画面显示方面起到了决定性的作用。Shader 编程也属于计算机图形学中一个重要的部分。
接下来让我们从可编程渲染管线来了解 Shader 编程。
渲染管线模型
3D 游戏以及 3D 模型通过渲染管线来渲染到 2D 的屏幕上。渲染管线的流程是在 GPU 中进行的,它主要占有计算机的显存部分。渲染管线在这个过程中进行了顶点处理、面处理、光栅化、像素处理。
1)顶点处理
大多数接触过 3D 图形的人都知道3D 模型是通过众多点构成的面而展现出来的。
顶点处理,是通过一系列坐标系的变换,让各个顶点通过一定的规律在摄像机前位移,最终在屏幕上对应这些顶点的过程。
首先,物体的各个顶点从自身坐标系,通过世界变换矩阵处理转换到世界坐标系,再通过取景变换矩阵变换到观察者坐标系,最后通过投影变换,将顶点转移到屏幕坐标系。
有一点大家会经常忘记,在观察者坐标系转换到投影坐标系的过程中,GPU(图形处理单元)还对材质属性和光照属性进行了处理。
2)面处理
三点成一面。面处理有三个部分:面的组装、面的截取、面的剔除。
- 面的组装:模型中的三个点会组成一个三角形的面(非任意点,因为每个点都有自己的编号)。这些面,面面相接,组成了我们能看到的模型。
- 面的截取:由于摄像机和人眼一样,可视的区域是一个锥形,模型在摄像机可视范围内可能并不是全覆盖,也就是在摄像机外,这些在摄像机之内的部分就会被截取。
- 面的剔除:为了模拟肉眼,摄像机前的物体会出现近大远小的现象,那么物体和物体之间会有遮挡,被遮挡的面会被剔除不处理;每个面都有法向量,所以只有在面的法向量和摄像机散射向量夹角大于90度的才会被摄像机捕捉到。
3)光栅化
光栅化,又称之合并阶段。它的主要功能是将面转换成一帧中的像素集合。
这一阶段是不可以编程的,它负责执行多个片段测试,包括:深度测试、alpha 测试和模板测试,程序员可以通过高度配置来实现想要的效果。如果通过了所有的测试,这部分颜色就会与帧缓冲存储的颜色通过 alpha 混合函数进行合并。
4)像素处理
这个阶段将像素区域着色,然后赋予贴图。
Shader 详解
介绍完 GPU 渲染管线之后,我们再来简单了解一下可编程着色器 Shader —— 图形渲染里最有趣的部分。Shader 能让渲染的图形展示出水面效果、火焰的热流效果、角色的虚化效果等视觉效果。
着色器可分为顶点着色器(VertexShader)、几何着色器(Geometry Shader)和像素着色器(Pixel Shader)。它们从输入的数据中取得一个元素,通过程序计算,变换为输出数据的一个或多个元素。
- 顶点着色器输入源为顶点,顶点包含其在自身坐标系或世界坐标系的位置和矢量信息,而输出源为已通过变换和照明处理的顶点,包含其投影坐标系的信息。
- 几何着色器的输入源为一个有 n 个顶点的几何图元以及最多 n 个作为控制点的额外顶点,输出源则变成 0 或多个图元。根据效果需要,这些图元的可能和输入的时候不同。
- 像素着色器输入为顶点间的片段,这些片段所包含的信息来自于对三角形顶点信息的插值,输出成将要写到帧缓冲里的颜色。
结语
在游戏中,绚丽的场景和角色是怎么来的呢? 很简单,纹理数据以纹理坐标(UV 坐标)寻址的,而并非内存地址。通过着色器我们可以直接读取纹理贴图。
模型的顶点和纹理内的 UV 坐标一一对应,这样,纹理就以一定的规则贴在了模型上。