Shader是为渲染管线中的特定处理阶段提供算法的一段代码。shader是伴随着可编程渲染管线出现的,它的出现使得游戏开发者可以对渲染过程加以控制,拥有更大的创作空间,因此Shader的出现可以看作是实时渲染技术的一次革命。
为了方便游戏开发者使用,Unity提供了大量的内建Shader,包括从最简单的顶点光照效果到高光,法线,反射等游戏中最常用的材质效果。
内建的shader根据应用对象可以分为以下几大类:
v 普通Normal Shader Family:用于不透明的对象。
v 透明Transparent Shader Family:用于透明的对象。
v 透明镂空效果Transparent Cutout Shader Family:用于包含完全透明部分的半透明对象。
v 自发光Self-illuminated Shader Family:用于有发光效果的对象。
v 反射Reflective Shader Family:用于能反射环境立方体贴图的不透明对象。
如何在效果各异的内建Shader中选择最合适的Shader是开发者需要考虑的问题,毕竟视觉效果越好的Shader,一般渲染开销也越大,同时对硬件的要求也越高。游戏开发者需要在游戏画面和游戏性能之间做出平衡。
以下是不同的光照效果从低到高的计算开销排序;
Unlit:仅适用纹理颜色,不受光照影响。
VertexLit:顶点光照。
Diffuse:漫反射。
Specular:在漫反射基础上增加高光计算。
Normal mapped:法线贴图,增加了一张发现贴图和几个着色器指令。
Normal mapped Specular:带高光法线贴图。
Parallax Normal Mapped:视差法线贴图,增加了视差贴图的计算开销。
Parallax Normal Mapped Specular:带高光视差法线贴图。
三种自定义的Shader
Unity中,开发者可以编写3种类型的Shader:
ü 表面着色器Surface Shaders:通常情况下用户都会使用这种Shader,它可以与灯光,阴影,投影器进行交互。表面着色器的抽象层次比较高,它可以容易地以简洁方式实现复杂的着色器效果。表面着色器可同时正常工作在前向渲染及延迟渲染模式下。表面着色器以Cg/HLSL语言进行编写。
ü 顶点和片段着色器Vertex and fragment Shaders:如果需要进行一些表面着色器无法处理的酷炫效果,或者编写的Shader不需要与灯光进行交互,或者想要的只是全屏图像效果,那么可以使用顶点和片段着色器。这种Shader可以非常灵活地实现想要的效果,但是需要编写更多的代码,并且很难与Unity的渲染管线完美集成。顶点和片段着色器同样是用Cg/HLSL语言编写。
ü 固定功能管线着色器Fixed Function Shaders:如果游戏运行在不支持可编程管线的老旧硬件上,那么就需要编写这种Shader。固定功能管线着色器可以作为片段或表面着色器的备用选择,这在当硬件无法运行那些炫酷Shader的时候哦,还可以通过固定功能管线着色器来绘制出一些基本的内容。固定功能管线着色器完全以ShaderLab语言编写,类似于微软的Effects或者是Nvidia的CgFX。
无论编写哪种Shader代码,都需要嵌在ShaderLab代码中,Unity需要通过ShaderLab代码来组织Shader结构。
shader Language目前主要有三种语言:基于OpenGL的GLSL,基于Direct3D的HLSL,还有NVIDIA公司的Cg语言。
HLSL全称是"High Level Shading Language"
cg全称是"C for Graphic"
GLSL全称是"OpenGL Shading Language"
Shader language原理
使用shader language编写的程序被称之为shader program着色程序。着色程序分为两类:vertex shader program顶点着色程序和fragment shader program片段着色程序。
GPU上有两个组件:Programmable vertex processor可编程点处理器,又称为顶点着色器;Programmable fragment processor可编程片段处理器,又称为片段着色器。
顶点和片段处理器都拥有非常强大的并行计算能力,并且非常擅长于矩阵(不高于4阶)计算,片段处理器还可以高速查询纹理信息(目前顶点处理器还不行,这是顶点处理器的一个发展方向)。
顶点着色器控制顶点坐标转换过程,片段着色器控制像素颜色计算过程。前者的输出是后者的输入。
现阶段可编程图形硬件的输入/输出。输入寄存器存放的是输入的图元信息,输出寄存器存放的是处理后的图元信息,纹理Buffer存放的是纹理数据,目前大多数的可编程图形硬件只支持片段处理器处理纹理;从外部宿主程序输入的常量放在常量寄存器中;临时寄存器存放着色程序在执行过程中产生的临时数据。
shader language被定位是高级语言,但是却没有独立于硬件,而是完全依赖于GPU架构,所以GPU编程技术的发展本质上还是图形硬件的发展。
eg:
1 Shader "MyShader"{//Shader的名称 2 3 Properties{ 4 5 _MyTexture("My Texture",2D) = "White"{} 6 7 //在这里定义Shader中使用的属性,例如颜色,向量,纹理 8 9 } 10 11 SubShader{ 12 13 //在这里编写Shader的实现代码 14 15 //包括表面着色器,顶点和片段着色器的Cg/HLSL代码 16 17 //或者是固定功能管线着色器的ShaderLab代码 18 19 } 20 21 SubShader{ 22 23 //在这里实现简化版的备选Shader,用于在不支持高级Shader特性的老硬件上运行 24 25 } 26 27 }
创建Shader
在Unity中开始编写Shader代码前,需要在项目工程中创建一个Shader文件,着点和编写脚本一样。
ShaderLab基础语法
在Unity中提供了一种名为ShaderLab的着色器语言来编写Shader,语法类似Cg语言,该语言能够描述材质所需要的各种特性,并且可以很方便地通过Inspector视图来查看和修改。
eg:
1 Shader "Simple colored lighting"{ 2 3 Properties{//定义一个名为Main Color的颜色属性 4 5 _Color("Main Color",Color) = (1,0.5,0.5,1) 6 7 } 8 9 SubShader{//Shader的实现代码 10 11 Pass{ 12 13 Material{ 14 15 Diffuse[_Color] 16 17 } 18 19 Lighting On 20 21 } 22 23 } 24 25 }
示例运行效果如下:
注意:Unity中的游戏体不能为默认材质添加Shader。要想使用自定义的Shader,首先需要自定义一个材质球,然后才可以使用自定义的Shader。