一、渲染的概念
渲染是指以软件由模型生成图像的过程
渲染管线(广义)分为CPU应用程序端渲染逻辑和GPU渲染管线(通常我们说的渲染管线)
预渲染与实时渲染
- 预渲染:预渲染的计算强度很大,需要大量的服务器运算完成,渲染需要很长时间,通常用于电影制作等
- 实时渲染:实时渲染需要在一秒钟内完成至少24帧图像,如果想流畅就需要至少60帧图像。所以实时渲染需要一些优化手段急速渲染过程。实时渲染通常通过图形处理器(GPU)完成这个过程。
二、CPU
(当相机调用render()时开始工作)
第一步 剔除(Culling)
1. 视锥体剔除(Frustum Culling)
摄像机根据FOV(Field of View 视场角) 和远近裁面形成一个锥台,让模型和这个锥台进行碰撞检测,如果没有碰撞说明不在视野内,直接剔除,不需要渲染。
Tips 1: 有的模型表面的网格非常复杂(比如球体)
简化处理:生成一个AABB包围盒与锥台进行碰撞检测
2.遮挡剔除(Occlusion Culling)
3.层级剔除(Layer Culling Mask)
第二步 确定渲染顺序—排序(Sort)
Render Queue 的数值越小,表示物体越先被渲染
如果Render Queue相等,会分成两个渲染队列,不透明渲染队列和透明渲染队列
1. 不透明渲染队列(Render Queue < 2500)
按摄像机距离从前到后排序
Tips 1: Why?
这其实是一种优化,离得近的如果覆盖了遮挡了距离远的,那后者就可以不用渲染了
2. 半透明渲染队列(Render Queue > 2500)
按摄像机距离从后向前排序
Tips 1: Why?
这是为了保证渲染结果的正确性
第三步 打包数据 发送给GPU
包含大量数据和参数
第四步 调用Shader:SetPassCall、DrawCall 发送给GPU
三、GPU
收到指令SetPassCall、DrawCall 和 CPU 传送的打包数据
第一步 通过一系列工作将模型渲染成2D图像
1. 顶点处理
顶点Shader:将模型空间顶点转换成裁剪空间,然后又硬件来将这些顶点映射到屏幕上(3D变2D)
最重要的任务:将顶点坐标从模型空间变换到裁剪空间
经过顶点Shader处理后,相机金字塔状的视锥体被转换变形成一个比例为221的立方体(CVV)
顶点Shader并不会产生2D图像,仅使得场景中的3D对象产生变形效果
拍照过程:放置物体 -> 摆好相机 -> 摁下快门
通过矩阵完成以下空间变化
① 模型空间 -> 世界空间
② 世界空间 -> 相机空间
③ 相机空间 -> 裁剪空间
2. 图元装配及光栅化(硬件操作阶段)
图元装配:将点连接起来
光栅化:在图元内部插入片元(类似还没有显示的像素)
光栅化之后3D彻底变成2D
具体操作
① 裁剪操作
对裁剪空间进行裁剪。与视锥体相交的部分会被裁剪不渲染部分并生成新的三角面,完全在外面的就直接裁剪掉
② 透视除法
将裁剪后的物体坐标缩放到标准化设备坐标(NDC)
③ 背面剔除
根据索引列表来判断是否为背面。
④ 视口转换
将标准化设备坐标转化为屏幕坐标(只转化x,y坐标)
⑤ 图元装配
前面的所有操作都是顶点操作,图元装配环节将点进行连线
⑥ 光栅化
生成在图形内部生成片元
z坐标值会通过插值储存为片元的深度值等各种数据来帮我们处理前后遮挡关系等
插值:我们知道两边界点的值,算出中间的值
3. 片元处理
每一个片元都会调用自己的片元Shader进行计算
片元Shader:对片元进行着色 ------ 光照着色,纹理着色
纹理图像:一个二维数组,利用文素地址储存一组颜色值
- 纹理技术
纹理采样:给定一个数值,找对对应的像素地址颜色值
纹理过滤机制:解决小图->大屏幕问题- 常规处理:对中间的值直接四舍五入为最接近的值进行采样:会失真(对应Unity中的Point)
- 优化:对周围四个值进行插值运算,最终结果会柔和很多(双线性插值,对应Unity中的Bilinear)
Mipmap纹理链:解决大图->映射到小块区域问题 ------ 生成一系列不同大小的图像,选用合适的来映射(对应Unity中的Generate Mip Maps)
纹理寻址模式:确定纹理坐标查出文素地址范围时的处理方法(对应Unity中的Wrap Mode)
纹理压缩格式:将我们传入的图片转换为各种平台能够使用的压缩格式,不同压缩格式对最终结果有很大影响
- 光照计算
- 光照形成
- 直接光照:考虑的是光线到达
- 间接光照
- 光照模型
Phong光照模型:
- 一个物体表面的颜色由三个因素决定:
- 漫反射—反射出去的光线在各个方向上都是均等的
- 镜面反射 光滑度:决定衰减范围
- 环境光:间接光照
基本框架—这些光照效果相加就是最终呈现的效果
- 直接光漫反射
- 直接光镜面反射
- 间接光漫反射
- 间接光镜面反射
- More
- 光照形成
4. 输出合并
处理遮挡关系和颜色混合等等,并完成输出
- 最重要的任务:处理遮挡关系、处理半透明混合
- 通俗地讲:片元通过重重考验到达像素点位置的过程
流程:
① Alpha测试
检测片元的Alpha值,如果太小就可以直接丢弃
② 模板测试
③ 深度测试
检测片元的深度值:深度越小越应该渲染(小于深度缓冲区深度值才能写入,写入后更新深度缓冲区的深度值)
- ZWrite 深度写入:关闭ZWrite后,通过深度测试之后的片元仍然写入,但深度缓冲区不更新
- ZTest 深度测试:默认是小于深度缓冲区的值才能写入,但可以强制修改
- Early-Z 提前深度测试:发生在顶点Shader之后,片元Shader之前。是一种优化
④ 混合
可以柔和地将片元都输出到像素点,进行混合
- 从后到前(半透明混合之前提到过)
- 关闭ZWrite
Tips 1: Shader是什么?
Shader是运行在GPU上的一段可编程的程序
一个完整的Shader由顶点Shader和片元Shader组合而成
第二步 输出到帧缓冲区
帧缓冲区相当于是临时的画布,当全部渲染完毕时,帧缓冲区的内容可以显示到屏幕中
缓冲区分为颜色缓冲区、深度缓冲区和模板缓冲区
第三步 后处理操作
显示到屏幕前,CPU可以拿到帧缓冲区的内容,进行二次修改(调色、Bloom等)然后再传送给GPU渲染管线,最终才显示在屏幕上
四、多个相机
每个相机会跑完整的渲染流程
相机通过Depth决定渲染顺序,后渲染的可以通过Clear Flags确定是否清除前一个相机的渲染。
参考资料:视频教程 - https://www.bilibili.com/video/BV1Q54y1G7v3
版权声明:本文为CSDN博主「CTYring」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_51029409/article/details/123640820