ShaderLab 语法

语法

Shader "name" { [Properties] Subshaders [Fallback] [CustomEditor] }

属性

数字

Range、 Float、Int

name ("display name", Range (min, max)) = number
name ("display name", Float) = number
name ("display name", Int) = number

Range 和 Float默认值仅仅是单个数字,例如“13.37”。 Int 默认值仅仅是单个数字,例如 "13.5"?

颜色和矢量

Color、 Vector

name ("display name", Color) = (number,number,number,number)
name ("display name", Vector) = (number,number,number,number)

Color 和 Vector 属性,默认值是括在圆括号中的四个数字,例如“(1,0.5,0.2,1)”。 ### 纹理

name ("display name", 2D) = "defaulttexture" {}
name ("display name", Cube) = "defaulttexture" {}
name ("display name", 3D) = "defaulttexture" {}

2D 纹理,默认值为空字符串或内置默认纹理之一:“white”(RGBA:1,1,1,1)、“black”(RGBA:0,0,0,0)、“gray”(RGBA:0.5,0.5,0.5,0.5)、“bump”(RGBA:0.5,0.5,1,0.5)或“red”(RGBA:1,0,0,0)。

非 2D 纹理(立方体、3D 或 2D 数组),默认值为空字符串。如果材质未指定立方体贴图/3D/数组纹理,则使用灰色(RGBA:0.5,0.5,0.5,0.5)。

属性特性和绘制器

在属性前面,可指定可选的特性(用方括号括起)。这些是 Unity 可以识别的特性,或者它们可以指示您自己的 MaterialPropertyDrawer 类 来控制它们在材质检视面板中的呈现方式。Unity 可以识别的特性包括:

  • [HideInInspector] - 不在材质检视面板中显示属性值。
  • [NoScaleOffset] - 对于具有此特性的纹理属性,材质检视面板不会显示纹理平铺/偏移字段。
  • [Normal] - 表示纹理属性需要法线贴图。
  • [HDR] - 表示纹理属性需要高动态范围 (HDR) 纹理。
  • [Gamma] - 表示在 UI 中将浮点/矢量属性指定为 sRGB 值(就像颜色一样),并且可能需要根据使用的颜色空间进行转换。请参阅着色器程序中的属性。
  • [PerRendererData] - 表示纹理属性将以 MaterialPropertyBlock 的形式来自每渲染器数据。材质检视面板会更改这些属性的纹理字段 UI。

SubShader

子着色器定义渲染通道的列表,并且可选择性地设置所有通道共同的任意状态。此外,还可以设置子着色器专用的标签。

当 Unity 选择要用于渲染的子着色器时,它会为每个定义的通道 (Pass) 渲染一次对象(并且数量可能由于光交互而增加)。由于对象的每次渲染成本都很高,因此应以尽可能少的通道数量定义着色器。当然,有时在某些图形硬件上,所需的效果不能在单个通道中完成;那么您别无选择,只能使用多个通道。

每个通道定义可以是常规 Pass、Use Pass 或 Grab Pass。

Pass 定义中允许的任何语句也可能出现在子 Subshader 代码块中。这将使所有通道都使用这一“共享”状态。

Pass

Pass 代码块将使游戏对象的几何体被渲染一次。

语法

Pass { [Name and Tags] [RenderSetup] }

名称和标签

一个通道 (Pass) 可以定义一个名称 (Name) 和任意数量的标签 (Tags)。这些名称/值字符串用于将通道的意图传达给渲染引擎。

渲染状态设置

一个通道将设置图形硬件的各种状态,例如是否应开启 Alpha 混合或是否应使用深度测试。

剔除和深度测试

剔除是一种优化方式,即不渲染背离观察者的多边形。所有多边形都有正面和背面。剔除利用大多数对象均为封闭体这一事实;如果您有一个立方体,您将永远不会看到背离您的面(前方始终只有一面朝向您),所以我们不需要绘制背离的面。因此有了“背面剔除”一词。

