Unity Shader基础

Unity Shader基础

ShaderLab

在unity中,所有的unity shader都是使用shaderlab来编写的。Shaderlab是unity提供的编写unity shader的一种说明性的语言。

Unity shader的结构

Shader名字

每一个unity shader的第一行都是通过shader语义来指定他的名字。例如:Shader"Custom/NewSurfaceShader"

材质和unity shader的桥梁:Properties

Properties语句块中包含了一系列的属性,这些属性将出现在材质面板中。

Properties

{

_Color ("Color", Color) = (1,1,1,1)

_MainTex ("Albedo (RGB)", 2D) ="white"{}

_Glossiness ("Smoothness", Range(0,1)) = 0.5

_Metallic ("Metallic", Range(0,1)) = 0.0

}

开发者们声明这些属性是为了在材质面板中能够更方便的调节各种材质的属性。如果我们需要在shader中访问他们,就必须使用属性的名字。中unity中这些属性通常由一个下划线开始。我们需要为他指定一个类型,并且要给每个属性一个默认值,材质面板上就会显示这些默认值。

属性类型有:Int,Float,Range(min,max),Color,Vector,2D,Cube,3D等。

Subshader

每一个unity shader文件可以包含多个subshader语义块,但至少有一个。

SubShader

{

[Tags]

[RenderSetup]

Pass

{

}

 }

Subshader中定义了一系列的Pass以及可选的状态[RenderSetup]和标签[Tags]设置。每个Pass定义了一次完整的渲染流程,如果Pass数目过多,往往会造成渲染性能的下降。

状态

ShaderLab提供了一系列渲染状态的设定,这些指令可以设置显卡的各种状态,例如是否开启混合/深度测试等。

状态名称 设置指令 解释
Cull Cull Back Front
ZTest ZTest Less Greater LEqual
ZWrite ZWrite On Off
Blend Blend SrcFactor DstFactor 开启并设置混合模式

标签

Tags是一个键值对,他的键和值都是字符串类型的。告诉unity我们希望怎样以及何时渲染这个对象。

标签类型 说明 例子
Queue 控制渲染顺序,指定该物体属于哪一个渲染队列,通过这种方式可以保证所有的透明物体可以在所有不透明物体的后边被渲染,我们可以使用渲染队列来控制物体的渲染顺序。 Tags{"Queue" = "Transparent"}
RenderType 对着色器分类。例如:这是一个不透明着色器或者设计一个透明的着色器等。这可以被用于着色器替换功能。 Tags{"RenderType" = "Opaque"}
DisableBatching 一些SubShader在使用Unity批处理时会出现问题。例如使用了模型空间下的坐标进行顶点动画。这时可以通过该标签来直接指明是否对该shader使用批处理。 Tags{"DisableBatching" = "True"}
ForecNoShadowCasting 控制该SubShader的物体是否会投射阴影 Tags{"ForceNoShadowCasting" = "True"}
IgnoreProjector 设置该SubShader的物体是否受Projector影响True常用与半透明物体。 Tags{"IgnoreProjector" = "True"}
CanUseSpriteAtlas 当该SubShader用于“sprite”时,将该标签设为False Tags{"CanUseSpriteAtlas" = "False"}
PriviewType 材质面板的预览类型,一般默认材质预览效果是球,形还可以该为"Plane" "SkyBox"。 Tags{"PreviewType" = "Plane"}

上述标签只能在Subshader中声明,而不可以在Pass中声明。

Pass语义块

通过这个名称,我们可以使用ShaderLab的UsePass命令来直接使用其他Unity Shader中的Pass。

Psaa同样可以设置标签,但他的标签不同于SubShader的标签。这些标签也是用于告诉渲染引擎我们希望怎样来渲染该物体。

标签类型 说明 例子
LightModel 定义该Pass在渲染管线中的角色 Tags{"LightModel"="ForwardBase"}
RequireOption 用于指定满足某些条件是才渲染该Pass,他的值是一个由空格分割的字符串。 Pass Tags{"RequireOption" = "SoftVegetation"}

UsePass:

可以用命令来复用其他Unity Shader中的Pass;

GrabPass:

抓取屏幕并将结果储存在一张纹理中,一用于后续的Pass处理。

Fallback

如果上边所有的SubShader在这块显卡上都不能运行,那么就使用最低级别的Shader。

Unity Shader的形式

表面着色器

表面着色器是unity自己创造的一种着色器代码类型。他需要的代码少,unity在背后做了很多的工作,但是渲染的代价比较大。

我们可以理解成,表面着色器是Unity对顶点/片元着色器更高一层的抽象。

表面着色器被定义在SubShader中的CGPROGRAM和ENDCG之间。因为表面着色器不需要开发者关心使用了多少个Pass每个Pass如何渲染等问题。

顶点/片元着色器

Unity中我们可以使用Cg/HLSL语言来编写顶点/片元着色器他们更加复杂,但是灵活性更高。

固定函数着色器

对于不支持可编程渲染管线的着色器,我们应该使用固定函数着色器来完成渲染。我们需要完全使用ShaderLab的语法。由于现在绝大多数GPU都支持可编程的渲染管线,这种固定管线的编程方式已经逐渐被抛弃。

我们如何选择Unity Shader形式

  1. 除非明确要求必须使用固定函数着色器,例如要在一些很老的设备上运行。
  2. 如果你想和光源打交道,你可能跟喜欢使用表面着色器,但是他在移动端性能不佳。
  3. 如果光照比较少,那么使用顶点/片元着色器。
  4. 如果你有很多自定义的渲染效果,请使用顶点/片元着色器。