什么是ShaderShader是着色器,是一段能够针对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))OpenGlDirectX光栅化阶段(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、CGHLSL 【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