让渲染看起来正确的另一个功能是“深度测试”。深度测试确保在场景中仅绘制距离最近的表面对象。

  • 设置多边形剔除模式。 Cull
Cull Back | Front | Off

控制应该剔除多边形的哪些面(不绘制)

*   Back 不渲染背离观察者的多边形**(默认值)**。
*   Front 不渲染面向观察者的多边形。用于从里到外翻转对象。
*   Off 禁用剔除 - 绘制所有面。**用于特殊效果**。
  • 设置深度缓冲区写入模式。 ZWrite
ZWrite On | Off

控制是否将此对象的像素写入深度缓冲区(默认值为 On)。如果要绘制实体对象,请将其保留为 on。如果要绘制半透明效果,请切换到 ZWrite Off。

  • 设置深度缓冲区测试模式。

ZTest

ZTest (Less | Greater | LEqual | GEqual | Equal | NotEqual | Always)

应如何执行深度测试。默认值为 LEqual(将前方或远处的对象作为现有对象绘制;隐藏其后面的对象)。

  • 设置 Z 缓冲区深度偏移。 Offset
Offset Factor, Units

允许使用两个参数指定深度偏移:factor 和 units。Factor 相对于多边形的 X 或 Y 缩放最大 Z 斜率,而 units 缩放最小可分辨深度缓冲区值。因此可强制将一个多边形绘制在另一个多边形上,尽管它们实际上位于相同位置。例如,Offset 0, -1 将多边形拉近摄像机并忽略多边形的斜率,而 Offset -1, -1 在观察掠射角时进一步拉近多边形。

设置 Alpha 混合、Alpha 操作和 alpha-to-coverage 模式。

Blend sourceBlendMode destBlendMode
Blend sourceBlendMode destBlendMode, alphaSourceBlendMode alphaDestBlendMode
BlendOp colorOp
BlendOp colorOp, alphaOp
AlphaToMask On | Off

设置颜色通道写入遮罩

设置颜色通道写入遮罩。写入 ColorMask 0 可关闭对所有颜色通道的渲染。默认模式是 写入所有通道 (RGBA),但是对于某些特殊效果,您可能希望不修改某些通道,或完全禁用颜色 写入。

使用多渲染目标 (MRT) 渲染时,可通过在末尾添加索引(0 到 7)来为每个渲染目标设置不同的颜色遮罩。例如,ColorMask RGB 3 将使渲染目标 #3 仅写入到 RGB 通道。

ColorMask RGB | A | 0 | R、G、B、A 的任意组合

旧版固定函数着色器命令

一些命令用于编写旧版“固定函数样式”着色器。这是视为已弃用的功能,因为编写表面着色器或着色器程序 可带来更大的灵活性。但是,对于非常简单的着色器,以固定函数样式编写着色器有时会更容易,因此这里提供了命令。请注意,如果不使用固定函数着色器,则会忽略以下所有命令。 ##### 固定函数 Lighting 和 Material

Lighting On | Off
Material { Material Block }
SeparateSpecular On | Off
Color Color-value
ColorMaterial AmbientAndDiffuse | Emission

所有这些均控制固定函数每顶点光照:它们将其开启,设置材质颜色,开启镜面高光,提供默认颜色(如果顶点光照关闭),并控制网格顶点颜色如何影响光照。

固定函数 Fog
Fog { Fog Block }
固定函数 AlphaTest
AlphaTest (Less | Greater | LEqual | GEqual | Equal | NotEqual | Always) CutoffValue
固定函数纹理组合器
SetTexture textureProperty { combine options }

混合

ShaderLab:通道标签

 Tags { "TagName1" = "Value1" "TagName2" = "Value2" }
LightMode 标签定义通道在光照管线中的角色。

