Unity Built-in
渲染流程图
CPU应用程序阶段
剔除
剔除(Culling)
将看不见的物体整个排除在渲染范围之外,不进行渲染
视锥体剔除
视锥体剔除(Frustum Culling)
视锥体:指摄像机根据FOV参数和远、近裁面产生的一个锥体
视锥体与物体进行碰撞检测来确定哪些物体应该被渲染,物体被碰撞盒进行包裹以便进行碰撞检测
层级剔除
层级剔除(Layer Culling Mask)
排除某几个特定层级上的物体
遮挡剔除
遮挡剔除(Occlusion Culling)
被遮挡的物体不被渲染
排序
排序(Sort),通过渲染队列(Render Queue)确定渲染顺序
不透明队列(<2500)
默认2000
按摄像机距离从前到后排序
半透明队列(>2500)
默认3000
按摄像机距离从后到前排序
打包数据
打包数据(Batch)
CPU要将写一些关于模型和渲染的数据打包发送给GPU
模型信息
就是要被渲染的模型文件的信息,如,fbx、obj等
顶点坐标(vertices)
法线(vertex normals)
UV(texture coords)
索引列表(Indices Array)
切线
顶点色
变换矩阵
世界变换矩阵
VP矩阵
根据摄像机位置和FOV等参数构建
灯光、材质参数
Shader
材质参数
灯光信息
绘制调用
GPU渲染阶段
GPU渲染管线流程
顶点着色器
顶点着色器(vertex shader)
最重要的任务
将顶点坐标从模型空间变换到裁剪空间
模拟“拍照”的过程
顶点着色器并不会产生2D图像,仅使得场景中的3D对象产生变形效果
可编程
经过矩阵将空间向量进行平移、旋转、缩放等操作
模型空间 -> 世界空间:
(放置物体)
通过模型矩阵(Model Matrix)
世界空间 -> 相机空间:
(摆好相机)
通过视图矩阵(View Matrix)
相机空间 -> 裁剪空间:
(按下快门)
通过投影矩阵(Projection Matrix)
图元装配及光栅化
也就是硬件操作阶段,不能人为操作
裁剪操作
对三角面进行裁剪操作,超出部分会被裁剪掉,重新生成一个新的三角面
标准化设备坐标(NDC)
将裁剪空间的坐标(
-w~w
)缩放到-1~1
为映射到屏幕坐标系做准备
背面剔除
通过模型信息的索引列表观察一个三角面的分布方向
逆时针为正面
顺时针为背面
屏幕坐标
只针对NDC的
XY
坐标进行转换
图元装配
之前都是对顶点进行操作,该阶段进行连线,生成封闭的三角形
生成的三角形被称为图元
光栅化
将3D顶点转化为2D像素
取屏幕坐标的
XY
坐标对图形进行“拍扁”操作通过插值生成算法生成片元
屏幕坐标(NDC)的
Z
坐标(深度值 depth)被用来判断生成的片元哪个应该最先显示在前面
片元
片元存储有对应插值计算后的数据
深度值Z
法线
顶点色
切线
位置
所有自定义的数据
片元着色器
最重要的任务
给片元上色
可编程
纹理技术
纹理采样
给定一个纹理坐标,通过算法找到对应纹素地址的颜色值
纹理过滤机制
当计算结果不为整数时该取哪个纹素地址
Mipmap
将大的图像映射到小的区域里
生成多个
level
图根据区域大小进行映射
纹理寻址模式
纹理坐标计算后的值超过了纹素地址的范围
纹理压缩格式
RGBA - 真彩色
ASTC - 移动端
ETC2 - 安卓
PVRTC - IOS
光照计算
光照组成
直接光照
光线到达物体表面后结果一次反射进入人眼
间接光照
光线到达物体表面后结果多次反射进入人眼
光照模型
Phong光照模型
对BRDF(双向反射分布函数)函数的简化
Phong = max(n \cdot l,0) + pow(max(r \cdot v,0),smoothness) + ambient
漫反射光(Diffuse)
max(n \cdot l,0)镜面反射光(Specular)
(r \cdot v)^{sh}环境光(Ambient)
基本框架
基本框架 = 直接光漫反射(Direct Diffuse) + 直接光镜面反射(Direct Specular) + 间接光漫反射(Indirect Diffuse) + 间接光镜面反射(Indirect Specular)
基本框架扩充 = 基本框架+More
输出合并
最重要的任务
处理遮挡关系
处理半透明混合
帧缓冲区(Frame Buffer)
颜色缓冲区(Color Buffer)
深度缓冲区(Depth Buffer)
模板缓冲区(Stencil Buffer)
Alpha测试(Alpha Test)
检测片元的Alpha值,如果低于某一个数值就丢弃
模板测试(Stencil Test)
与深度测试类似,设定某一规则,符合规则的片元才会被写入模板缓冲区(Stencil Buffer)
深度测试(Depth Test)
片元的深度值Z与深度缓冲区的数值进行比对,如果片元深度值Z小于深度缓冲区的值,则会写入,反之亦然
深度写入(ZWrite)
控制通过测试的片元是否写入深度缓冲区
不会影响颜色缓冲区的写入
深度测试(ZTest)
自定义深度测试的规则,决定哪些片元可以通过测试
提前深度测试(Early-Z)
可提高性能
需要硬件支持
混合(Blending)
相对于深度测试,是一个比较柔和的机制
对于半透明混合,要得到正确的渲染顺序,需要严格按照从后到前的规则
对于半透明混合,一般需要关闭深度写入(ZWrite)
对同一个位置上的多个片元进行混合计算,得到新的颜色值
Alpha Blend = SrcColor * A + DestColor * B其中,
A
和B
是两个自定义因子,比如如下着色器指令Blend SrcAlpha OneMinusSrcAlpha
Blend SrcAlpha One
就相当于
Alpha Blend = SrcColor * SrcAlpha + DestColor * (1.0-SrcAlpha)Alpha Blend = SrcColor * SrcAlpha + DestColor * 1.0