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

386 阅读5分钟

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

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

前言

在前面的章节中我们有讨论过每个 Shader 中都可以有多个 SubShader ,并且在渲染时会找到第一个合适的并执行。那么除了在 SubShader 中定义的 Pass 不同以外,我们还能如何定义 SubShader 呢,我们知道在 SubShader 和 Pass 中都有 Tags 可选参数组,Tags 的作用是告诉引擎如何去渲染我们的对象,语法格式如下:

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

通过 Tags{} 来表示我们添加了一系列的 参数标识,大括号内可以添加多组 Tag(所以才叫 Tags 嘛),名称(TagName)和值(Value)是成对成对出现的,并且全部用字符串表示。


SubShader Tags

SubShader 中的 Tags 必须放置于 SubShader 中的 Tags 内,具体参数有以下这些:

Queue

渲染队列,指定对象什么时候渲染,每个队列其实都是利用一个整数进行索引的。

有以下取值:

1. Background

值为 1000,此队列的对象最先进行渲染。

2. Geometry

Queue 的默认值,值为 2000,通常用于 不透明对象,比如场景中的物件与角色等。

3. AlphaTest

值为 2450,要么 完全透明 要么 完全不透明,多用于利用贴图来实现边缘透明的效果,也就是美术常说的透贴。

4. Transparent

值为 3000,常用于 半透明对象,渲染时 从后往前 进行渲染,建议需要混合的对象放入此队列。

5. Overlay

值为 4000,此渲染队列用于 叠加 效果。最后渲染的东西应该放在这里(例如镜头光晕等)。

写法示例:

Tags{ "Queue" = "Geometry" }

那是不是只有以上这些固定化的渲染队列了呢?

当然不是,我们还有一种方式可以 自定义渲染队列

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

如上所示,可以通过在值后加数字的形式来进行重新指定渲染队列。

渲染队列直接影响性能中的重复绘制,合理的队列可极大的提升渲染效率。在 Unity 中,渲染队列小于 2500 的对象都被认为是 不透明的物体,(如 BackgroundGeometryAlphaTest),这些物体是 从前往后 绘制的,而使用其他的队列(如 TransparentOverlay)的物体则是 从后往前 绘制的。这意味着,我们需要尽可能地把物体的队列设置为不透明物体的渲染队列,而尽量避免重复绘制。

RenderType

自带的值有以下这些:

  • Opaque
  • Transparent
  • TransparentCutout
  • Background
  • Overlay
  • TreeOpaque
  • TreeTransparentCutout
  • TreeBillboard
  • Grass
  • GrassBillboard

这些名称实际上只是一种内部的约定,用来区别这个 Shader 要渲染的对象是属于什么类别的,你可以想像成是我们把各种不同的物体进行分类一样。当然你也 可以改成自定义的名称,这样并不会影响到 Shader 的效果。

那既然没有什么效果影响,那 RenderType 又有什么作用呢?

它的作用是可以利用 Camera.SetReplacementShader 来更改最终的渲染效果。先说下这条语句的语法:

camera.SetReplacementShader (EffectShader, Tag);

这是 Unity 的脚本 API,需要在 C# 脚本中进行调用。
其中 EffectShader 是我们需要渲染的 Shader,Tag 是用来筛选渲染对象用的。

具体按以下规则执行:

  1. 使用 SetReplacementShader("shaderA",""),这里 Tag 为空,表示全部物体 Shader 都替换成 shaderA 进行渲染。
  2. SetReplacementShader("shaderA","RenderType"),由于这里 TagRenderType, 所以先查看场景中的 shader 中 是否有 RenderType 参数,如果有,再看 RenderType 中的值 是否与 shaderA 中的 RenderType 值相等,相等则使用 shaderA 渲染,否则就不渲染(Game 视图什么也没有)。
  3. 关于 Tag 参数并不局限于 RenderType ,我们同样可以使用 SetReplacementShader("shaderA","IgnoreProjector") 或是其他任何参数如: SetReplacementShader("shaderA","ABC") 等。

用法示例

我们建个脚本,添加如下代码,实现 替换材质开关 功能。

其中 taecg/Overdraw(此 Shader 实现的是类似于 Overdraw 的效果)这个 Shader 中的 Tag 如下:

而我们的物体(这头狼),我们给它 的Shader 中 Tag 如下:

然后,我们同时在场景中添加几个其它的默认几何体(它们都是默认的 StandardShader)。

结果如下:

v2-fd7264ba733bc6514645825fe79d1582_b.gif

首先在场景中查找所有的对象,筛选出有 RenderType 标签的对象,此时三个物体都有,然后进一步和 taecg/Overdraw 这个 Shader 进行对比,发现只有狼的值与此相同,所以只渲染狼,并且是以taecg/Overdraw 这个 Shader 来进行渲染。

DisableBatching tag

有的时候,我们会利用 Shader 在模型的顶点本地坐标下做一些位移动画,当此模型有 批处理 时会出现效果不正确的情况,这是因为批处理会将所有几何转换为 世界坐标空间,因此 “本地坐标空间” 将丢失。

"DisableBatching" = "True"

这时我们就可以利用此 Tag 在 Shader 中指定是否受批处理影响,有以下 3 个值可选:

  1. False(默认值), 不禁用批处理 zhihu.gif

  2. True,始终禁用此着色器的批处理 zhihu.gif

  3. LODFading,仅当 LOD 激活时禁用批处理

ForceNoShadowCasting tag

是否强制关闭投射阴影,值可为:

  • True,强制关闭投射阴影
  • False(默认值),不关闭投射阴影
"ForceNoShadowCasting" = "True"

IgnoreProjector tag

是否忽略 Projector 投影器的影响,Projector 是 Unity 中内置的组件,可用于实现 贴花 等功能。

  • True,使对象不受 Projector 影响

  • False(默认值),使对象受 Projector 影响

CanUseSpriteAtlas tag

是否可用于精灵打包图集,意思就是如果某个图片精灵被设置为打包进图集中,那么当此精灵所指定 Shader 中设置为

"CanUseSpriteAtlas" = "False"

时就会使其 无法工作,相应的 UI 上也会有警告提示。

PreviewType tag

此 Tag 决定了材质面板的 预览窗口如何显示模型,默认显示的是球体,当我们把值定义为以下两种情况时会进行相应的变化。此功能仅仅影响的只是材质面板的预览,对 Shader 本身没有什么影响。

  1. Plane 平面预览
  2. Skybox 天空盒预览