4

一些程序(即声音合成、程序纹理生成……)让他们的用户完全自由地通过图形编辑器以任意方式安排程序的各种功能。用户可以放置一个或多个“节点”(每个节点代表某种从一个或多个输入生成一个或多个输出的功能)并以任何所需的方式将它们修补/连接在一起以生成最终输出。

我想知道这种软件的最佳表示可能是必要的数据结构,无论是对于生成器系统本身还是对于它的图形表示。我特别困惑的是如何对节点输入和输出可能具有各种数据类型的事实进行建模,并且根据节点类型,其中只有一些可能是有效的。

那么如何建模:

  • 节点输入/输出值
  • 节点本身(继承?)及其连接
  • 生成过程,从起始节点传播到输出节点
4

2 回答 2

2

我参与过一些这样的系统。有许多不同的做事方式。但我过去做过的一种常见方法是让 Node 对象链接到其他 Node 对象。节点通过一些 IAction 接口包含一个动作对象。用户以某种方式指定在特定节点处实现 IAction 接口的具体动作对象(这通常还涉及为对象指定一些状态,例如要应用的过滤器的参数)。

然后有一个框架来初始化(编译)和执行(运行)图,并安排在输入准备好时调用 IAction 接口并将输入传递给节点,并将输出传递给下游节点。这是一个非常简单的算法:并行运行所有输入都存在的节点(从没有输入的节点开始),然后将其余节点放在等待队列中,直到它们的输入存在。

这只是如何做到这一点的一种方式;正如您所指出的,有许多变体,以及许多使用这种技术的系统。也有一些框架(如果我理解正确的话, TPL Dataflow就是其中之一)。

关于如何确保节点之间的连接保持一致的问题,在我看来,这归结为在框架做多少和节点做多少之间做出选择。在一个极端,框架可以在图“编译时”严格匹配连接类型;另一方面,框架可以将其留给节点在“运行时”进行检查。如果大多数连接只是相同的类型,例如它们都是字节流,则后者可能是合适的。

顺便说一句,在 Java 或 C#(或其他 HLL)中可能比在 C++ 中更容易,因为对接口、反射、动态加载对象等有更多支持(例如,在 C# 中,您可以轻松地为对象指定类型和从流中动态创建它,而您必须自己在 C++ 中滚动)。

于 2013-04-16T12:43:59.967 回答
1

你可能想看看观察者模式,特别是这种类型的信号/槽系统。 观察者模式_

我不久前使用 C++ 进行的一个项目使用信号/插槽来允许用户在运行时动态连接不同的音频合成模块。不过,在性能方面可能会有所取舍。

至于对不同的可能输入进行建模,您可以制作一个信号对象以包含实际数据作为 void 指针和一个字符串或枚举,指定接收类在处理过程中假定的数据类型是正确的。当您的用户最初连接这些对象时,可能会返回一种合同(“这些是此对象发送的类型”),并且可以在处理开始之前完成实际验证。

于 2013-04-16T12:20:15.510 回答