原文:Custom Nodes with CodeFunctionNode@Unity Docs
随着Unity发布了ShaderGraph,创建一个Shader比以往都要更加容易。然而无论提供多少个默认节点,都不能满足用户的自定义需求。因此,我们开发了一个自定义节点的API,可以在C#中创建新节点。或许能满足用户们刁钻的需求。
本文将介绍一种最简单的实现方法,称之为Code Function Node,接下来将展示详细细节。
让我们先创建一个C#脚本,在这个例子中,我们将脚本命名为MyCustomNode。为了使用Code Function Node API,需要引入UnityEditor.ShaderGraph并继承父类CodeFunctionNode。
1 | using UnityEngine; |
由于CodeFunctionNode仍是虚类,故接下来我们将实现其中要求我们实现的函数。
方法GetFunctionToConvert使用反射将一段方法转化为ShaderGraph可用的方法信息(MethodInfo)。
如下添加引用System.Reflection并重写GetFunctionToConvert方法,注意”MyCustomFunction”这段字符串正对应着我们要实现的Shader函数名,我们将在稍后实现。至此一个节点便完成了,同时在构造函数中设置name成员可以指定该Node在ShderGraph中显示的标题。
1 | using UnityEngine; |
接下来我们实现MyCustomFunction函数。
首先创建一个返回字符串的静态方法,在参数中我们可以定义当前Node的端口(Port)。这些端口名将直接映射到最终实现Shader中的参数名。这个例子中我们将设置两个输入的端口A和B,数据格式都是动态维度向量(Dynamic Dimension Vector),同时输出一个动态维度向量Out。这一组端口便构成了一个Node的所有节点。同时我们需要添加Slot属性以区分不同的id。
1 | static string MyCustomFunction( |
更详细的数据格式列表请查阅API文档或文末附录。
这个函数需要返回一个包含着色器程序的字符串,如HLSL语句。本例中我们将定义一个Out=A+B的简单函数,这个函数大致如下:
1 | static string MyCustomFunction( |
最后我们需要将这个节点显示再节点列表中,以供选择。这要求我们为类添加一个属性。如下添加,最后一个字符串将作为节点在节点列表中的显示名字(区别于显示在节点上方的节点标题)其余为分类文件夹。
1 | [] |
这样一来我们就创建好了一个自定义节点,可以在ShaderGraph中尽情使用了!
其他例子
除了Out = A + B,我们还可以定义很多东西。下面这个例子展示了如何在三个多维向量中选取最小值。
1 | static string Min3( |
下面这个例子是通过一个布尔值决定是否反转法向量。其中Normal端口被绑定为世界坐标法线(World Space Normal),即没有线段连入这个端口是,默认使用世界坐标法线。
1 | static string Min3( |
附录
Port Types
| Argument Type | Data Type |
|---|---|
| Boolean | Boolean |
| Vector1 | Vector1 |
| Vector2 | Vector2 |
| Vector3 | Vector3 |
| Vector4 | Vector4 |
| Color | Vector4 (with a ColorRGBA Port Binding) |
| ColorRGBA | Vector4 (with a ColorRGBA Port Binding) |
| ColorRGB | Vector3 (with a ColorRGB Port Binding) |
| Texture2D | Texture2D |
| Texture2DArray | Texture2DArray |
| Texture3D | Texture3D |
| Cubemap | Cubemap |
| SamplerState | SamplerState |
| DynamicDimensionVector | DynamicVector |
| Matrix4x4 | Matrix4 |
| Matrix3x3 | Matrix3 |
| Matrix2x2 | Matrix2 |
| DynamicDimensionMatrix | DynamicMatrix |