前言
ShaderGraph在Unity2019脱离了Preview,目前功能已经非常丰富了,预设结点数量够多,也提供了自定结点的接口,配合URP后可大大简化工作流,提高效率。
注:Unity在2019.3中已将LWRP升级并重命名为为Universal Render Pipeline,简称URP。见官方的说明,在未来有URP将会逐渐代替传统管线成为默认管线。
以后或许就是图程搭建渲染框架,编写好自定义Master Node,TA通过Shader Graph实现具体的功能了。
自定义Node可以通过官方的接口实现,也很简单。但显然在实际项目中我们还会有自定义Master Node的需要。对此,Unity提供了一种方法,即创建Unlit Graph,用CustomFunction Node实现自定义的光照,然后保存为Sub Graph使用。在这一篇博客中讲解了这种方法:
Custom lighting in shader graphblogs.unity3d.com但是我觉得这种方法还是不够好,如果说要以ShaderGraph为中心开展工作,我们还需要能够指定更多的东西,比如Cull,ZWrite,ZTest。而这些选项在默认提供的Master Node下都是没有的。
而Unity确实也没有提供任何自定MasterNode的手段,好在ShaderGraph和URP的代码都是开源的,因此我们就来修改一下源代码让其支持更多设置。如图:
本文以实现Lambert+Blinn Phong光照为例,但限于代码全放出来篇幅会非常长,因此只会列举一小部分核心代码,其他部分参考核心代码的实现集可。
准备
修改尽量遵守以下原则:添加新的代码文件,而不修改已有的代码(或者尽量很少很简单),这样还能继续从版本更新中收益。
首先我习惯先将ShaderGraph和URP及其依赖的Core这三个包从项目的“Library/PackageCache"中移动到”Package”中,这样可以在工程中查看和引用这部分的代码。
新建类/接口需要按照源代码中同样的命名空间命名,而且需要放在源代码对应的目录下,因为源代码中类的访问级别都是缺省的internal级别。
开始前还需要先理清一下代码的结构,ShaderGraph这个包中只定义了Node的UI等。而在URP这个包中才实际上定义了将Master Node转化为代码的行为。因此我们先自定UI,再自定生成逻辑。
自定Node UI
在ShaderGraph包中,新建一个接口:
interface IMyLightingSubShader : ISubShader{}
接着新建一个类:
[Serializable,Title("Custom", "Master", "MyLighting")]
class MyLightingMasterNode : MasterNode<IMyLightingSubShader>, IMayRequirePosition,IMayRequireNormal,IMayRequireTangent{}
Title属性指定创建时在菜单中的标题和级别,至于后面的3个接口,在该Node需要这几个属性的时候加上,我们实现Lambert光照,肯定是需要考虑Normal和Tangent的。这3个接口的实现,可以和UnlitMasterNode.cs中一致,这里不放代码。
接下来,我们要创建在MasterNode UI上显示的属性的ID和名称:
public const string AlbedoSlotName = "Albedo";
public const string PositionName = "Vertex Position";
public const int AlbedoSlotId = 0;
public const int PositionSlotId = 1;
每个属性的ID需要不同,名字则是在UI上显示的内容。接着在Updat