ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Unity中ShaderLab的基本代码结构与常用语法的归纳整理

2022-03-01 15:02:05  阅读:161  来源: 互联网

标签:name 标签 代码 语法 Unity ShaderLab 着色器 属性


Unity中ShaderLab的基本代码结构与常用语法的归纳整理

Unity中ShaderLab的基本代码结构与常用语法的归纳整理

Shader 是着色器文件的根命令,每个shader文件有且只有一个 Shader
Shader 指定当对象的材质使用此着色器时如何渲染此类对象。

Shader整体结构

Shader "<name>"
{
    <optional: Material properties>
    <One or more SubShader definitions>
    <optional: custom editor>
    <optional: fallback>
}

示例

Shader "Examples/ShaderSyntax"
{
    CustomEditor = "ExampleCustomEditor"

    Properties
    {
        // 此处是材质属性声明
    }
    SubShader
    {
        // 此处是定义子着色器的其余代码

        Pass
        {
           // 此处是定义通道的代码
        }
    }

    Fallback "ExampleFallbackShader"
}

此示例代码演示 Shader 对象的基本语法和结构。示例 Shader 对象有一个包含单个通道的 SubShader。它定义材质属性和一个 Fallback。
而Properties、SubShader、Pass、CustomEditor和Fallback在后文会解释。


属性/Properties

典型的属性包括对象颜色、纹理或者着色器要使用的任意值。

着色器中声明的所有属性都会显示在 Unity 中的材质检视面板中。

属性的代码块:

Properties
{
    <Material property declaration>
    <Material property declaration>
}

定义属性代码块,Properties 代码块可以包含任意数量的材质属性声明。

材质属性声明

所有材质属性声明都遵循以下基本格式:

[optional: attribute] _name("display text in Inspector", type name) = default value

数字和滑动条

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

这些全都定义一个具有默认值的数字(标量)属性。Range 格式使该属性显示为一个滑动条,范围在 minmax 之间。

示例:

_WaveScale ("Wave scale", Range (0.02,0.15)) = 0.07 // 滑动条

颜色和矢量

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

使用给定 RGBA 分量的默认值定义颜色属性,或使用默认值定义 4D 矢量属性。颜色属性会显示拾色器,并根据颜色空间按需进行调整(请参阅着色器程序中的属性)。矢量属性显示为四个数字字段。

纹理

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

分别定义 2D 纹理、立方体贴图或 3D(体积)属性。

着色器中的每个属性均通过 name 引用(在 Unity 中,着色器属性名称通常以下划线开头)。属性在材质检视面板中将显示为 display name。每个属性都在等号后给出默认值:

  • 对于 Range 和 Float 属性,默认值仅仅是单个数字,例如“13.37”。
  • 对于 Color 和 Vector 属性,默认值是括在圆括号中的四个数字,例如“(1,0.5,0.2,1)”。
  • 对于 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)。

注意:Properties 代码块中的着色器参数被序列化为材质数据。着色器程序实际上可以有更多参数(如矩阵、矢量和浮点数),这些参数在运行时从代码中在材质上设置,但如果它们不是 Properties 代码块的一部分,则不会保存它们的值。

属性特性和绘制器

在属性前面,可指定可选的特性(用方括号括起)。

  • [HideInInspector] - 不在材质检视面板中显示属性值。
  • [NoScaleOffset] - 对于具有此特性的纹理属性,材质检视面板不会显示纹理平铺/偏移字段。
  • [Normal] - 表示纹理属性需要法线贴图。
  • [HDR] - 表示纹理属性需要高动态范围 (HDR) 纹理。
  • [Gamma] - 表示在 UI 中将浮点/矢量属性指定为 sRGB 值(就像颜色一样),并且可能需要根据使用的颜色空间进行转换。请参阅着色器程序中的属性。
  • [PerRendererData] - 表示纹理属性将以 MaterialPropertyBlock 的形式来自每渲染器数据。材质检视面板会更改这些属性的纹理字段 UI。
  • [MainTexture] - 表示一个属性 (property) 是材质的主纹理。默认情况下,Unity 将属性 (property) 名称为 _MainTex 的纹理视为主纹理。如果您的纹理具有其他属性 (property) 名称,但您希望 Unity 将这个纹理视为主纹理,请使用此属性 (attribute)。如果您多次使用此属性 (attribute),则 Unity 会使用第一个属性 (property),而忽略后续属性 (property)。
  • [MainColor] - 表示一个属性 (property) 是材质的主色。默认情况下,Unity 将属性 (property) 名称为 _Color 的颜色视为主色。如果您的颜色具有其他属性 (property) 名称,但您希望 Unity 将这个颜色视为主色,请使用此属性 (attribute)。如果您多次使用此属性 (attribute),则 Unity 会使用第一个属性 (property),而忽略后续属性 (property)。

