【转载】零基础入门 Unity Shader(四)

394 阅读9分钟

原文链接

零基础入门Unity Shader(四) | taecg

原文写得很好,但是主题格式我不太喜欢,所以我对文章的格式进行了修整,方便自己日后阅读

正文

前言

在上篇介绍了 Shader 的框架后,这篇我们来细说一下 Porperties 属性部分。

Properties 可以理解为是材质与 Shader 的连接通道,我们在材质面板上需要设置的内容都 必须 通过 Properties 来实现并暴露。

语法格式

属性的写法有个通用的格式:

[Attribute]_Name ("Display Name",Type) = Default Value

Attribute

属性标记,说白了就是 Unity 内置的几个属性标记关键字,用于对当前这条属性进行一些特殊的处理,在下面会进行详细介绍。

此标记不是必选项,可以不添加,同时一条属性上也可以有多条属性标记。

_Name

属性的名称,也就是变量名,在 Shader 的 CG 代码中就是通过这个名称来调用此属性内容的,在外部利用脚本调用时也是这个名称,所以一定要用英文。

在名称前 一定 要加上 下划线,否则会出现编绎错误!至于为什么加下划线,没有去细究原因,有知道的可以告知分享下〜

关于此变量名,有一点 很重要
就是如果此 Shader 有 FallBack 的话,一定 要将此 Shader 中的变量名与 FallBack 中的变量名保持一致,否则会出现 FallBack 后原有的属性值获取不到的情况,切记!

Display Name

显示在材质面板上的名称,主要起到说明解释的作用,可中文(正式项目中建议 最好 还是用英文)。

建议这里的显示名称要起的有意义,要知道最终在材质上调节的人很大部分情况下不会是你自己,别人更不可能知道每个属性内部是如何关联以及有什么作用,所以当我们 TA 在做完一个 Shader 给到使用人员的时候,一定要给他讲解一下,不管是有个说明文档还是简单沟通下都是 有必要 的。这样才能最大发挥 Shader 的使用效果,所以显示名称起着一半说明书的作用,一定要重视。
什么样的名字是有意义的呢?
作用与通道的组合(在需要说明通道的情况下)。
比如:一张基础表面色贴图,可以用 "Base (RGB)",这样既说明了此贴图是基本贴图,同时又说明了此贴图在表面色上只使用到了 RGB 三个通道。

Type

属性的类型,常用的有以下几种:

  1. Color 颜色
  2. Int 整数
  3. Float 浮点数
  4. Vector 四维数
  5. 2D 纹理
  6. 3D 纹理
  7. Cube 立方体纹理

每条属性是什么,以及在材质面板上应该显示什么都是由此类型来决定的,在下面会进行详细介绍说明。

Default Value

默认值,当第一次指定此 Shader 时,或者在材质面板上执行 Reset 时,属性的值会自动恢复到默认值,不同的类型具体写法也不太一样,下面会结合类型进行详细说明。

Color(类型:颜色)

示例如下:

Properties
{
     _Color("我是 Color", Color) = (1,1,1,1)
}
  • 变量名:_Color
  • 显示名称:我是 Color
  • 类型:Color
  • 默认值:(1,1,1,1)

颜色属性是个四维分量,也就是由四个数值来组成的,每个数值代表着颜色的一个通道。四个数值依次为 RGBA(红,绿,蓝,透明)。

RGB 的取值是 0-255(2 的 8 次方个值域),而在 Shader 中被归一化为 0-1 间。

Shader 中的浮点数值后不需要加后缀 f,否则会出错。
零点几的值可以省略零,比如 0.95 可以写成 .95

[HDR]

Properties
{
        [HDR]_Color("Color", Color) = (1,1,0,1)
}

当给颜色添加了 HDR 后,则在材质面板中的颜色上会显示 HDR 的字样。同时点击颜色弹出来的取色器面板中也会多出一条 Intensity 的选项(2018.3 版本,2017 版本是Brightness)。

HDR 可以使颜色亮度的值超过 1,通过这个值可以配合镜头 Bloom 效果做出物体泛光的视觉效果。

Int(类型:整型)

示例如下:

Properties
{
        _Int("我是 Int", Int) = 1
}
  • 变量名:_Int
  • 显示名称:我是 Int
  • 类型:Int
  • 默认值:1

虽然在材质面板中我们可以随意输入数值,比如 0.55, 但是在 Shader 内部它却只能被识别为整数。

注意,此值并不是四舍五入,而是直接取整,比如 1.999,结果是 1.

Float(类型:浮点数)

示例如下:

Properties
{
        _Float("我是 Float", Float) = 0.5
}
  • 变量名:_Float
  • 显示名称:我是 Float
  • 类型:Float
  • 默认值:0.5

Int 长的很像,只不过 Float 中支持浮点数。

在 Shader 中 Float 是最基本的类型,而 Int 只是一种 伪整型,从 Shader 精度上来讲并不存在整型。所以在 Properties 内完全可以用 Float 替代 Int

[Range]

Properties
{
        _Float("我是Float", Range( 0 , 1)) = 0.5
}

很常用的一种属性标记,主要是用来将浮点数 限制在一个可以通过滑动条来选择的一个区间

将此属性中原有的 Float 替换成 Range (Min,Max) 即可,Min=最小值,Max=最大值。

[PowerSlider]

Properties
{
        [PowerSlider(3)]_Float("我是Float", Range( 0 , 1)) = 0.5
}

先上张图:

我们拿它跟上面的不加 PowerSlider 来对比,同样是值 0.5 , 在材质面板上滑杆的位置是不一样的。

PowerSlider (Value)

其中 Value 的值我们可以自由定义,支持浮点数, 值越大会导致滑条的曲度变化越大,值为 1 时不改变。

