渲染流水线RenderPipeline
渲染流水线
可编程Shader
在整个渲染流水线中,主要进行编程的部分为
几何阶段的顶点着色器(VertexShader),【约定缩写:Vert】
对模型的顶点进行操作
光栅化阶段的片元着色器(Fragment Shader)【约定缩写:Frag】
进行纹理采样
DX中也称为(Pixel Shader)像素着色器
而其他的Shader功能通常不能直接修改,一般做成开关的形式,根据需要开启或关闭
渲染完成后,各个通道的渲染结果存入帧缓存,此时还可以进行后期处理(PP)
着色器分工
几何阶段(Vertex)
顶点着色器:VertexShader 基本功能: 将顶点从模型空间转换为齐次空间(齐次剪裁坐标), 再由硬件转换为归一化设备坐标系 (Normalized Device Coordinates,NDC 左手系) 自定义编程功能: 做顶点动画、置换、移动旋转缩放等操作
曲面细分着色器:Tesselation Shader 基本功能:曲面细分
几何着色器(置换):Geometry Shader(Displacement) 基本功能:曲面细分后的顶点着色器
剪裁:Clipping 基本功能: 将看不到的物体和物体看不到的部分做剪裁 剪裁类型: 2、远近平面剪裁:离摄像机过远或过近的物体做剪裁(低消耗) 3、视野剪裁:将视野范围外的物体做剪裁(相对中消耗) 4、遮挡剪裁:被遮挡的物体进行剪裁(相对高消耗)
屏幕映射:ScreenMapping 基本功能: 将每个图元转换到屏幕坐标系(ScreenCoordinates) (注:屏幕坐标系只有xy,如果带上z轴则称为窗口坐标系(WindowsCoordinates)) OpenGl DirectX
光栅化阶段(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
最后的结果都会保存到一个叫帧缓冲的地方 (即渲染完成后的各个通道)
常见问题
剪裁问题
由于在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默认]
驱动:视平台而定 坐标系:左手坐标系 屏幕坐标系:
//Cg/Hlsh【DirectX】
Shader "Unity/Hibari"
{
SubShader
{
pass
{
CGPROGRAM //标签开始
ENDCG //标签结束
}
}
}
GLSL:
驱动:OpenGL 坐标系:右手坐标系 屏幕坐标系:
//GLSL【OpenGL】
Shader "Unity/Hibari"
{
SubShader
{
pass
{
GLSLPROGRAM //OpenGL标签开始
ENDGLSL //OpenGL标签结束
}
}
}
HLSL:
驱动:DirectX 坐标系:左手坐标系 屏幕坐标系:
//HlsL【DirectX】
Shader "Unity/Hibari"
{
SubShader
{
pass
{
HLSLPROGRAM //DX标签开始
ENDHLSL //DX标签结束
}
}
}