LightMode 标签的可能值:

  • Always:始终渲染;不应用光照。
  • ForwardBase:在前向渲染中使用;应用环境光、主方向光、顶点/SH 光源和光照贴图。
  • ForwardAdd:在前向渲染中使用;应用附加的每像素光源(每个光源有一个通道)。
  • Deferred:在延迟渲染中使用;渲染 G 缓冲区。
  • ShadowCaster:将对象深度渲染到阴影贴图或深度纹理中。
  • MotionVectors:用于计算每对象运动矢量。
  • PrepassBase:在旧版延迟光照中使用;渲染法线和镜面反射指数。
  • PrepassFinal:在旧版延迟光照中使用;通过组合纹理、光照和反光来渲染最终颜色。
  • Vertex:当对象不进行光照贴图时在旧版顶点光照渲染中使用;应用所有顶点光源。
  • VertexLMRGBM:当对象不进行光照贴图时在旧版顶点光照渲染中使用;在光照贴图为 RGBM 编码的平台上(PC 和游戏主机)。
  • VertexLM:当对象不进行光照贴图时在旧版顶点光照渲染中使用;在光照贴图为双 LDR 编码的平台上(移动平台)。

#####PassFlags 标签

一个通道可指示一些标志来更改渲染管线向通道传递数据的方式。这可通过使用 PassFlags 标签来实现,该标签的值为空格分隔的标志名称。目前支持以下标志:

  • OnlyDirectional:在 ForwardBase 通道类型中使用时,此标志的作用是仅允许主方向光和环境光/光照探针数据传递到着色器。这意味着非重要光源的数据将不会传递到顶点光源或球谐函数着色器变量。请参阅前向渲染以了解详细信息。

#####RequireOptions 标签

一个通道可指示仅当满足某些外部条件时才渲染该通道。这可通过使用 RequireOptions 标签来实现,该标签的值为空格分隔的选项字符串。目前,Unity 支持以下选项:

  • SoftVegetation:仅当 Quality 窗口中开启了 Soft Vegetation 时才渲染此通道。

模板缓冲

模板缓冲区可用作一般目的的每像素遮罩,以便保存或丢弃像素。

模板缓冲区通常是每像素 8 位整数。该值可以写入、递增或递减。后续绘制调用可以根据该值进行测试,以确定在运行像素着色器之前是否应丢弃像素。

Ref

    Ref referenceValue

要比较的参考值(如果 Comp 是 always 以外的任何值)和/或要写入缓冲区的值(如果 Pass、Fail 或 ZFail 设置为替换)。值为 0 到 255 之间的整数。

ReadMask、WriteMask、Comp、Pass、Fail、ZFail

    ReadMask readMask

这是一个 8 位掩码,值为 0 到 255 之间的整数,用于比较参考值和缓冲区的内容 (referenceValue & readMask) comparisonFunction (stencilBufferValue & readMask)。默认值:255

    WriteMask writeMask

这是一个 8 位掩码,值为 0 到 255 之间整数,写入缓冲区时使用。请注意,与其他写掩码一样,它指定写操作将影响模板缓冲区的哪些位(例如 WriteMask 0 表示不会影响任何位,也不会写入 0)。默认值:255

    Comp comparisonFunction

用于将参考值与缓冲区的当前内容进行比较的函数。默认值:always

    Pass stencilOperation

如果模板测试(和深度测试)通过,如何处理缓冲区的内容。默认值:keep

    Fail stencilOperation

如果模板测试(和深度测试)失败,如何处理缓冲区的内容。默认值:keep

    ZFail stencilOperation

如果模板测试通过但深度测试失败,如何处理缓冲区的内容。默认值:keep

Comp、Pass、Fail 和 ZFail 将应用于正面几何体,除非指定了 Cull Front,在这种情况下将应用于背面几何体。您还可以通过定义 CompFront、PassFront、FailFront 或 ZFailFront(用于正面几何体)以及 CompBack、PassBack、FailBack 或 ZFailBack(用于背面几何体)来显式指定双面模板状态。

