unity6 Shaderlab语法笔记
unity6 Shaderlab语法笔记
‘祈止’前言
shaderlab是unity提供的一套着色器方案。使用HLSL语法,并包含一些CG的关键字和一些文件。
注:像素着色器 == 片元着色器
注:本文基本是CG风格写法
CG和HLSL的区别,CG能自动导入shader库。HLSL则需要手动导入。
语法
ulishader框架如下:
1 | Shader "Pao/BasicGrammar" // 这时shader的名称,可用与表示shader,游戏程序可以通过名称找到这个shader。 |
include
可以在代码块(CGPROGRAM)里使用include,导入任意文本文件中的代码,后缀名任意都可以。
但是最好使用Unity规定的.cginc或.hlsl。因为只用这两种才会被unity实时追踪,其内容更改才能实时生效。
语义
定义结构体时,结构体内的变量需要标注语义。以明确其用处。
对于顶点着色器的输出,和像素着色器的输入数据,其语义有以下要求:
1 | struct v2f // 这时像素着色器的输入数据,也是顶点着色器的输出数据 |
TEXCOORDn是通用浮点数据语义,可以表达普通插值变量。
语法糖:
1 | float4(v.uv, 1, 1); //等价于 |
片元着色器的语义:
1 | fixed4 frag (v2f i) : SV_Target // SV_Target也是一个语义 |
SV_Target表示像素着色器的渲染目标,SV_Target就是第0个,也可以有SV_Target1等。
这个语义对应的是是着色器的返回值fixed4,所以也可以写成:
1 | void frag (v2f i, out fixed4 col : SV_Target){ |
材质参数
1 | sampler2D _MainTex; // simpler state + texture2D 采样状态+一张纹理索引 |
采样状态由贴图面板中的 Wrap Mode和Filter Mode决定的。
Wrap Mode:当UV坐标超过0~1的范围时,如何进行采样。
- Repeat:重复,循环采样
- Clamp:边缘拉伸,UV>1的情况取UV=1。
- Mirror:镜像重复,0-1正常,1-2翻转,2-3再翻转
- Mirror Once:只镜像一次,0-1正常,1-2翻转,2以后停在边缘(Clamp)
- Per-axis:分别控制U、V,两个方向使用不同模式。
Filter Mode:是UV对贴图采样的过滤方式,有:
Point (no filter) (不过滤)
Bilinear(双线性过滤):在一张mipmap中的像素间插值。
Trilinear(三线性过滤):在两张mipmap中分别Bilinear,然后两个结果进行层级间插值。
也有特殊的:
- Anisotropic Filtering (各向异性过滤,AF)
uniform变量
变量可以在CG代码块定义,Properties中定义同名同类型的变量,可以在面板中显示它。本质是同一个。
如:
1 | float4 _Color; // 此处定义uniform变量默认值是(0,0,0,0) |
这样写就是让物体变成纯色_Color的颜色。
可以通过脚本代码修改这个颜色:
1 | public class UniformSetter : MonoBehavior |
Properties中定义:
1 | Properties |
这里的_Color一般指主颜色,就是渲染组件(Sprite Renderer)中的Color。在这里写了,unity才会把主颜色赋值给他
这样就能在材质面板中修改shader中的uniform变量。
常用的有:
1 | //数值类型 |
对于数值类型可以不写最后的”{}”,但是对于纹理类型,必须写最后的”{}”。
这个”{}”中用于填写扩展配置,即便没有配置也需要写一个空的”{}”。
数值类型:
- fixed:低精度
- half:中精度
- float:高精度
在高性能平台如PC,unity会默认把fixed和half当做float处理。
想要在高性能平台使用低、中精度,可以在项目设置里,修改shader Settings 下的Shader Precision Model。
在现在,硬件性能更高了。fixed在多数移动平台中也会被作为half处理。
注:Properties中的多分量变量只有:Color和Vector。本质都是四维向量。
使用二维向量或三维向量,要在代码块中定义float2,然后在Properties中使用Color或Vector。这样只对应一部分。
不常用类型:
- Integer:整数
- 2DArray:2D贴图的列表
- CubeArray:Cube贴图的列表
surf shader
除了上述常规shader,unity还提供一种简化shader——surf shader:
1 | Shader "Custom/NewSurfaceShader" |
这种shader只有一个surface,这是unity提供的语法糖。本质上还是顶点像素着色器。可以用于快速的写一些简单光照效果。
渲染状态
渲染状态有以下:
1 | Conservative True // True/False 开启"保守光栅化"。(轮廓描边,阴影体积等) |
渲染状态可以写在:
- SubShader,对次SubShader中的所以Pass生效
- Pass中,对当前Pass生效,生效级别比SubShader更高
Tags
SubShader:
1 | Tags { |
RenderType有以下取值:
- Opaque (不透明)
- Transparent (半透明)
- TransparentCutout (镂空,Alpha测试)
- Background (背景)
- Overlay (UI)
Pass:
1 | Tags { |
注:SubShader和Pass的Tags不一样,改变位置不能生效。
LightMode有以下取值:
Always:无条件执行,忽略光照管线规则,无光照的特效、UI、纯色物体
ForwardBase:正向渲染基础通道(处理主方向光 + 环境光),普通不透明物体的主光照
ForwardAdd 正向渲染附加通道(处理点光 / 聚光灯),多光源场景的附加光照
ShadowCaster 阴影投射通道(生成阴影贴图),物体投射阴影的专用 Pass
PassFlags有以下取值:
- OnlyDirectional:仅处理方向光(太阳 / 主光源)
- None:处理所有类型灯光(默认)
- Specular:仅处理灯光的高光部分(内置管线专用)
RequireOptions有以下取值:
- SoftVegetation 引擎开启SoftVegetation
- DisableBatching 仅合批关闭时执行 Pass
- Instancing 仅实例化渲染时执行 Pass
变体
SubShader变体语法:
1 | Properties |
本质上,unity会将变体编译为多个着色器。
1 |
|
变体的编译指令的用法:
| 编译指令 | 编译 | 用途 | 控制范围 | C#控制 |
|---|---|---|---|---|
| multi_compile | 编译所有变体 | 需要运行时切换变体 | 所有材质 | Shader.SetKeyword(GlobalKeyword.Create(“aa”), true); |
| multi_compile_local | 编译所有变体 | 需要运行时切换变体 | 单个材质 | mat.SetKeyword(“aa”, true); |
| shader_feature | 只编译材质用到的变体 | 不需要动态切换变体 | 所有材质 | Shader.SetKeyword(GlobalKeyword.Create(“aa”), true); |
| shader_feature_local | 只编译材质用到的变体 | 不需要动态切换变体 | 单个材质 | mat.SetKeyword(“aa”, true); |
宏
类似C++的宏定义,是纯粹的文本替换:
1 | // 普通宏 |
swizzle语法
一种语法糖:
1 | SV_Target0.xyw = vec3(1.0,1.0,1.0) //本质对x、y、w分别按顺序赋值。 |
材质UV缩放和偏移
在材质面板的Texture下有Tiling和Offset用于控制UV缩放和偏移。
可以这样声明变量,以关联着两个数值:
1 | sampler2D _MainTex; |
注意:这种写法本质是一个宏。
HLSL风格
(HLSL风格片元着色器,不建议在CG中使用):
1 | TEXTURE2D(_MainTex); // 声明2D纹理 |
(HLSL风格顶点着色器,不能在CG中使用):
1 | struct Attributes |
SRP Batcher
在HLSL中会使用CBUFFER包含所有的uniform变量。
在CG中,使用同一个材质的不同实例的物体会打断合批,原因是不同实例使用了不同的变量。使用SRP Batcher可以将变量缓冲在CBUFFER中,将使用同一个shader变体的但不同实例的物体依旧能够进行合批。
1 | CBUFFER_START(UnityPerMaterial) |
其实在CG中也可以,只要CG代码兼容HLSL并且在URP管线中。因为untiy的CG和HLSL本质是一样的。