此属性标记的主要作用,是 方便用户调节滑杆。比如有个属性值是从 0-1,但是很大部分情况下所用到的值都是 0-0.1 左右,同时需要 更精细 的在这区间进行微调。那么正常情况下,用户在整个滑条上想选择 0-0.1 之间本身就变的很难了,更不要说在这区间微调了。所以这个时候就可以利用 PowerSlider 来解决此问题。

[IntRange]

Properties
{
        [IntRange]_Float("我是Float", Range( 0 , 1)) = 1
}

加了它之后呢,你在材质面板上拖动时就只能生成整数了。所以说我们完全可以用 Float 来代替 Int

注意,当添加了 [IntRange] 后,默认值会被自动进行处理,假如默认值你写的是 0.1,则在 Shader 内部会自动 向下取整,取值为 0.

[Toggle]

开关,0 代表关,1 代表开,就这么简单。

Properties
{
        [Toggle]_Float("我是Float", Range( 0 , 1)) = 1
}

[Enum]

枚举,美术问:啥是枚举呀?答:你可以理解为就是下拉列表啦~

Properties
{
 [Enum(UnityEngine.Rendering.CullMode)]_Float("我是Float", Float) = 1
}

关于 ToggleEnum 我们会在后续的篇章中详细探讨,到时会结合具体用法与功能再来说明,这样比较好理解。这里仅仅只是知道下我们可以通过Float来实现这些功能。

Vector(类型:四维向量)

示例如下:

Properties
{
        _Vector("我是 Vector", Vector) = (0,0,0,0)
}
  • 变量名:_Vector
  • 显示名称:我是 Vector
  • 类型:Vector
  • 默认值:(0,0,0,0)

由四个 Float 组合而成的 Vector ,在材质面板中显示的是四个数值输入框。

四个分量分别对应 XYZW,也可以叫做 RGBA

XYZWRGBA 同样都是四个分量组合,只是在用于颜色时我们通常用 RGBA 来表示,用作坐标时习惯用 XYZW 来表示而已,同样我们也是可以用 Vector 来输出颜色,只是不那么方便直观而已。

2D(类型:2D纹理)

示例如下:

Properties
{
        _MainTex("我是 2D 纹理", 2D) = "white" {}
}
  • 变量名:_MainTex
  • 显示名称:我是 2D 纹理
  • 类型:2D
  • 默认值:white

纹理贴图,也是 Shader 中最最常用的属性之一。

[NoScaleOffset]

Properties
{
        [NoScaleOffset]_MainTex("我是2D纹理", 2D) = "white" {}
}

在材质面板中除了显示贴图槽以外默认还会显示两组Float。

  1. Tiling (贴图重复度)
  2. Offset (贴图偏移值)

如需让这两组值产生作用,我们需要在 Shader 中添加一些代码以支持,在后续文章中会讲解。

如果我们不希望用户去调节此参数,或者为了使性能极致化,我们可以考虑把它们的代码功能移除掉,但一旦如此,材质面板中的参数将不起作用,这时我们就可以使用 [NoScaleOffset] 属性标记来将它们隐藏掉。

[Normal]

Properties
{
        [Normal]_MainTex("我是2D纹理", 2D) = "white" {}
}

如果我们希望用户指定贴图时选择法线,那我们要怎么办呢,我们并不能控制用户会选择什么类型的贴图。

此时我们可以通过添加 [Normal],来标记此属性是 用来接收法线贴图的,当用户指定了非法线的贴图时会在材质面板上进行警告提示:

有一点一定要 注意,有时美术在其它软件中导出了法线贴图,但在 Unity 直接拖上来还是会有警告提示,是因为没有在贴图导入面板中把 Texture Type 设置为Normal,只有这样这张贴图才会被 Unity 识别为法线。

默认值

2D 纹理的默认值有以下几种:

  1. white
  2. black
  3. gray
  4. bump

如果不设置默认值,即 =""{},则其实与 ="gray"{} 相同。

当设置了默认值后,Shader 内部会自动调用 Unity 内部准备的一张小图片,white 就是纯白色, black 就是纯黑色,gray 就是灰色图,bump 就是法线图。

3D(类型:3D纹理)

示例如下:

Properties
{
        _MainTex("我是 3D 纹理", 3D) = "" {}
}
  • 变量名:_MainTex
  • 显示名称:我是 3D 纹理
  • 类型:3D
  • 默认值:空

3D 纹理主要用在查找表或者体积数据上,默认值与 2D 的不同,不管如何设置都只会显示为灰色图。

Cube(类型:立方体纹理)

示例如下:

Properties
{
        _MainTex("我是 Cube 纹理", CUBE) = "" {}
}
  • 变量名:_MainTex
  • 显示名称:我是 Cube 纹理
  • 类型:CUBE
  • 默认值:空

Cubemap 是一个由六个独立的正方形纹理组成的集合,它将多个纹理组合起来映射到一个单一纹理。

基本上说 CubeMap 包含 6 个 2D 纹理,这每个 2D 纹理是一个立方体(cube)的一个面,也就是说它是一个有贴图的立方体。

想像成一个方形盒子被我们拆开铺平的情景。

CubeMap 通常被用来作为具有反射属性物体的反射源。

通用属性标记

还有一些比较常用的属性标记,可以用于任何属性,下面来介绍下:

[Header]

Properties
{
        [Header(This is Header )]_Int("我是Int", Int) = 1
        _Float("我是Float", Range( 0 , 1)) = 1
}

在材质面板上进行标注,通常用作 分类组别 用,注意 只支持英文、数字、空格以及下划线。

[HideInInspector]

在材质面板中 隐藏此条属性,在不希望暴露某条属性时可以快速将其隐藏。