比较函数
函数 解释
Greater 仅渲染参考值大于缓冲区值的像素。
GEqual 仅渲染参考值大于或等于缓冲区值的像素。
Less 仅渲染参考值小于缓冲区值的像素。
LEqual 仅渲染参考值小于或等于缓冲区值的像素。
Equal 仅渲染参考值等于缓冲区值的像素。
NotEqual 仅渲染参考值不同于缓冲区值的像素。
Always 使模板测试始终通过。
Never 使模板测试始终失败。
模板操作
函数 解释
Keep 保持缓冲区的当前内容。
Zero 将 0 写入缓冲区。
Replace 将参考值写入缓冲区。
IncrSat 递增缓冲区中的当前值。如果该值已经是 255,则保持为 255。
DecrSat 递减缓冲区中的当前值。如果该值已经是 0,则保持为 0。
Invert 将所有位求反。
IncrWrap 递增缓冲区中的当前值。如果该值已经是 255,则变为 0。
DecrWrap 递减缓冲区中的当前值。如果该值已经是 0,则变为 255。
延迟渲染路径

在延迟渲染路径中渲染的对象的模板功能在某种程度上受到限制,因为在基础通道和光照通道期间,模板缓冲区用于其他目的。在这两个阶段中,着色器中定义的模板状态将被忽略,而仅在最终通道期间考虑。因此,不可能基于模板测试来屏蔽这些对象,但是它们仍然可以修改缓冲区内容,以供稍后在帧中渲染的对象使用。在延迟路径之后在前向渲染路径中渲染的对象(例如透明对象或没有表面着色器的对象)将再次正常设置其模板状态。

延迟渲染路径使用模板缓冲区的三个最高位,加上最多四个最高位(具体取决于场景中使用的光遮罩层数)。可以使用模板读写掩码在“干净”的位范围内操作,也可以使用 Camera.clearStencilAfterLightingPass 强制摄像机在光照通道后清理模板缓冲区。

ShaderLab:Name

Name "PassName"

为当前通道提供 PassName 名称。请注意,在内部,名称将转换为大写

ShaderLab:UsePass

UsePass "Shader/Name"

插入来自给定着色器的具有给定名称的所有通道。Shader/Name 包含着色器名称和通道名称,以斜杠字符分隔。请注意,系统只会考虑第一个受支持的子着色器。

ShaderLab:GrabPass

GrabPass 是一种特殊通道类型,它把即将绘制对象时的屏幕内容抓取到纹理中。在后续通道中即可使用此纹理,从而执行基于图像的高级效果。

GrabPass 包含在子着色器内部。它可采用两种形式:

  • 简单的 GrabPass { } 可将当前屏幕内容抓取到某个纹理中。在随后的通道中可通过 _GrabTexture 名称访问该纹理。注意:这种抓取通道的形式将为使用它的每个对象执行耗时的屏幕抓取操作。
  • GrabPass { "TextureName" } 可将当前屏幕内容抓取到纹理中,但仅为使用给定纹理名称的第一个对象在每一帧执行一次该操作。在后续通道中可通过给定纹理名称访问该纹理。场景中有多个对象在使用 GrabPass 时,这种方法更高效。

ShaderLab:子着色器标签 (SubShader Tags)

标签用于确定子着色器的渲染顺序和其他参数。请注意,以下由 Unity 识别的标签必须位于 SubShader 部分中,不能在 Pass 中!

除了 Unity 可以识别的内置标签外,您还可以使用自己的标签并使用 Material.GetTag 函数来查询这些标签。

  • 渲染顺序 - Queue 标签

有四个预定义的渲染队列,但预定义的渲染队列之间可以有更多的队列。预定义队列包括:

  • Background - 此渲染队列在任何其他渲染队列之前渲染。通常会对需要处于背景中的对象使用此渲染队列。
  • Geometry(默认值)- 此队列用于大部分对象。不透明几何体使用此队列。
  • AlphaTest - 进行 Alpha 测试的几何体将使用此队列。这是不同于 Geometry 队列的单独队列,因为在绘制完所有实体对象之后再渲染经过 Alpha 测试的对象会更有效。
  • Transparent - 此渲染队列在 Geometry 和 AlphaTest 之后渲染,按照从后到前的顺序。任何经过 Alpha 混合者(即不写入深度缓冲区的着色器)都应该放在这里(玻璃、粒子效果)。
  • Overlay - 此渲染队列旨在获得覆盖效果。最后渲染的任何内容都应该放在此处(例如,镜头光晕)。