示例

// 水着色器的属性
Properties
{
    _WaveScale ("Wave scale", Range (0.02,0.15)) = 0.07 // 滑动条
    _ReflDistort ("Reflection distort", Range (0,1.5)) = 0.5
    _RefrDistort ("Refraction distort", Range (0,1.5)) = 0.4
    _RefrColor ("Refraction color", Color) = (.34, .85, .92, 1) // 颜色
    _ReflectionTex ("Environment Reflection", 2D) = "" {} // 纹理
    _RefractionTex ("Environment Refraction", 2D) = "" {}
    _Fresnel ("Fresnel (A) ", 2D) = "" {}
    _BumpMap ("Bumpmap (RGB) ", 2D) = "" {}
}

子着色器/SubShader

Unity 中的每个着色器都包含一个子着色器列表。当 Unity 必须显示网格时,它将找到要使用的着色器,并选择在用户的显卡上运行的第一个子着色器。

SubShader的代码块

SubShader
{
    <optional: LOD>
    <optional: tags>
    <optional: commands>
    <One or more Pass definitions>
}

使用 LOD 代码块为 SubShader 分配 LOD(细节级别)值。

LOD代码示例

Shader "Examples/ExampleLOD"
{
    SubShader
    {
        LOD 200
        Pass
        {                
              // 此处是定义通道的代码的其余部分。
        }
    }
    SubShader
    {
        LOD 100
        Pass
        {                
              // 此处是定义通道的代码的其余部分。
        }
    }
}

使用 Tags 代码块将数据的键值对分配给子着色器。

  • 要定义通道标签,请将 Tags 代码块置于 Pass 代码块内部。
  • 要定义子着色器标签,请将 Tags 代码块置于 SubShader 代码块内部,但是在 Pass 代码块外部。
  • 下文会介绍Tags

使用 ShaderLab 命令将 GPU 指令或着色器代码添加到 SubShader。
使用 Pass 代码块定义一个或多个通道。

子着色器定义渲染通道的列表,当Unity选择要用于渲染的子着色器时,它会为每个定义的通道Pass渲染一次对象(并且数量可能由于光交互而增加)。由于对象每次渲染成本都很高,因此需要以尽可能少的通道数量定义着色器。

Pass定义中允许的任何语句也可能出现在SubShader代码块中,这将使所有通道都是用这一“共享”状态。(个人认为与全局变量概念类似)

示例

// ...
Shader "Examples/SinglePass"
{
    SubShader
    {
        Tags { "ExampleSubShaderTagKey" = "ExampleSubShaderTagValue" }
        LOD 100

         // 此处是应用于整个子着色器的 ShaderLab 命令。

        Pass
        {                
              Name "ExamplePassName"
              Tags { "ExamplePassTagKey" = "ExamplePassTagValue" }

              // 此处是应用于此通道的 ShaderLab 命令。

              // 此处是 HLSL 代码。
        }
    }
}

此示例代码演示了用于创建包含单个子着色器的 Shader 对象的语法,而每个子着色器又包含一个通道。

Pass的语法

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

语法

Pass { [Name and Tags] [RenderSetup] }

基本的Pass命令包含渲染状态设置命令的列表。

名称和标签

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

其中,Name和Tags的语法结构如下

Name "PassName"
Tags { "TagName1" = "Value1" "TagName2" = "Value2" }

Name 为当前通道提供 PassName 名称。请注意,在内部,名称将转换为大写。
而标签则是指定 TagName1 具有 Value1TagName2 具有 Value2。可根据需要添加任意数量的标签。

