Shader Graph着色器视图自定义节点API:Code Function Node

随着在

Unity 2018.1

中加入Shader Graph着色器视图,如今在Unity中创建自定义着色器变得更为简单。然而,尽管我们默认提供了不少各式各样的节点Node,这些节点仍不可能满足开发者的所有需求。因此我们开发了一个自定义节点API,提供开发者在使用C#创建新节点时使用。这个API还能帮助开发者根据需求扩展Shader Graph着色器视图。

明天晚上8点,新一期的Unity技术直播课程将详解使用Shader Graph着色器视图快速创建炫酷特效。今天我们将先介绍在Unity 2018.1 beta中一个扩展Shader Graph着色器视图的方法-使用Code Function Node,它是创建自定义节点最简单的方法。下面将介绍如何使用该方法创建一个新节点。

使用Code Function Node创建新节点

首先新创建一个C#脚本,命名为MyCustomNode。为了使用Code Function Node API,我们需要在代码中包含或是添加该类到命名空间UnityEditor.ShaderGraph,然后从基类CodeFunctionNode进行继承。

usingUnityEngine;

usingUnityEditor.ShaderGraph;

publicclassMyCustomNode:CodeFunctionNode

{

}

你可能已经注意到,MyCustomNode被高亮为一个错误。如果我们把光标移到该错误信息上,会看到提示我们需要实现一个名为GetFunctionToConvert的继承成员。基类CodeFunctionNode会告诉Shader Graph着色器视图如何处理这个节点,但我们仍需要告诉它结果函数应该是什么。

GetFunctionToConvert方法使用Reflection反射来将一个方法转换为MethodInfo的实例,从而使CodeFunctionNode能在Shader Graph着色器视图中转换和使用。并且让我们能更为直观地写出着色器函数。

如下面代码所示,添加命名空间System.Reflection和重写函数GetFunctionToConvert。要注意MyCustomFunction,它将作为函数名写入着色器中。你还能根据自己正在编写的函数为其命名,只要不以数字开头即可。在本示例中我们将使用MyCustomFunction这个名字。

usingUnityEngine;

usingUnityEditor.ShaderGraph;

usingSystem.Reflection;

publicclassMyCustomNode:CodeFunctionNode

{

protectedoverrideMethodInfoGetFunctionToConvert()

{

returnGetType().GetMethod("MyCustomFunction",

BindingFlags.Static|BindingFlags.NonPublic);

}

}

现在我们脚本中的错误都已经解决,我们可以开始编写节点的功能了!

首先我们应进行命名,在类中加入一个没有参数的公有构造函数。在该函数中,将变量名设为包含节点标题的字符串。当该节点在图中出现时,它将显示在节点的标题栏上。本示例中我们将节点命名为My Custom Node。

usingUnityEngine;

usingUnityEditor.ShaderGraph;

usingSystem.Reflection;

publicclassMyCustomNode:CodeFunctionNode

{

publicMyCustomNode()

{

name="My Custom Node";

}

protectedoverrideMethodInfoGetFunctionToConvert()

{

returnGetType().GetMethod("MyCustomFunction",

BindingFlags.Static|BindingFlags.NonPublic);

}

}

接下来,我们将定义节点的函数。如果你熟悉反射,你会注意到方法GetFunctionToConvert会尝试访问这个类中的方法MyCustomFunction。MyCustomFunction将定义着色器函数。

现在让我们创建一个静态方法,返回类型为string,它的名字与方法GetFunctionToConvert中的字符串一致。本示例中,这个名字为MyCustomFunction。在该方法的参数中,我们可以定义节点将拥有哪些端口。这些参数将直接映射到最后着色器函数的参数中。我们需要添加Shader Graph着色器视图中支持类型的参数并对其设定Slot属性。

现在我们要加入二个类型为DynamicDimensionVector的参数,分别命名为A和B,以及一个out参数,类型为DynamicDimensionVector,命名为Out。然后我们为这些参数加入默认Slot属性。每个Slot属性需要一个特别的索引和绑定,我们把它们设为None。

staticstringMyCustomFunction(

[Slot(,Binding.None)]DynamicDimensionVectorA,

[Slot(1,Binding.None)]DynamicDimensionVectorB,

[Slot(2,Binding.None)]outDynamicDimensionVectorOut)

{

}

在下面方法中,我们会在返回字符串中定义着色器函数的内容。这些内容包含着色器函数和HLSL代码。本示例中定义为Out = A + B;。我们创建好的方法如下所示:

staticstringMyCustomFunction(

[Slot(,Binding.None)]DynamicDimensionVectorA,

[Slot(1,Binding.None)]DynamicDimensionVectorB,

[Slot(2,Binding.None)]outDynamicDimensionVectorOut)

{

return

@"

{

Out = A + B;

}

";

}

}

这就是Shader Graph着色器视图中加法节点的C#代码。

在完成可用节点前,我们还要做一件事:指定它在Create Node Menu创建节点菜单的出现位置。这一步通过在类上添加Title属性来完成。这会定义一个string数组,它会描述节点在菜单层级列表中出现的位置。这个数组中最后一个字符串定义了节点在Create Node Menu中的名字。

本示例中,我们会把节点称为My Custom Node,并把它放在Custom文件夹中。

[Title("Custom","My Custom Node")]

publicclassMyCustomNode:CodeFunctionNode

{

现在我们的节点就完成了!如果我们返回Unity,编译脚本然后打开Shader Graph着色器视图,我们会看到在Create Node Menu中出现了新节点。

然后在Shader Graph着色器视图中创建节点实例。你会看到它拥有和我们在MyCustomFunction类中所定义的相同名字和类型。

现在你便可以通过使用不同的接口类型和绑定来创建各种节点。这个方法返回的字符串可以包含任意在Unity常规着色器中有效的HLSL代码。下面的节点会返回三个输入值中的最小值。

staticstringMin3(

[Slot(,Binding.None)]DynamicDimensionVectorA,

[Slot(1,Binding.None)]DynamicDimensionVectorB,

[Slot(2,Binding.None)]DynamicDimensionVectorC,

[Slot(3,Binding.None)]outDynamicDimensionVectorOut)

{

return

@"

{

Out = min(min(A, B), C);

}

";

}

}

下面这个节点能根据输入的布尔值反转法线。要注意在本示例中,接口Normal是如何拥有WorldSpaceNormal的绑定的。当没有任何边线(Edge)连接这个接口时,它会默认使用网格的世界空间法线向量。

注意:当使用一个具体输出类型,例如Vector 3时,我们必须在返回着色器函数前对其进行定义。

staticstringFlipNormal(

[Slot(,Binding.WorldSpaceNormal)]Vector3Normal,

[Slot(1,Binding.None)]BooleanPredicate,

[Slot(2,Binding.None)]outVector3Out)

{

Out=Vector3.zero;

return

@"

{

Out = Predicate == 1 ? -1 * Normal : Normal;;

}

";

}

}

参考文档

Reflection

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/reflection

CodeFunctionNode API

https://github.com/Unity-Technologies/ShaderGraph/wiki/CodeFunctionNode

Port Binding

https://github.com/Unity-Technologies/ShaderGraph/wiki/Port-Bindings

小结

现在你已经准备好在Shader Graph着色器视图中使用Code Function Node来创建节点了吗?当然这只是开始。要想自定义该系统,你还可以在Shader Graph着色器视图中去做更多的事情。

明天晚上8点,Unity技术经理成亮将为开发者们带来更多Shader Graph着色器视图的功能讲解,对着色器开发感兴趣的开发或美术人员一定不能错过,带上你的问题和讲师互动吧!

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180410A0O24200?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券