前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >基础渲染系列(十)——更复杂的复合材质

基础渲染系列(十)——更复杂的复合材质

作者头像
放牛的星星
发布2020-07-10 13:40:39
2.3K0
发布2020-07-10 13:40:39
举报
文章被收录于专栏:壹种念头壹种念头

本文重点:

1、烘焙自阴影到材质中 2、给表面的某些部分增加细节 3、支持更多的效果变体 4、一次性编辑多个材质

这是关于渲染的系列教程的第十部分。上一次,我们使用了多个纹理来创建复杂的材质。这次我们再增加一些复杂度,并且还支持多材质编辑。

本教程是使用Unity 5.4.3f1制作。

(复合材质往往看起来一团糟)

1、遮挡区域

虽然我们可以创建看起来很复杂的材质,但这些只是假象,三角形仍然是平坦。法线贴图可以给人深刻的印象,但这仅适用于直射光。没有自我遮挡。较高的零件应该在较低的区域上投射阴影,但现在不会发生。当法线贴图存在小孔,凹痕或裂缝时,这一点最为明显。

假设有人在向我们的电路板射击。但没有穿过电路板,留下了明显的凹痕。下面就是为此调整的法线贴图。

(凹陷电路法线图)

使用此法线贴图时,电路材质确实确实凹陷了。但是凹痕最深的部分和未凹痕的表面一样被照亮。凹痕没有任何自我遮挡的现象。结果,这些凹痕看起来并不深。

1.1 遮挡贴图

要添加自阴影,我们可以使用所谓的遮挡贴图。你可以将其视为材质的一部分,固定阴影贴图。用于凹陷电路的这种贴图,一般为灰度图像。

(遮挡贴图)

要使用此贴图,请将此贴图的texture属性添加到我们的着色器。再添加一个遮挡强度滑块属性,以便我们可以对其进行微调。

就像金属贴图一样,使着色器功能仅在设置遮挡贴图时才对其进行采样。仅将功能添加到基本通道中,因此不必担心会出现其他灯光影响。

1.2 遮挡UI

因为我们有一个自定义的着色器GUI,所以必须将新属性手动添加到着色器的UI中。因此,向MyLightingShaderGUI.DoMain添加DoOcclusion步骤。

这种新方法与DoMetallic几乎相同,DoMetallic也涉及贴图,滑块和关键字。因此,请复制该方法并进行所需的更改。尽管DoMetallic在没有贴图的情况下会显示滑块,但我们需要在此做相反的操作。另外,Unity的标准着色器使用遮挡贴图的G颜色通道,因此我们也将这样做。在工具提示中展示。

(检视器,没有和有遮挡贴图)

1.3 添加阴影

要访问包含文件中的贴图,请添加采样器和float变量。

创建一个函数以对贴图进行采样(如果存在)。如果不存在,则不应调制光,结果保持为1。

当遮挡强度为零时,贴图完全不会影响光线,因此,该函数需要返回1。当处于全强度时,结果恰好是贴图中的结果。我们可以通过基于滑块在1和贴图之间进行插值来实现。

要将阴影应用于灯光,需要将遮挡因素纳入CreateLight内部的光计算中。

(没有和有遮挡 强度为1)

1.4 方向光阴影

现在凹痕已经变深了,但总体来说并没有太明显。这是因为在此场景中,许多光线实际上是间接光线。由于我们的遮挡贴图并非特定于任何光源的,因此我们也需要将其应用于间接光源。这是通过调制漫射和镜面反射间接光来完成的。

(没有VS有 全遮挡)

这会产生更强的阴影。实际上,它们可能过于强了。由于遮挡贴图基于的是表面形状而不是特定的光,因此将其仅应用于间接光才是有意义的。来自四面八方的光会随着进入凹坑的深度而减少。但是,当灯光直接照射在其上时,凹痕应完全点亮。因此,我们删除方向光的遮挡。

(没有和有方向光遮挡)

就遮挡贴图而言,这是尽可能真实的。话虽如此,你也经常会发现游戏中遮挡贴图也应用于方向光。Unity的旧着色器也这样做。虽然这不真实,但确实可以让使美术人员更好地控制灯光。

屏幕空间环境光遮挡如何?

SSAO是一种后处理图像效果,它使用深度缓冲区动态创建整个帧的遮挡图。它用于增强场景的深度感。由于它是一种后处理效果,因此在渲染所有灯光之后将其应用于图像。这意味着阴影会同时应用于间接和直接光。结果,这种效果也不真实。

1.5 合并贴图

由于我们仅使用遮挡图的一个通道,即G通道。用于电路的金属图存储在R通道中,平滑度存储在alpha通道中。这意味着我们可以将所有三个贴图组合为一个纹理。下面是一张这样的贴图。

(在单个贴图中结合金属,遮挡和平滑度)

