跳转至

汇聚与 sibling aggregator

一棵树必须描述两张图。 本页讲的是第二张图 —— 以及那条决定每个 composite 收集什么的唯一规则。

为什么有两套层级

Harmony 的 Node View 同时承载两张连接图:

层级 颜色 连接 含义
Input / Transform 🟢 绿 peg → 它的子级 "这个带动那个"
Output / Composite 🔵 蓝 comp ← 输入它的东西 "这个合成那个"

它们不是同一棵树。一个 peg 可以驱动多个互不相同的合成,而一个 composite 可以汇集任何单个 peg 都不带动的东西。

staging 树就是一棵树 —— 它只有一种父子关系。所以 OSA 把它用在绿色图上,那里缩进本身就已经是你想要的意思:子行就是子节点

这样蓝色图就没有缩进可用了。它的答案是在兄弟之间的位置

sibling aggregator

没有绿色容器的 composite,汇聚它下方的兄弟。

这就是 sibling aggregator(兄弟汇聚器)。它自己没有可以往里看的作用域,所以它顺着列表往下看

Comp-1        ← starts block 1
Peg-1         ← feeds Comp-1 … but see below: what enters is Comp-2's output
  Comp-2      ← starts an inner block; its output IS Peg-1's output
  Drawing-1   ← feeds Comp-2
  Drawing-2   ← feeds Comp-2
Drawing-3     ← feeds Comp-1
Comp-3        ← ENDS block 1, starts block 2
Drawing-4     ← feeds Comp-3
Drawing-5     ← feeds Comp-3

念出来就是:一个 comp 开启一个区块,它之后的一切都流进它,而同一层级上的下一个 comp 关闭这个区块并开启新的一个

peg 不喂给 comp —— 喂过去的是它那套层级的输出

Peg-1 是一个变换,不是一张图像。到达 Comp-1 的是 Peg-1 之下所有东西的结果,而那个结果是从 Comp-2 出来的 —— Peg-1 作用域内的那个 comp,它已经汇集了 Drawing-1Drawing-2

所以连线是 Comp-2 → Comp-1Peg-1 在绿色图上;它从不出现在蓝色图上。

Comp-2 拿掉,Peg-1 就没有 comp 替它说话 —— 这时 Drawing-1Drawing-2冒泡上来各自单独接进 Comp-1,变成两个输入而不是一个。这就是有 comp 的 peg 和没有 comp 的 peg 之间的全部差别,详见容器输出什么

而 Peg-1 里的第二个 comp 意味着有两个输出到达 Comp-1 —— 每个区块一个:

Comp-1
Peg-1              ← now hands Comp-1 TWO outputs
  Comp-2           ← block A → its output goes to Comp-1
  Drawing-1        → feeds Comp-2
  Comp-2b          ← block B: closes A, opens its own
  Drawing-2        → feeds Comp-2b
                   ← Comp-2b's output ALSO goes to Comp-1

每个在容器内结束的区块都会作为它自己的输出冒泡上来,按树的顺序。所以从 Peg-1 到达 Comp-1 的连线数量,正好等于 Peg-1 关闭的区块数量 —— 一个 comp,一根线;两个 comp,两根线;完全没有 comp,则每个 drawing 一根线。

什么会打断这条链

同一层级上的另一个 composite。 只有它会。

当遍历在同一批兄弟中遇到第二个 comp 时,它会冲刷当前区块并开启一个全新的。没有标记要设,也没有选项要勾:第二个 comp 的存在本身就是边界。

这就是为什么你可以把一个场景铺成一列扁平的兄弟,仍然从中得到几套彼此分开的合成 —— 你只需在每组该结束的地方放一个 comp 来分隔它们。

决定收子级还是收兄弟的规则

只有绿色容器才创建作用域,而绿色容器正好只有两种:PegGroup