对于特殊用例,可以使用中间队列。在内部,每个队列由整数索引表示;Background 是 1000,Geometry 是 2000,AlphaTest 是 2450,Transparent 是 3000,Overlay 是 4000。如果着色器使用如下所示的队列:

Tags { "Queue" = "Geometry+1" }

这将使对象在所有不透明对象之后渲染,但在透明对象之前渲染,因为渲染队列索引值将是 2001(几何体索引值加一)。如果您希望始终在其他对象集之间绘制某些对象,那么这非常有用。例如,在大多数情况下,透明的水应该在不透明对象之后绘制,但又要在透明对象之前绘制。

索引值高达 2500 的队列(“Geometry+500”)视为“不透明”,并且会优化对象的绘制顺序以获得最佳性能。 较高索引的渲染队列被认为是“透明对象”并按距离将对象进行排序,从距离最远的对象开始渲染,最后渲染距离最近的对象。天空盒在所有不透明对象和所有透明对象之间绘制。

  • RenderType 标签 RenderType 标签将着色器分为几个预定义的组,例如,不透明的着色器,或经过 Alpha 测试的着色器等等。着色器替换将使用该标签,在某些情况下还用于产生摄像机的深度纹理。

  • DisableBatching 标签

使用绘制调用批处理时,一些着色器(主要是进行对象空间顶点变形的着色器)不起作用,这是因为批处理会将所有几何体转换为世界空间,所以“对象空间”丢失。

可使用 DisableBatching 标签来指示这一情况。有三个可能的值:“True”(始终对此着色器禁用批处理)、“False”(不禁用批处理;这是默认值)和“LODFading”(当 LOD 淡化处于激活状态时禁用批处理;主要用于树)。

不起作用的情况下,禁用提高性能?

  • ForceNoShadowCasting 标签 如果提供了 ForceNoShadowCasting 标签并且值为“True”,则使用该子着色器渲染的对象绝不会投射阴影。对透明对象使用着色器替换并且不希望从其他子着色器继承阴影通道时,这非常有用。

  • IgnoreProjector 标签

如果提供了 IgnoreProjector 标签并且值为“True”,则使用此着色器的对象不会受到投影器的影响。这对半透明对象非常有用,因为投影器无法影响它们。

  • CanUseSpriteAtlas 标签

如果着色器用于精灵,请将 CanUseSpriteAtlas 标签设置为“False”,这样在精灵打包到图集内时,该标签将不起作用。(精灵打包器 (Sprite Packer)。

  • PreviewType 标签

PreviewType 指示材质检视面板预览应如何显示材质。默认情况下,材质显示为球体,但也可以将 PreviewType 设置为“Plane”(将显示为 2D)或“Skybox”(将显示为天空盒)。

Fallback

在所有子着色器的后面可定义 Fallback。基本上就是说,“如果没有任何子着色器能够在此硬件上运行,则尝试使用另一个着色器中的子着色器”。

 Fallback "name"
 //或者
 // Fallback Off

CustomEditor

ShaderLab:其他命令

Category 是一种逻辑分组,其中包含属于该分组的所有命令。这主要用于“继承”渲染状态。例如,您的着色器可能有多个子着色器,并且其中每个子着色器都需要关闭雾效、将混合设置为附加等,便可为此使用 Category:

Shader "example" {
Category {
    Fog { Mode Off }
    Blend One One
    SubShader {
        // ...
    }
    SubShader {
        // ...
    }
    // ...
}
}

Category 代码块仅影响着色器解析,效果完全等同于将 Category 中设置的任意状态“粘贴”到 Category 下面的所有代码块中。这完全不会影响着色器执行速度。


文章作者: Yonggang Long
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Yonggang Long !
 上一篇
2022-08-10 Yonggang Long
下一篇 
2022-08-10 Yonggang Long
  目录