渲染流水线RenderPipeline

渲染流水线

Shader 基础知识 - 图1

可编程Shader

在整个渲染流水线中,主要进行编程的部分为
几何阶段的顶点着色器(VertexShader),【约定缩写:Vert】
对模型的顶点进行操作
光栅化阶段的片元着色器(Fragment Shader)【约定缩写:Frag】
进行纹理采样
DX中也称为(Pixel Shader)像素着色器
而其他的Shader功能通常不能直接修改,一般做成开关的形式,根据需要开启或关闭
渲染完成后,各个通道的渲染结果存入帧缓存,此时还可以进行后期处理(PP)

着色器分工

几何阶段(Vertex)

顶点着色器:VertexShader 基本功能: 将顶点从模型空间转换为齐次空间(齐次剪裁坐标), 再由硬件转换为归一化设备坐标系 image.png (Normalized Device Coordinates,NDC 左手系) 自定义编程功能: 做顶点动画、置换、移动旋转缩放等操作

曲面细分着色器:Tesselation Shader 基本功能:曲面细分

几何着色器(置换):Geometry Shader(Displacement) 基本功能:曲面细分后的顶点着色器

剪裁:Clipping 基本功能: 将看不到的物体和物体看不到的部分做剪裁 剪裁类型: 2、远近平面剪裁:离摄像机过远或过近的物体做剪裁(低消耗) 3、视野剪裁:将视野范围外的物体做剪裁(相对中消耗) 4、遮挡剪裁:被遮挡的物体进行剪裁(相对高消耗)

屏幕映射:ScreenMapping 基本功能: 将每个图元转换到屏幕坐标系(ScreenCoordinates) (注:屏幕坐标系只有xy,如果带上z轴则称为窗口坐标系(WindowsCoordinates)) OpenGlimage.png DirectXimage.png

光栅化阶段(Fragment)

三角形设置、遍历(Triangle Setup、Traversal) 基本功能: 通过插值计算,算出每个面(片元)覆盖的像素,和每个像素的深度 输出包含各种信息的片元序列(每个片元包含 顶点信息、法线信息、纹理坐标、屏幕坐标、深度信息等等)

片元着色器(像素着色器):Fragment Shader(Pixel Shader) 基本功能: 对每一个单独的片元,填充纹理采样颜色等结果,渲染灯光,法线,深度等信息 (但注意:此时每个片元都是独立的,包括每个片元各种信息都是独立的,结果没有合并) 自定义编程功能: 最重要的着色器,我们会在这里写光照函数等计算纹理效果的算法

逐片元操作(合并输出):Per-Fragment Operations(OutputMerger) 基本功能: 任务1:决定片元的可见性(通过模板测试、深度测试来决定) 任务2:混合片元(将相同类型的片元通过混合Blend的方式合成成各个通到) 任务3:将结果合并 并输出到颜色缓冲区(各种通道保存到Buffer)

模板测试:Stencil Test(模板缓冲 Stencil Buffer) 读取片元中的掩码值并和参考值做比较,如果小于则舍弃 (掩码值和窗口值可以由开发人员用函数指定) 作用:限制渲染区域、渲染阴影、轮廓渲染等

深度测试:Depth Test(深度缓冲 Depth Buffer) 测试物体离摄像机的距离,过远过近剔除, 作用:与半透明物体的渲染有关

混合:Blend 将片元合并到一个单独的通道,并输出到颜色缓冲Color buffer

帧缓存:Frame buffer

最后的结果都会保存到一个叫帧缓冲的地方 (即渲染完成后的各个通道) image.png


常见问题

剪裁问题

由于在CPU阶段会对视野范围外的物体做剔除,
此时如果使用顶点着色器(VertexShader)将物体平移到视野范围内,
由于已经被CPU剔除了所以也不会被渲染出来