着色器不知道我们是否正在重复使用纹理,因此它仍将第二次对遮挡贴图进行采样。但是使用单个纹理确实会减少内存和存储需求。通过使用DXT5压缩,我们的三个512×512映射仅需要341KB。这确实意味着将金属贴图和遮挡贴图组合为单个可能会降低质量。幸运的是,这些贴图通常没有那么多的细节,也不需要非常准确。因此结果通常是可以接受的。

我们可以将其缩小为单个纹理样本吗?

是的,你必须调整着色器以从同一贴图采样所有内容。如果你正在执行此优化,则也可以摆脱多余的纹理属性。

2 细节遮罩

现在的电路材质缺乏一些细节。让我们完善这部分。下面是带细节的反照率图和法线图。

(细节反照率和法线贴图)

然后导入,并将纹理设置为淡出mipmap。分配纹理并使用全强度法线。这些细节不能太小,3 x 3的tiling效果较好。

(细节电路板)

2.1 细节遮罩

现在的细节会覆盖整个表面,但这看起来并不好。最好是细节不要覆盖金属零件。我们可以使用蒙版纹理来控制显示细节的展示。就像是二进制splat贴图一样工作,就像我们在第3部分“组合纹理”中使用的一样。区别在于,值0表示无细节信息,值1表示完整详细信息。

这是一个细节遮罩,可以防止细节出现在金属零件上。为了增加种类,它还减少甚至完全消除电路板的下部区域。而且,无论在板子上打出什么凹痕,细节都会被抹去。

(细节遮罩)

Unity的标准着色器使用细节蒙版的Alpha通道,因此我们也使用该通道。上图将所有四个颜色通道设置为相同的值。

将此贴图的属性添加到我们的着色器。

由于许多材质都没有细节蒙版,因此也要为其提供着色器功能。基础和附加pass都需要它。

添加require变量和一个函数以将掩码数据添加到我们的包含文件中。

将贴图也添加到我们的用户界面中,位于自发光贴图和颜色下方。现在,它是结合了shader关键字的单个纹理属性。

(使用细节遮罩)

2.2 反照率细节

为了掩饰细节,我们将不得不再次调整包含文件。不必总是将反照率与细节相乘,而是基于蒙版在未修改和修改后的反照率之间进行插值。就像所有其他属性一样,将反照率的检索放入其自身的函数中。

2.3 法线细节

还需要对法线向量进行相同的调整。这时,没有任何细节与未修改的朝上的切线空间法线向量相对应。因此,我们再次通过基于细节蒙版的向量及其原始值之间的插值来替换原始细节法线。

(细节遮罩)

3 更多的关键字

我们一直在使用着色器功能来启用着色器代码,该代码可以采样并在我们的光照方程中包含各种贴图。Unity的标准着色器也可以做到这一点。这就是超级着色器的想法。它可以做很多事情,但是具有多种使用风格的变体。

标准着色器还具有着色器功能,可切换法线贴图和局部贴图的使用。当指定主法线贴图或细节法线贴图时,法线贴图将启用。当设置了细节反照率或法线时,将启用细节。

将这些功能添加到我们的着色器中吧。先保持简单并独立切换每个贴图。首先,根据细节反照率贴图的存在设置一个关键字。

接下来,基于主法线图的关键字。

与细节法线贴图相似。

3.1 更多的着色器变体

为了使它正常生效,请为我们的着色器通道中的每个关键字添加一个新的着色器Feature。首先,基本pass。

然后,附加pass。

着色器变体的数量现在已经增加了很多。但是,要激活材质中的关键字,必须通过检查器更改所有相关贴图。否则,着色器GUI将无法正确设置关键字。创建新材质时这不是问题,但是在更改后需要刷新现有材质。

3.2 使用关键字

现在,我们必须更改包含文件以利用新的关键字。首先,GetAlbedo也许可以省略细节图部分。

如何测试这是否真的有效?

当你不使用反照率细节贴图时,你当然不会得到反照率细节。但这是因为实际上确实省略了代码,还是因为着色器正在采样默认纹理呢?

你可以通过两种方法来验证关键字是否按预期工作。首先,暂时将默认纹理更改为显而易见的颜色,例如细节反照率图为白色。如果在删除贴图后材质变得太亮,则表示仍包含该代码。或者,在代码中添加一个临时的#else块,这将使显而易见的变化。

接下来,我们必须处理法线贴图。在这种情况下,我们有四种可能的配置。没有法线贴图,只有主贴图,只有细节贴图,或者都没有。让我们隔离对这些贴图进行采样的代码,然后将其移至新功能。

现在重写GetTangentSpaceNormal,以便它可以有效地处理所有四种情况。由于着色器编译器的优化,我们可以通过两次定义检查来完成此操作。

那反照率图和颜色呢?

