【Unity Shader入门】Shader基础概念:渲染流水线
【Unity Shader入门】Shader编程基础:ShaderLab语法
【Unity Shader入门】Shader数学基础:向量(矢量)
【Unity Shader入门】Shader数学基础:矩阵
【Unity Shader入门】Shader数学基础:矩阵变换
【Unity Shader入门】Shader编程初级:Shader结构
Unity Shader != 真正的Shader
Unity Shader实际上是指的就是一个ShaderLab文件。以.Shader作为后缀的一种文件。在Unity Shader里面,我们可以做的事情远多于一个传统意义上的Shader。
1.在传统的Shader中,我们仅可以编写特定类型的Shader,例如顶点着色器、片元着色器等。而在Unity Shader中,我们可以在同一个文件里同时包含需要的顶点着色器和片元着色器代码。
2.在传统的Shader中,我们无法设置一些渲染设置,例如是否开启混合、深度测试等,这些是开发者在另外的代码中自行设置的。而在Unity Shader中,我们通过一行特定的指令就可以完成这些设置。
3.在传统的Shader中,我们需要编写冗长的代码来设置着色器的输入输出,要小心地处理这些输入输出的位置对应关系等。而在Unity Shader中,我们只需要在特定语句块中声明一些属性,就可以依靠材质来方便地改变这些属性。而且对于模型自带的数据(如顶点位置、纹理坐标、法线等),Unity Shader也提供了直接访问的方法,不需要开发者自行编码来传给着色器。
由于Unity Shader的高度封装性,我们可以编写的Shader类型和语法都被限制了。例如:Unity对曲面细分着色器、几何着色器等的支持性就差一些。
可以说,Unity Shader提供了一种让开发者同时控制渲染流水线中多个阶段的方式,不仅仅是提供Shader代码。作为开发者而言,我们绝大部分时候只需要和Unity Shader打交道,而不需要关心渲染引擎底层的实现细节。
Unity Shader是使用ShaderLab语言编写的,但对于表面着色器和顶点/片元着色器,我们可以在ShaderLab内部嵌套CG/HLSL语言来编写这些着色器代码。CG/HLSL代码是区别于ShaderLab的另一个世界。
从本质上讲,Unity Shader只有两种形式:顶点/片元着色器(Unity会把表面着色器转化为包含多Pass的顶点/片元着色器)和固定函数着色器(Unity5.2版本以后,固定函数着色器会被转化成顶点/片元着色器,因此本质上说UnityShader只有顶点/片元着色器一种形式)。
Unity一共提供了4 种Unity Shader 模板供我们选择——
Standard Surface Shader:包含了标准光照模型基于物理的渲染方法表面着色器模板 (PBR)
Unlit Shader:一个不包含光照(但包含雾效)的基本的顶点/片元着色器
Image Effect Shader: 实现各种屏幕后处理效果
Compute Shader:特殊Shader,利用GPU 的并行性来进行一些与常规渲染流水线无关的计算
Shader "Example"
{
//属性块:定义了一些属性参数,可在Unity编辑器的“Inspector”面板中编辑和调整。
Properties
{
//_MainTex是变量名 ("Texture"是在“Inspector”中的名字, 2D是变量类型) = "White" {}是默认值
_MainTex("Texture",2D) = "White" {}
// 整数:创建一个让用户填入整数的栏位
_Int("Int",Int) = 2
// 浮点数:创建一个让用户填入浮点数的栏位
_Float("Float",float) = 1.5
// 在(min,max)范围内的浮点数:创建一个滑动条,可以让用户选择在min和max之间的浮点数值
_Range("Range",range(0.0,2.0)) = 1.0
// 颜色 RGBA:创建一个调色板选择器,可以让用户选择颜色
_Color("Color",color) = (1,1,1,1)
// 四维向量:创建4个栏位,让用户可以填入相应的浮点数,代表一个Vecto4
_Vector("Vector",Vector) = (1,2,3,4)
// 创建一个图片选择框,可以让用户选择贴图
_2D("Texture",2D) = "White" {
// 矩形纹理:创建一个non-power-of-2贴图选择框,功能基本跟2D想同
_Rect("Rect",Rect) = "White" {}
// 立方体贴图纹理:创建一个选择Cubmap的框
_Cube("Cube",Cube) = "White" {}
// 3D纹理
_3D("3D",3D) = "black" {}
}
SubShader{ }
}
一个Shader可以有多个子着色器(SubShader),这些子着色器互不干扰,且只有一个会运行,编写多个子着色器的目的是为了解决平台兼容性问题,Unity会自己选择兼容终端平台的Shader运行。
Shader "Example"
{
Properties{ }
// Unity加载Shader扫描所有SubShader块,使用第一个能在目标平台使用的SubShader块,当所有SubShader都不支持目标平台时会执行Fallback语义块
SubShader{ }
Fallback Off // 当上面Shader运行不了的时候会使用下面的Fallback Shader渲染
}
Unity ShaderLab中,经常会看到各种Tag(标签)。这里大致分为两类Tag,SubShader Tag 和 Pass Tag。
里面写了走里面,外面写了走外面,如果里外定义相同key使用外面的
Shader "Example"
{
Properties{ }
SubShader
{
//标签 可选 key = value
Tags
{
// 渲染顺序:使用 Queue标签,分别放入不同的渲染队列中
"Queue" = "Transparent"
// 着色器替换功能
"RenderType" = "Opaque"
// 是否进行合批
"DisableBatching" = "True"
// 是否投射阴影
"ForceNoShadowCasting" = "True"
// 是否受Projector的影响,通常用于透明物体
"IgnoreProjector" = "True"
// 是否用于图片的shader,通常用于UI
"CanUseSpriteAltas" = "False"
// 用作shader面板预览的类型
"PreviewType" = "Plane"
}
Pass
{
// 在pass通道中特有的Tag设置
Tags
{
// 定义该Pass通道在Unity渲染流水中的角色
"LightMode" = "ForwardBase"
// 当满足某些条件时才渲染该Pass通道
"RequireOptions" = "SoftVegetation"
}
}
}
Fallback Off
}
Rendering Order - Queue tag
在3D引擎中,我们经常要对透明和不透明物体进行排序。先渲染不透明再渲染透明物体,Unity使用 Queue标签,分别放入不同的渲染队列中。
Background:背景,一般天空盒之类的使用这个标签,最早被渲染
Geometry(default):适用于大部分不透明的物体
AlphaTest:如果Shader要使用AlphaTest功能,使用这个队列性能更高
Transparent:这个渲染队列在AlphaTest之后,Shader中有用到Alpha Blend的,或者深入不写入的都应该放在这个队列。
Overlay:最后渲染的队列,全屏幕后期的,都应该使用这个
this render queue is meant for overlay effects. Anything rendered last should go here (e.g. lens flares).
RenderType tag
RenderType tag可以用自定义的字符串,在使用ShadeReplacement,全局替换渲染的时候有用。
Opaque:用于大多数着色器(法线着色器、自发光着色器、反射着色器以及地形的着色器)。
Transparent:用于半透明着色器(透明着色器、粒子着色器、字体着色器、地形额外通道的着色器)。
TransparentCutout:蒙皮透明着色器(Transparent Cutout,两个通道的植被着色器)。
Background:Skybox shaders. 天空盒着色器。
Overlay:GUITexture, Halo, Flare shaders. 光晕着色器、闪光着色器。
TreeOpaque:terrain engine tree bark. 地形引擎中的树皮。
TreeTransparentCutout:terrain engine tree leaves. 地形引擎中的树叶。
TreeBillboard:terrain engine billboarded trees. 地形引擎中的广告牌树。
Grass:terrain engine grass. 地形引擎中的草。
GrassBillboard:terrain engine billboarded grass. 地形引擎何中的广告牌草。
DisableBatching tag
很多着色器中,如果使用的Batching技术,物体的模型空间中的位置信息都没了。如果要设计的模型空间坐标系的操作的Shader,就得禁用 Batching,保存模型空间的信息。 我们可以使用 "DisableBatching " = “True”,默认都是“False”
ForceNoShadowCasting tag
如果要替换一个半透明的物体的Shader,如果想要这个物体不需要产生阴影,就用这个。半透明物体渲染如果不需要阴影就加上标签。
IgnoreProjector tag
Unity有种Projector投影效果,如果加上这个Tag,那么就不会受到投影影响。(贴花,Projector阴影效果)
CanUseSpriteAtlas tag
如果着色器用于精灵,则将CanUseSpriteAtlas标记设置为“ False”,并且在将它们打包到地图集中时不起作用(请参见Sprite Packer)。
PreviewType tag
PreviewType 正常我们都是用一个球体预览材质,设置标签”Plane“ 或者 “Skybox”
Pass Tag 一般控制灯光相关的信息,这些跟SubShader Tag一样,只能在Pass块里面起效果。
LightMode tag
渲染路径标签, 一般现在渲染分为了 三类,顶点渲染路径,向前的渲染,对于的延迟渲染路径。
Always:始终渲染,没有照明
ForwardBase:在前向渲染中,应用了环境光、主方向光、顶点/SH光和光照贴图(只受到环境光,主要(强度最大那个)的方向光,球协光照和lightMap影响)
ForwardAdd:用于正向渲染,应用每个像素的附加光,每个光通过一次。(如果灯光类型是 NO-IMPORT 或者其他类型光源 就会用到这个)
Deferred:延迟渲染的,渲染到Gbuffer
ShadowCaster:渲染物体深度到阴影贴图或深度纹理。(生成阴影要用深度图Shader)
MotionVectors: 渲染物体深度到阴影贴图或深度纹理。用于计算每个物体的运动矢量。(计算物件移动向量)
PrepassBase:用于传统的延迟照明,渲染正常和高光指数。
PrepassFinal:用于传统的延迟照明,渲染最终颜色的纹理,照明和发射。
Vertex:当对象没有光照映射时,在传统顶点光照渲染中使用;所有顶点光照都被应用。
VertexLMRGBM:当对象被光照映射时,在传统顶点光照渲染中使用;在lightMap编码为RGBM (PC和控制台)的平台上。
VertexLM:当对象被光照映射时,在传统顶点光照渲染中使用;在lightMap是double-LDR编码的平台(移动平台)上。
PassFlags tag
通过Pass可以指示更改渲染管道将数据传递给它的方式的标志。 这是通过使用PassFlags标记完成的,该标记的值是用空格分隔标志名称。 当前支持的标志是:
OnlyDirectional: 在ForwardBase传递类型中使用时,使用此标志可以将仅主要定向光和环境/光照探针数据传递到着色器中。 这意味着不重要的光的数据不会传递到顶点光或球谐函数着色器变量中。 有关详细信息,请参见正向渲染。
RequireOptions tag
通过Pass可以表明仅应在满足某些外部条件时才进行渲染。 这是通过使用RequireOptions标记完成的,该标记的值是一串用空格分隔的选项。 当前,Unity支持的选项包括:
SoftVegetation:仅当Quality Settings中设置SoftVegetation处于启用状态时,才渲染此通道。
Shader "Example"
{
Properties{ }
SubShader
{
Tags { }
// 渲染设置
// 裁剪
Cull off
//深度测试
ZTest Always
//深度写入
Zwrite of
// 混合
Blend SrcFactor DstFactor
// 不同情况下使用不同的LOD达到性能提升
Lod 100
Pass
{
Tags { }
// 渲染设置
}
}
Fallback Off
}
Cull
Cull Back(默认):把图片的背面剪裁,相当于背面不进行渲染
Cull Front:把图片的正面剪裁,相当于正面不进行渲染
Cull Off:关闭剔除,正反面都渲染
ZWrite
ZWrite On(默认): 深度写入开启
ZWrite Off:深度写入关闭
深度写入开启后决定片元的深度值是否写入深度缓冲。不建议关闭深度写入,除非有特殊需求,关闭深度写入会有很多意想不到的现象产生。
ZTest
ZTest LEqual(默认):深度小于等于当前缓存则通过
ZTest GEqual:深度大于等于当前缓存则通过
ZTest Equal:深度等于当前缓存则通过
ZTest NotEqual:深度不等于当前缓存则通过
ZTest Less:深度小于当前缓存则通过
ZTest Greater:深度大于当前缓存则通过
ZTest Always:不论如何都通过
ZTest Off:效果跟ZTest Always一样
这里的缓存可以理解成,相机视角此时所保存的某一点的深度值,离相机越近,深度值越大。
Blend
ShaderLab提供了相应的Blend混合命令,用于指定后渲染产生的颜色如何与颜色缓存中的颜色进行混合。混合命令由Blend关键字,操作和因子组成,操作默认是加操作
Blend Off:关闭混合
Blend SrcFactor DstFactor:基本的配置并启动混合操作。对产生的颜色乘以SrcFactor。对已存在于屏幕的颜色乘以DstFactor,并且两者将被叠加在一起。
Blend SrcFactor DstFactor,SrcFactorA DstFactorA:同上,但是使用不同的要素来混合alpha通道,也就是有了4个操作对象
以下所有属性都可以作为SrcFactor或DstFactor。其中Source指的是被计算过的颜色,Destination是已经在屏幕上的颜色
One:值为1,使用此因子来让帧缓冲区源颜色或是目标颜色完全的通过
Zero:值为0,使用此因子来删除帧缓冲区源颜色或目标颜色的值。
SrcColor:使用此因子为将当前值乘以帧缓冲区源颜色的值
SrcAlpha:使用此因子为将当前值乘以帧缓冲区源颜色的Alpha的值
DstColor:使用此因子为将当前值乘以帧缓冲区目标颜色的值。
DstAlpha:使用此因子为将当前值乘以帧缓冲区目标颜色Alpha分量的值
OneMinusSrcColor:使用此因子为将当前值乘以(1-帧缓冲区源颜色值)
OneMinusSrcAlpha:使用此因子为将当前值乘以(1-帧缓冲区源颜色Alpha分量的值)
OneMinusDstColor:使用此因子为将当前值乘以(1-目标颜色值)
OneMinusDstAlpha:使用此因子为将当前值乘以(1-目标颜色Alpha分量的值)
Shader "Example"
{
Properties{ }
SubShader
{
Tags { }
//正常(Normal)
Blend SrcAlpha OneMinusSrcAlpha
//柔和相加(Soft Addtive)
Blend OneMinusDstAlpha One
//正片叠底(Multiply),即相乘
Blend DstColor Zero
//两倍相乘(2x Multiply)
Blend DstColor SrcColor
//滤色(Screen)
Blend OneMinusDstColor One
//线性减淡(Linear Dodge)
Blend One One
Pass { }
}
Fallback Off
}
BlendOp
是混合操作,下面是一些常用的混合操作:
BlendOp Add(默认):将源颜色和目的颜色相加
BlendOp Sub:用源颜色减去目的颜色
BlendOp RevSub:用目的颜色减去源颜色
BlendOp Min:取源颜色和目的颜色中的较小值,是逐分量比较
BlendOp Max:取源颜色和目的颜色中的较大值,是逐分量比较
BlendOp LogicalClear:全部赋值为0,就是透明
BlendOp LogicalSet:全部赋值为1,就是黑色
BlendOp LogicalCopy:复制原颜色的值,相当于前面的Blend One Zero
BlendOp LogicalCopyInverted:把源颜色的值按位取反后渲染
BlendOp LogicalNoop:渲染目的颜色中的像素,相当于前面的Blend Zero One
BlendOp LogicalInvert:把目的颜色中的值按位取反后渲染
BlendOp LogicalAnd:源颜色 & 目的颜色
BlendOp LogicalNand:! (源颜色 & 目的颜色)
BlendOp LogicalOr:源颜色 | 目的颜色
BlendOp LogicalNor:! (源颜色 | 目的颜色)
BlendOp LogicalXor:源颜色 ^ 目的颜色
BlendOp LogicalEquiv:! ( 源颜色 ^ 目的颜色)
BlendOp LogicalAndReverse:源颜色 & !目的颜色
BlendOp LogicalAndInverted:!源颜色 & 目的颜色
BlendOp LogicalOrReverse:源颜色 | !目的颜色
BlendOp LogicalOrInverted:!源颜色 | 目的颜色
Shader "Example"
{
Properties{ }
SubShader
{
Tags { }
//变暗(Darken)
BlendOp Min
Blend One One
//变亮(Lighten)
BlendOp Max
Blend One One
Pass { }
}
Fallback Off
}
LOD
Shader Level of Detail (LOD),翻译过来是什么“着色器的细节层次效果”。Shader LOD其实就是根据设备性能的不同编译不同版本的Shader。这个是另外一种控制细节级别的技术,在一个Shader当中,可以给不同的SubShader指定不同的LOD属性。
根据这个特性,我们就可以在一个Shader里写一出组SubShader,分别设置不同的LOD,LOD越大的对应性能越好,越低的性能越差。然后我们就可以用设置LOD的方法来控制游戏画面的渲染质量。
Shader "Example"
{
Properties{ }
SubShader
{
Tags{ }
LOD 100
}
SubShader
{
Tags{ }
LOD 200
}
Fallback Off
}
在Edit->Project Setting->QualitySettings中的Maximum LOD Level可以设置最大LOD等级,Shader的LOD值是小于所设定的LOD值,才会被编译使用。Maximum LOD Level的等级可以设置7个级别,例如设置为1,则表示把最大LOD值设置为100,等级2,则最大LOD值为200,以此类推,若设置为0,则表示不进行LOD判断,任何LOD值的Shader都会被使用。
一个Pass就是一次绘制,可以看成一个DC(Draw Call),对于表面着色器而言,只有一个Pass,但是顶点片元着色器可以有多个Pass,多个Pass可以实现一些特殊效果。Pass的意义在于多次渲染,如果你有一个Pass,那么着色器只会被调用一次,如果你有多个Pass的话,那么就相当于执行多次SubShader了,这就叫双通道或者多通道。在编写Shader的时候,Pass要尽量的少,每多一个Pass,那么DC就会多一次!而且我们可以在一个Shader中使用另一个Shader的某一个Pass块,Pass块是可以命名的,使用use "passname"这样的方式可调用,具体方式。
Pass { [Name and Tags] [RenderSetup] [TextureSetup] }
Name and tags:一个Pass 可以定义它的名字和任意数量的标签-name/value 字符串 将Pass的含义告诉给渲染引擎。
Render Setup 渲染设置: Pass设置了一系列的显卡状态,比如说alpha混合是否开启,是否允许雾化等等。
Texture Setup 纹理设置:当渲染状态设置以后,你可以用SetTexture命令指定这些纹理和他们的结合方式。
Shader "Example"
{
Properties{ }
SubShader
{
Tags{ }
// 渲染设置
Pass
{
// Pass通道名称,可以当成一个函数进行使用,使用时需要全名称大小调用
Name "name"
// Pass标签
Tags{ }
// Render Setup 渲染设置
// Texture Setup 纹理设置
// CG语言所写的代码,主要是顶点/片元着色器
CGPROGRAM// 插入Cg代码开始
ENDCG // 插入Cg代码结束
}
}
Fallback Off
}
回滚,相当于备胎。
SIKI学院 Unity Shader入门(Unity2018.3)
UnityShader 基础知识
Unity Shader (一)ShaderLab 语法
Unity Shader 中各种Tag
UnityShader与Shader的区别
UnityShader RenderType