剪裁顺序 CPU剔除 1、摄像机剔除:将视野范围外的物体做剔除(直接把整个物体删除) GPU剪裁 2、远近平面剪裁:离摄像机过远或过近的物体做剪裁(低消耗) 3、视野(视锥)剪裁:将视野范围外的物体做剪裁(相对中消耗) 4、遮挡剪裁:被遮挡的物体进行剪裁(相对高消耗)

解决方案:将摄像机剔除的范围扩大一点(太远的物体也是无效的)

置换问题

如果使用顶点着色器进行置换,即使进行了曲面细分,只能运行出没细分之前的效果。

在Shader编程过程中,需要遵守渲染流水线的运行顺序, 曲面细分着色器是在顶点着色器之后进行的,

解决办法:置换必须在曲面细分之后进行

前向渲染与延迟渲染 ForwardRending & Deferred Rending

(Unity中的渲染方式有好几种设置模式,之后再具体探究)
前向渲染:
特点:直接将场景内的物体全部都渲染出来
优点:能够渲染半透明、玻璃等材质
缺点:对性能消耗异常的搭
延迟渲染:
特点:先将物体剔除后,将视野中仅看得到的物体渲染出来
优点:消耗小
缺点:半透明物体,透明物体无法正常渲染
补救办法:渲染排序


Shader语言:HLSL、GLSL、CG

HLSL 【High-Level Shading Language】

依赖系统的语言
特点:由编译器翻译成对应GPU支持的机器语言
驱动:DirectX
平台:Windows、Xbox360等
缺点:被微软控制的着色器,编译器几乎只支持微软平台
优点:编译结果都一样

GLSL 【OpenGL Shading Language】

依赖硬件的语言
特点:在GPU内进行编译,翻译成自己所支持的机器语言
驱动:OpenGL
平台:NVIDA、AMD-ATI
缺点:由于不同厂商对GLSL编译方式不同导致结果不同,且需要显卡支持
优点:显卡支持就行,跨平台性好

CG 【C for Graphic】

跨平台语言
特点:由硬件商Nvida开发的语言
优点:跨平台
缺点:无法保持最新的OpenGL特性

CG/HLSL

由于这两种语言非常相似,几乎可以进行无缝迁移,
为了保证兼容性 Unity通常使用CG/HLSL进行编程


在Unity中选择Shader语言

Unity通过标记来确定用户使用的是那种Shader语言

标记是写在SubShader中,用来确定使用的Shader语言,一般Unity默认Cg/HLSL

⚠️注意:在vertex shader处理结束后,都是按照左手系计算的(ndc空间)
⚠️注意:DX与Opgl的Y轴相反,法线贴图的G通道也相反
⚠️注意:Unity中可以选择不同的Shader语言,但需要在不同的标签内

Cg:[Unity默认]

驱动:视平台而定 坐标系:左手坐标系 屏幕坐标系:image.png

  1. //Cg/HlshDirectX
  2. Shader "Unity/Hibari"
  3. {
  4. SubShader
  5. {
  6. pass
  7. {
  8. CGPROGRAM //标签开始
  9. ENDCG //标签结束
  10. }
  11. }
  12. }

GLSL:

驱动:OpenGL 坐标系:右手坐标系 屏幕坐标系:image.png

  1. //GLSLOpenGL
  2. Shader "Unity/Hibari"
  3. {
  4. SubShader
  5. {
  6. pass
  7. {
  8. GLSLPROGRAM //OpenGL标签开始
  9. ENDGLSL //OpenGL标签结束
  10. }
  11. }
  12. }

HLSL:

驱动:DirectX 坐标系:左手坐标系 屏幕坐标系:image.png

  1. //HlsLDirectX
  2. Shader "Unity/Hibari"
  3. {
  4. SubShader
  5. {
  6. pass
  7. {
  8. HLSLPROGRAM //DX标签开始
  9. ENDHLSL //DX标签结束
  10. }
  11. }
  12. }