Unity Shader基础代码结构

部分资料取自冯乐乐的《Unity Shader入门精要》

名字

在shader第一行我们需要指定unity shader的名字,名字可以通过“/”来进行层次的划分,例如“Custom/TestShader”

在unity的材质面板中就能在Custom标签那一栏中找到TestShader

shader结构

语法:

shader
1
Shader "Custom/TestShader"{}

Properties

在这里设置需要unity材质面板中能够方便调整的各种属性

这里的属性包含三个部分:

  1. 名字:名字主要是在unity shader中访问需要的名字,通常是以”_”开始
  2. 显示名称:这里的名称是在unity材质面板中显示的名字
  3. 类型:类型则指定了unity shader中这些属性的类型,并且我们需要给这些属性提供默认值

Properties中支持以下类型:

属性类型 例子
Int _Number (“Number”, Int) = 2
Float _Intensity (“Intensity”, Float) = 1.5
Range(min, max) _SideRange (“SideRange”, Range(0.0, 5.0)) = 3.0
Color _RimColor (“RimColor”, Color) = (1,1,1,1)
Vector _LightDir (“LightDir”, Vector) = (2,3,6,1)
2D _2DTex (“2D”, 2D) = “”{}
Cube _CubeTex (“Cube”, Cube) = “white”{}
3D _3DTex (“3D”, 3D) = “white”{}

Subshader

每个unity shader可以包含多个subshader,在加载shader的时候会扫描所有的subshader模块,然后选择第一个能够使用的subshader。如果都不行那么就会使用Fallback定义的unity shader。subshader和pass中都可以包含Tags和RenderSetup,如果设置在subshader中那么将适用于所有的pass

subshader结构:

shader
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
SubShader{
// 可选部分
[Tags]

[RenderSetup]

// pass定义,可以有多个pass
// 第一个pass
Pass{

}

// 第二个pass
Pass{

}
}

RenderSetup

提供一些列渲染状态的设置,例如是否开启混合,开启深度测试等等

状态名称 设置指令 解释
Cull Cull Back|Front|Off 设置剔除模式:背面/正面/关闭
ZTest ZTest Less|Greater|LEqual|GEqual|Equal|NotEqual|Always 设置深度测试使用函数
ZWrite ZWrite On|Off 深度写入开关
Blend Blend SrcFactor DstFactor 混合模式设置

ZTest参数解释:

  • LEqual:小于等于
  • GEqual:大于等于
  • Always:无论如何都通过

Tags

Tags是以键值对的形式存在的,主要是告诉渲染引擎,希望怎样来渲染这个对象

标签结构

shader
1
Tags {"TagName1"="Value1" "TagName2"="Value2"}

常用的两种标签类型

标签类型 说明
Queue 控制渲染顺序,指定渲染队列 Tags {“Queue”=”Transparent”}
RenderType 对着色器进行分类,例如不透明和透明着色器,可用于Shader replacement Tags {“RenderType”=”Opaque”}

Fallback

Fallback用于告诉unity如果所有subshader都不能用那么就用这里这个,Fallback还可用于阴影的投射

Fallback “shader名字”

Fallback off


最终unity shader大致结构如下:

shader
1
2
3
4
5
6
7
8
9
10
11
Shader "Custom/SimpleShader"{
Properties{

}
SubShader{
pass{

}
}
Fallback "Diffuse"
}

shader样例

Shader
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
Shader "Custom/testShader"{
Properties{
// _Float为变量名字,可以自由更改,以_起头作为传统
_Float("Float", Float) = 0.0
_Range("Range", Range(0.0,1.0)) = 0.0
_Vector("Vector", Vector) = (1,1,1,1)
_Color("Color", Color) = (0.5,0.5,0.5,0.5)
_MainTex("MainTex", 2D) = "black"{}
}
SubShader{
pass{
// 以CGPROGRAM和ENDCG包裹
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"

struct appdata{
float4 vertex:POSITION;
float2 uv:TEXCOORD0;//TEXCOORD0这里是第一套uv的意思
// float3 normal:NORMAL;
// float4 color:COLOR;
};

struct v2f{
float4 pos:SV_POSITION;
float2 uv:TEXCOORD0; //TEXCOORD0是储存器
};
// 这里声明的变量需要和Properties里面的一致
float4 _Color;
// 纹理需要配一个float4才能够调用tilling和offset
sampler2D _MainTex;
float4 _MainTex_ST;

v2f vert(appdata v){
v2f o;
// mvp变换的两种方式
// float4 world_pos = mul(unity_ObjectToWorld, v.vertex);
// float4 camera_pos = mul(UNITY_MATRIX_V, world_pos);
// float4 projection_pos = mul(UNITY_MATRIX_P, camera_pos);
float4 projection_pos = UnityObjectToClipPos(v.vertex);
o.pos = projection_pos;
// 获取uv
o.uv = v.uv * _MainTex_ST.xy + _MainTex_ST.zw;
return o;
}

float4 frag(v2f i):SV_TARGET{
// 贴图采样
float4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
}
}