精品学习网->精美文摘

上一篇    全部文章


什么是Shader

Shader是着色器,是一段能够针对3D对象进行操作、并被GPU所执行的程序。通过这些程序,程序员就能够获得绝大部分想要的3D图形效果。在一个3D场景中,一般包含多个Shader。这些Shader中有的负责对3D对象表面进行处理,有的负责对3D对象的纹理进行处理。早在微软发布DirectX  8时,Shader  Model的概念就出现在其中了,并根据操作对象的不同被分为对顶点进行各种操作的Vertex  Shader和对像素进行各种操作的Pixel  Shader。
2D图形,就是无论你如何移动视角,地面上的建筑物、花草树木样子都不会变,而3D图形则不  同,随着视角的变换,你看到的物体也在变化,从正面变成侧面,越远的物体越小,越近的越大,与现实生活中人眼看到的情景非常相似。
shader就是专门用来渲染3D图形的一种技  术,通过shader,程序设计人员可以自己编写显卡渲染画面的算法,使画面更漂亮、更逼真。  几年前并没有shader这个东西,所以那时候的显卡,就不  支持shader,而只支持固定管线渲染,游戏画面也没有现在的酷。
shader又分两种  ,一种是顶点shader(3D图形都是由一个一个三角形组  成的,顶点shader就是计算顶点位置,并为后期像素渲染做准备的),另一种是像素shader,像素shader顾名思义,就是以像素为单位,计算光  照、颜色的一系列算法。
几个不同的图形API有各自的shader语言:
在DirectX中,顶点shader叫做  vertex  shader  ,像素shader叫做  pixel  shader;
在OpenGL中,顶点shader也叫做  vertex  shader  ,但像素shader叫做  fragment  shader。
此外显卡芯片厂商nVidia还推出CG显卡编程语言,也支持  shader。
shader  有很多不同的版本:
所以,即使你的显卡支持shader,但可能版本不够高,所以无法支持比较新的游戏使用的  shader。
一般来说,大部分游  戏都支持不同版本的shader,为的是让尽可能多的机器都能运行,为此需要做很多额外的工作。
除了显卡不够新之外,不同显卡厂商对shader的支持也不尽相同,所以同一个游戏,一样的  设置,在n卡和ATI的卡上,表现可能大不一样。
另外,安装官方最新的驱动程序也是必要的。如果你安装了错误的驱动程序,甚至是随便从网上下载一个显卡驱动,那么即使你的显卡支持  shader,也可能跑不了需要shader支持的程序,包括但不限于网络游戏!  

Shader基础知识

渲染流水线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/HLSH


⚠️注意:在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

          {
               GLSLPRORAM  //OpenGL标签开始
                  ENDGLSL  //OpenGL标签结束

          }

    }

}



HLSH:
驱动:DirectX

坐标系:左手坐标系

屏幕坐标系:


//Hlsh【DirectX】 

Shader  "Unity/Hibari"  {      

        SubShader      

    {            
        pass            

        {      

        HLSHPROGRAM  //DX标签开始            

        ENDHLSH  //DX标签结束            

        }      

    } 

}  

FALSE

     返回顶部
什么是Shader