“在读CandyCat的Unity Shader入门精要之后,发现忘得比看得快,所以索性重看一遍并记了一段笔记”
渲染流程分为三个阶段
- 应用阶段(Application Stage); CPU实现
- 把数据加载到显存中; 硬盘(HDD) -> RAM -> VRAM
- 设置渲染状态; 使用哪种类型的着色器,光源属性,材质等;
- 调用Draw Call;
- 几何阶段(Geometry Stage); GPU实现
- 光栅化阶段(Rasterizer Stage); GPU实现
GPU渲染流水线
1 . 几何阶段
顶点数据 (显存)-> 顶点着色器 -> 曲面细分着色器 -> 几何着色器 -> 裁剪 -> 屏幕映射
顶点着色器(Vertex Shader)
完全可编程, 实现顶点的空间变化,顶点着色的功能;
- 实现坐标变换,把顶点坐标从模型空间转换到齐次裁剪空间,之后使用透视除法,获得归一化的设备坐标(Normalized Device Coordinates);
- 逐顶点光照,
曲面细分着色器(Tessellation Shader)
可选着色器,用于细分图元;
几何着色器(Geometry Shader)
可选着色器,可以被用于执行逐图元的着色操作,或者被用于产生更多的图元;
裁剪(Clipping)
可配置,剔除不在摄像机视野内的顶点,剔除某些三角图元的面片;
屏幕映射(Screen Mapping)
把每个图元的x,y坐标转换到屏幕坐标系; 注意: OpenGL与DirectX的屏幕坐标系不同;
2. 光栅化阶段
屏幕映射 -> 三角形设置 -> 三角形遍历 -> 片元着色器 -> 逐片元操作 -> 屏幕图像
三角形设置(Triangle Setup)
计算光栅化一个三角形网络所需的信息,通过顶点计算三角形边界的表达方式;
三角形遍历(Triangle Travelsal)
检查每个像素是否被一个三角网络覆盖,若被覆盖则生成一个片元(Fragment),最终输出片元序列(包含了最终颜色,屏幕坐标信息,深度信息,法线,纹理坐标等);
片元着色器(Fragment Shader)
可编程着色器,在DirectX中也称像素着色器(Pixel Shader),实质上是通过对顶点插值,通过颜色、纹理的计算,输出最终的颜色信息。
逐片元操作(Per-Fragment Operations)
片元 -> 模板测试 ->深度测试 -> 混合 -> 颜色缓冲区(帧缓冲区)
OpenGL的说法,在DirectX中为输出合并阶段(Output-Merger)
- 决定每个片元的可见性,涉及到了深度测试,模板测试等;
- 若一个片元通过测试,就需要将该片元的颜色与存储在颜色缓冲区中的颜色进行混合。
颜色缓冲区(帧缓冲区)
就是帧缓冲区(图形设备的内存),需要渲染的场景的每一个像素都最终写入该缓冲区,然后由他渲染到屏幕上显示。
模板测试(Stencil Test)
GPU会首先模板缓冲区(Stencil Buffer)中该片元位置的模板值,将该值与读取到的参考值进行比较,进而修改模板缓冲区,…. 模板测试中可进行渲染阴影,轮廓渲染等。
深度测试
主要影响透明效果
DrawCall相关
- draw call 对帧率的影响在于cpu提交命令的速度;
- 减少draw call需要避免使用大量很小的网格,避免使用过多的材质。
着色器介绍
Shader
{
subShader
{
pass
{
}
}
}
1. 表面着色器(Surface Shader)
Unity特有的对于顶点/片元着色器Vertex/Fragment Shader的抽象封装,自动完成了光照细节的处理,但相应的渲染代价更大,性能更低。 写在SubShader内,不需要考虑pass的渲染问题。
2.顶点/片元着色器(Vertex/Fragment Shader)
写在Pass内,可以通过选择pass控制渲染的实现细节;