Unity的标准着色器假定始终存在一个反照率贴图,因此不为其保留关键字。由于绝大多数材质都使用反照率贴图,因此这是一个合理的假设。同样,我也不用albedo关键字。当然,你可以自由添加它。

标准着色器也始终应用反照率着色。这个假设更令人质疑,因为许多材质没有使用色调,而是使用默认的白色。可以为色调添加一个关键字,仅当色调设置为除白色以外的其他颜色时才启用它。但我不希望这样做,因为颜色的选择不像使用或不使用纹理那样是二进制的。容易出现意料之外的问题,例如未应用的动画颜色,因为它们最初是白色的。

标准着色器确实根据自发光的颜色设置其自发光关键字。颜色设置为黑色时,将其保留。然而,这也是导致许多人无法设置自发光颜色动画的原因。所以我也不这样做。

Ubershaders是个好主意。但是,在处理特定项目时,你有机会创建着色器,该着色器完全(且仅)支持所需的功能,并且关键字应尽可能少。一旦认真考虑优化着色器的时候,就可以利用它。

4 编辑多个材质

到目前为止,我们仅考虑一次编辑一个材质。但是Unity允许我们选择多种材质。如果这些材质全部使用我们的着色器,则可以使用着色器GUI一次编辑所有材质。你还将在预览面板中看到整个选择。

(预览两个选中的材质)

4.1 设置关键字太少

所以,其实可以同时编辑多个材质!但是,有一个问题。在创建使用我们的着色器的两种新材质时,你会看到。选择两个,然后为其分配法线贴图。即使两种材质现在都具有法线贴图,但只有第一种材质最终会使用它们。

(只有第一个材质有法线)

发生这种情况是因为我们的着色器GUI只设置一种材质的关键字。也就是编辑者当前打开的目标,也就是所选内容中的第一材质。

什么决定所选材质的顺序?

顺序是任意的,但是每次是一致的。因此,你不能依靠某种材质作为选择的第一材质。

我们可以通过调整选择中所有材质的关键字来解决此问题。为此,我们必须调整着色器GUI的SetKeyword方法。不必使用目标字段,我们需要遍历编辑器的目标数组中的所有材质。让我们使用一个foreach循环来执行此操作,因为它是简洁的代码,在这里我们不必担心性能。

foreach如何工作?

foreach是for循环的方便替代方法。与常规的for循环相比,它具有一些开销,因为它创建了一个临时的迭代器对象。因此,我永远不会在经常执行的应用程序代码或编辑器代码中使用它。

如果愿意,可以用常规的for循环替换它们。

请注意,上面的代码使用一个临时变量来缓存editor.targets属性。foreach循环不需要这样做,因为仅直接引用一次数组即可获得其迭代器。另外,editor.targets是一个对象数组,因此我们必须将每个项目显式转换为材质。foreach循环隐式执行此强制转换。

修改后,更改贴图或凹凸比例后,法线将显示在所有材质中。

(两个材质带有法线)

4.2 设置过多的关键字

不幸的是,我们刚刚创造了另一个问题。考虑选择两种材质。第一种材质使用法线贴图,而第二种材质则不使用。在这种情况下,UI会显示凹凸比例,因为它是基于第一种材质的。这不是问题,因为第二种材质将仅忽略凹凸比例。但是,当更改凹凸比例时,UI将更新两种材质的关键字。结果就是两种材质都设置了_NORMAL_MAP关键字。因此,第二个材质往后都启用了_NORMAL_MAP关键字,即使它不使用法线贴图也是如此!

如果仅在更改纹理属性时更新了关键字,则不会存在此问题。不幸的是,由于TexturePropertySingleLine合并了两个属性,因此我们无法使用BeginChangeCheck和EndChangeCheck方法来区分它们。以前很好,但现在不会了。

要解决此问题,我们必须先跟踪贴图的纹理引用,然后才能对其进行更改。然后,我们仅在进行更改的情况下设置关键字,这是不同的贴图。

这解决了DoNormals的问题。但这也会影响DoMetallic,DoOcclusion,DoEmission和DoSecondaryNormals。调整所有这些方法,就像我们修复DoNormals一样。现在,我们的着色器GUI正确支持多材质编辑!

下一章,介绍透明度。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-05-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 壹种念头 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、遮挡区域
    • 1.1 遮挡贴图
      • 1.2 遮挡UI
        • 1.3 添加阴影
          • 1.4 方向光阴影
            • 1.5 合并贴图
            • 2 细节遮罩
              • 2.1 细节遮罩
                • 2.2 反照率细节
                  • 2.3 法线细节
                  • 3 更多的关键字
                    • 3.1 更多的着色器变体
                      • 3.2 使用关键字
                      • 4 编辑多个材质
                        • 4.1 设置关键字太少
                          • 4.2 设置过多的关键字
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档