【Unity Shaders】使用CgInclude让你的Shader模块化——使用#define指令创建Shader

时间:2022-01-20 15:21:19

本系列主要参考《Unity Shaders and Effects Cookbook》一书(感谢原书作者),同时会加上一点个人理解或拓展。

这里是本书所有的插图。这里是本书所需的代码和资源(当然你也可以从官网下载)。

========================================== 分割线 ==========================================

写在前面

我们已经看到如何使用Unity内置的CgInclude文件,以及如何创建我们自己的CgInclude去保存光照模型、变量和辅助函数。在这篇中,我们关注如何更动态、有效地使用CgInclude文件,使得我们的Shader更加模块化,并且可以根据需要切换不同的状态。

因此,本篇中,我们将会修改上一节中创建的Half Lambert光照模型,为它添加一个定义(definition)。这样,如果我们的Shader中定义了Half Lambert,那光照模型将会使用Half Lambert漫反射,否则就会使用标准的NdotL光照模型。

这节代码就3行,只是个引子。

实现

我们首先再来看一下我们的CgInclude文件。我们想要让该光照模型具有两个状态:

  1. 第一个状态,是正常的NdotL(Normal*LightDir)漫反射光照模型,而第二个状态,就是一个Half Lambert光照模型。修改我们的CgInclude文件去包含下面的两行代码:
    【Unity Shaders】使用CgInclude让你的Shader模块化——使用#define指令创建Shader
  2. 然后,在我们的Shader中,更新CGPROGRAM块中的指令:
    【Unity Shaders】使用CgInclude让你的Shader模块化——使用#define指令创建Shader
  3. 保存你的Shader,返回Unity编译。这时你不会看到任何变化,这是因为我们告诉Unity,去定义一个名为HalfLambert的指令,如果它在任何已包括的文件中找到了这个定义,它就会使用第一步中的代码。
  4. 返回Shader,然后注释掉我们刚才新加的指令。保存后返回Unity查看:
    【Unity Shaders】使用CgInclude让你的Shader模块化——使用#define指令创建Shader
这时就会发现,Unity没有使用Half Lambert,而是使用了标准的NdotL光照模型。这时因为我们没有定义HalfLambert,因此Unity在编译时将会跳过那段代码。这使得我们的Shader更加灵活有效,我们可以不再编写或删除大量重复的代码。



解释



如你所见,虽然这节代码只有3行,但我们可以利用这些简单的技术来使得光照模型更加多变。通过使用#ifdef指令,我们告诉Unity去查找这个名称的定义,这里这个名字指的是HalfLambert。

使用CgInclude来编写Shader,不仅可以帮助我们节省大量的代码,还可以存储大量的光照模型。这使得我们更容易地去调用光照模型,或者使用多个状态去修改它。

这里讲到的这些技巧,其实和C++里面的相关知识很类似,而这些也是CG的知识内容。越学越感到,Unity虽然封装了很多细节,但学习原始的Shader越显得重要啊。