我们先从渲染管线说起
一个3d模型从max中开始建模,经过一系列的变化被渲染成游戏中的一个像素、一帧画面的流程,可以称为渲染管线
1,准备数据:首先需要拿到模型的数据,包括顶点,uv,法线等
2,顶点变化:将模型空间(以模型自身轴为坐标中心)下的物体通过空间转换从而将一个三维坐标的点投影成一个电脑屏幕上二维坐标点,在这个过程中,顶点数据要经历从模型空间------世界空间-----相机空间-----裁剪空间(通过MVP三个矩阵变换)
3,光栅化:把顶点连成三角形,并把三角形覆盖的像素进行插值,这时我们就有了模型在屏幕投影后的“像素”区域(因为这时还没有渲染完成,所以也称为片元)
4,着色:对片元进行着色操作,纹理采样(uv),光照模型(法线),最终呈现出来的颜色效果都在这一步操作:例如我们想实现一个卡通光影效果,那我们需要对Lambert光照进行简化step,将漫反射渐变光照限制为黑白分明的二分光照效果
5,输出合并:这一步决定一帧画面内模型的渲染顺序,通过进行深度测试-----模板测试-----透明度混合,输出到帧缓存
在这整个流程中,我们不需要对所有内容进行编程,重点在于顶点变化以及着色,也称为顶点着色器和像素着色器,将这两个着色器整合起来就是shader,shader是整个渲染管线中高度定制编程的部分,下方这张图便于理解:
在unity shader中我们可以控制更多:例如是否通过深度测试,透明度混合等
接下来梳理一些知识点
drawcall:每当cpu向gpu发送一次渲染指令就称为drawcall,(如果我们每一个模型都要发送一次指令会严重的浪费性能,可以将一批模型一次性发送(批处理)
顶点动画:我们可以通过在顶点变换的过程进行计算,改变模型顶点的偏移,实现丰富的效果
深度测试:深度图是一张以相机为原点到模型各个位置的黑白图,通过采样深度纹理我们可以知道像素之间的深度关系,那么通过比较就可以得出哪个像素渲染再前,而哪个像素被舍弃,深度缓存(z-buffer)是用来存放临时的深度数据进行比较。有个常用的做法是边缘检测,通过比较透明物体和不透明物体的深度来判断边缘。
光照模型:我们用到的模型都是经验模型,不是符合物理界自然规律的,图形学中只要看起来是对的就是对的,BRDF是描述光的入射和反射的函数,任何一个光照模型都可以称为BRDF,一个基础的光照效果应该包含:漫反射+高光+环境光