槽位 comp 汇聚 为什么
单独的 C 下方的兄弟 除了一个汇聚点什么都不是
D-C 下方的兄弟 没有绿色容器,所以没有作用域
BD-C 下方的兄弟 backdrop 是视觉的 —— 它不拥有节点
BD-D-C 下方的兄弟 同上:backdrop 对接线毫无影响
P-CG-C 子级 绿色容器创建了一个内部作用域
P-D-CG-D-C 子级 同上
BD-P-CBD-P-G-D-C 子级 起作用的是 peg;backdrop 只是画了个框

backdrop 从不改变谁来汇聚

这一点大家最容易搞错,值得直说:BD 是视觉的BG=BD-C 汇聚兄弟的方式和裸的 C 完全一样,因为 backdrop 和 comp 之间没有绿色连接,comp 无从借它收集子级。只有 PG 才能把一个 comp 变成子级汇聚器。

带 Peg(或 Group)+ Comp 的 super node

现在来看你每天都在搭的那种情况。

一个既有绿色容器又有 comp 的槽位 —— hero=P-Chero=BD-P-G-C —— 会让这个 comp 按树的顺序汇聚它的直接子级……

……直到第一个本身就是 comp 的子级为止。 那个子级开启了一个新的 sibling-aggregator 区块,它之后的一切归那个区块。

hero=P-C            ← green scope; its comp collects the children below
├── arm=D           → feeds hero-C
├── leg=D           → feeds hero-C
├── fx=C            ← a comp among the children: block boundary
├── glow=D          → feeds fx-C
└── dust=D          → feeds fx-C

hero-C 拿到 armlegfx-C 拿到 glowdust,而继续往上走的是 fx-C 自己的输出。

这就是整套合成语言:绿色容器开启一个作用域,里面的 comp 一直收集,直到下一个 comp 叫停。

容器输出什么

这个容器 它的输出
有内部 comp 单个输出 —— 那个 comp,或它之后的最后一个效果
没有内部 comp 多输出:里面的每个 drawing 都冒泡上来

没有 comp 的 peg 不合并任何东西。它交给父级一个列表,每一项都单独接进父级的 comp。

SuperNode=P-D-C
├── Peg-1  (P only, no Comp)
│   ├── Drawing-A
│   └── Drawing-B
└── Drawing-C

Peg-1 返回 [Drawing-A, Drawing-B],所以 SuperNode-C 收到四个输入:

端口 输入
3 SuperNode 自己的 drawing
2 Drawing-A(从 Peg-1 冒泡上来)
1 Drawing-B(从 Peg-1 冒泡上来)
0 Drawing-C

在 peg 里放一个 comp,这两个就会塌缩成一个输入。这就是 Peg-1=PPeg-1=P-C 的实际差别,也通常就是一张图上连线比你预期多的原因。

端口顺序

蓝色图有方向,而且是固定的:

端口 渲染在 位于
端口 N(最高) 前面 Node View 的左侧
端口 0(最低) 后面 Node View 的右侧

所以 Node View 里最左边的元素在渲染的最上层,最右边的在最后面。在 super node 内部,槽位自己的 drawing 占据最前的端口,子级占据它下面的端口,从左到右。

这也是为什么 Wide Bus 把你树的顶端放在左边:树的顺序、端口的顺序和渲染的顺序是同一个顺序,读法也一样。

在树里读出它

你不必在脑子里模拟这一切 —— Details 列已经告诉你每一行会搭出什么,而上面那条规则告诉你它的 comp 会收集什么:

BACKGROUND      (Backdrop > Peg > Comp)     ← green scope: collects its children
  sky           (Read)                       → feeds BACKGROUND-C
  clouds        (Read)                       → feeds BACKGROUND-C
EFFECTS         (Backdrop > Peg > Comp > Effects)

如果某个 comp 收集的东西不对,只有两个问题要问:那个槽位上有绿色容器吗? 以及在同一批兄弟中,它上面还有另一个 comp 吗?