如何在 Nuke 中的 Ops 之间交换自定义数据?

How to exchange custom data between Ops in Nuke?

此问题是针对使用 C++ 和 NDK of Nuke 的开发人员提出的。

Context: 假设一个自定义 Op 实现了 DD::Image::NoIopDD::Image::Executable。节点迭代一系列帧以提取信息 每个帧,存储在自定义数据结构中。一个自定义旋钮,它是一个成员 上述 Op 的变量(但在 UI 中不可见),处理加载和保存 数据结构的(序列化)。

现在我想在 Ops 之间交换那个数据结构。

到目前为止,我有以下想法:

  1. 表达式链接

    旋钮可以使用表达式链接共享信息(矩阵等)。 此功能也可以用于自定义数据吗?

  2. 图像数据的序列化

    自定义数据将被序列化并写入(新)通道。一个 处理树下方的节点可以抓住它并反序列化 再次。当然,通道不能在序列化之间改变 和反序列化或者其他......我知道这是一个黑客,但是,嘿,任何端口 在暴风雨中!

  3. GeoOp + 渲染器

    在自定义数据完全基于点的情况下(不幸的是, 它不是在我的情况下),我可以把上面的节点变成一个 3D 节点并通过 将数据指向其他 3D 节点。在某些时候需要渲染节点 回到二维。

我正朝着正确的方向前进?如果不是,什么是明智的 使该数据结构可用于其他节点的方法,这些节点依赖于 里面包含的信息?

此问题已在 Nuke-dev mailing list 上得到回答:

如果您知道您的 Op 输入的实际 class,则可以将 输入 class 类型并直接访问它。一个简单的例子可以是 下面这个片段:

//! @file DownstreamOp.cpp

#include "UpstreamOp.h" // The Op that contains your custom data.

// ...

UpstreamOp * upstreamOp = dynamic_cast< UpstreamOp * >( input( 0 ) );

if ( upstreamOp )
{
    YourCustomData * data = yourOp->getData();
    // ...
}

// ...

更新

参考我通过电子邮件收到的问题进行更新:

I am trying to do this exact same thing, pass custom data from one Iop plugin to another. But these two plugins are defined in different dso/dll files. How did you get this to work ?

简答:

将您的 Ops 编译成一个共享对象。

长答案:

  • UpstreamOp.cpp
  • DownstreamOp.cpp

定义依赖操作。

在第一次尝试中,我仅使用 UpstreamOp.cpp 编译了第一个插件, 照常。对于第二个插件,我编译了 DownstreamOp.cppUpstreamOp.cpp 进入该插件。

奇怪的是它起作用了(在 Linux 上;没有测试 Windows)。

但是,通过覆盖

bool Op::test_input( int input, Op * op ) const;

东西会坏的。仍然使用上述插件创建和保存一个 Comp 作品。但是再次加载相同的 Comp 会破坏节点图中的连接 在 UpstreamOpDownstreamOp 之间并且无法再连接 他们又来了。

我的假设是:因为两个插件都包含 UpstreamOp 它的符号 如果节点使用 UpstreamOp 的实例,则取决于插件的加载顺序 来自第一个或第二个插件。所以,如果 UpstreamOp 来自第一个插件 使用则 Op::test_input() 中的任何 dynamic_cast 都会失败,并且两个 Op 不能 被连接了。

令人惊讶的是,Nuke 甚至不厌其烦地从上面开始 配置,因为它可能对来自插件的符号相当挑剔,例如,如果它们 缺失。

无论如何,为了解决这个问题,我做了以下事情:

  1. 将两个 Ops 编译成一个共享对象,例如myplugins.so,以及
  2. 添加TCL脚本或Python脚本(init.py/menu.py)指示Nuke如何加载 Ops 正确。

可以在 dev guide 和说明中找到 TCL 脚本的示例 因为你的 menu.py 可能是这样的

menu = nuke.menu( 'Nodes' ).addMenu( 'my-plugins' )
menu.addCommand('UpstreamOp', lambda: nuke.createNode('UpstreamOp'))
menu.addCommand('DownstreamOp', lambda: nuke.createNode('DownstreamOp'))
nuke.load('myplugins')

到目前为止,这对我们来说是可靠的(在 Linux 和 Windows 上,还没有测试 Mac)。