这里简单解释下 标签

标签

从根本上说,标签就是键/值对。在通道中,标签用于控制此通道在光照管线(环境光、顶点光照、像素光照等等)中具有哪个角色以及某些其他选项。请注意,以下由 Unity 识别的标签_必须_位于 Pass 部分中,不能在 SubShader 中!

以下是内置渲染管线中的预定义通道标签

LightMode 标签
LightMode 标签定义通道在光照管线中的角色。很少手动使用这些标签;大部分情况下,需要与光照进行交互的着色器都先编写为表面着色器,然后再处理这些细节。

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

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

回到子着色器中来,
这有一种常用标签:Queue标签——用于渲染顺序
使用 Queue 标签来确定对象的绘制顺序。着色器决定其对象属于哪个渲染队列,这样任何透明着色器都可以确保它们在所有不透明对象之后绘制,依此类推。

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

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

示例

Shader "Transparent Queue Example"
{
     SubShader
     {
        Tags { "Queue" = "Transparent" }
        Pass
        {
            // 着色器主体的剩余部分...
        }
    }
}

还有另一个常用的标签——RenderPipeline 标签
RenderPipeline 标签向 Unity 告知子着色器是否与通用渲染管线 (URP) 或高清渲染管线 (HDRP) 兼容。

  • UniversalRenderPipeline -此子着色器仅与 URP 兼容。
  • HighDefinitionRenderPipeline -此子着色器仅与 HDRP 兼容。
  • (任何其他值,或未声明)-此子着色器与 URP 和 HDRP 不兼容。

示例

Shader "ExampleShader" {
    SubShader {
        Tags { "RenderPipeline" = "UniversalRenderPipeline" }
        Pass {
            …
        }
    }
}

当然标签不止上面这些,具体可查询Unity官方手册_ShaderLab


Fallback

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

语法

Fallback "name"

回退到具有给定_名称 (name)_ 的着色器,或者…

Fallback Off

显式说明即使没有子着色器可以在此硬件上运行,也不会进行回退并且不会显示警告。

示例

Shader "example" {
    // 此处为属性和子着色器...
    Fallback "otherexample"
}

CustomEditor

可为着色器定义一个 CustomEditor。如果执行了此操作,Unity 将查找具有此名称并能扩展 ShaderGUI 的类。如果找到,则使用此着色器的所有材质都将使用此 ShaderGUI。

语法

CustomEditor "name"

使用具有给定 _名称 (name)_ 的 ShaderGUI。

CustomEditor 语句将影响使用此着色器的所有材质。

示例

Shader "example" {
    // 此处为属性和子着色器...
    CustomEditor "MyCustomEditor"
}

ShaderLab 命令

Category

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

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

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

还有其他许多的命令,例如:

  • AlphaToMask:设置 alpha-to-coverage 模式。
  • Blend:启用和配置 alpha 混合。
  • BlendOp:设置 Blend 命令使用的操作。
  • ColorMask:设置颜色通道写入掩码。
  • Conservative:启用和禁用保守光栅化。
  • Cull:设置多边形剔除模式。
  • Offset:设置多边形深度偏移。
  • Stencil:配置模板测试,以及向模板缓冲区写入的内容。
  • ZClip:设置深度剪辑模式。
  • ZTest:设置深度测试模式。
  • ZWrite:设置深度缓冲区写入模式。

受限于篇幅,若想了解具体可前往Unity官方手册_ShaderLab了解。


HLSL代码

HLSL代码块即

Shader "ExampleShader" {
    SubShader {
        Tags { "RenderPipeline" = "UniversalRenderPipeline" }
        Pass {
            CGPROGRAM
    		//这一部分即HLSL代码块
        	ENDCG
        }
    }
}

Pass代码块中CGPROGRAM的内容,由于文章篇幅限制,将于下篇文章再进行归纳整理。


本文参考自Unity官方手册_ShaderLab
结合本人自身理解对Unity官方手册‘ShaderLab’部分的常用内容做了归纳整理。
如有错误遗漏或解释冗余,敬请批评指正

标签:name,标签,代码,语法,Unity,ShaderLab,着色器,属性
来源: https://blog.csdn.net/JRegn/article/details/123190377

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有