Dimensions(维度)与 Key Domain(打 key 作用域)¶
这是整个工具赖以建立的核心理念,一页就能讲完。
一个姿势(pose)存储在一个地址上。一个 dimension 就是这个地址的一个分量。
一个 layer 的 dimension 是如何相加的¶
一个 pose layer 会跨越三样东西打 key:
它自己的 grid + 承载它的 control + 它的 knob
每一样都贡献自己的轴,它们合成为一个单一的地址:
| 这个 layer | 总和 | 标签 |
|---|---|---|
| 一个 3 × 3 的 grid,全局,没有 knob | 2 | 2D |
| 同一个 layer,放在 Head 这个 control 内部 | 2 + 2 | 4D |
| ……再跨越一个 13 状态的 phoneme knob 打 key | 2 + 2 + 1 | 5D |
| ……如果那个 knob 换成一个 3 × 3 的 grid | 2 + 2 + 2 | 6D |
六维是一个 pose layer 的上限——它自己的 grid(最多 2)、它的 control(最多 2)、以及一个 knob(最多 2)——当链条完全全局时上限是四维:没有 control 参与就没有承载它的 grid,一个全局 layer 最多是它自己的 2 加上一个 2D knob。ORC 在每一处可以挂接轴的地方都执行这个预算——Knob 选择器会隐藏超出预算的候选,一次拖放会带着原因拒绝,而当结果会超过 4D 时 Make Global 也会拒绝。一个 layer 只能挂一个 knob,正是这一点封顶了这条链。
Outliner 会在每一行显示这个数字,鼠标悬停时会把总和拆解出来:
5D —— 这个 layer 跨越打 key 的轴总数(自身的 grid + 承载它的父级 + 每一个额外的 knob)。
有两种情况不贡献任何维度:
- 一个 control 的 face——它本身就是 control 的 grid,所以它不会再跨越自身重复打 key。
- 一个全局(global)的 layer——它上方什么都没有。一个全局的 slider 读作
1D。
driver 和 look-at 能到达八维¶
一个 driver 或 look-at 字段会在同一套堆叠之上,再叠加它自己这个 widget 的 dimension:
widget 本身 (0–2) + control (0–2) + pose layer (0–2) + 它的 knob (0–2)
一个二维的 pad driver,如果同时跨越一个 control 加上一个 pose layer 加上该 layer 的二维 knob 打 key,就是 8D。没有任何东西会阻止你这么做;也没有任何东西会为此警告你。
| Widget | 自身的 dimension 数 |
|---|---|
| Checkbox | 0 |
| Slider、Combo Slider | 1 |
| 二维 pad(Continuous Grid) | 2 |
| look-at 摇杆 | 2 |
Key domain(打 key 作用域)¶
一个 key domain 是某个东西被打 key 所跨越的位置集合。
pose layer 的 key domain 来自它在树中所处的位置——这就是为什么拖动一个 layer 会改变它的行为。driver 和 look-at 则是显式地选择自己的 key domain,用的是同样的四个选项、同样的措辞:
| Domain | 每一个……对应一个值 | 什么时候用 |
|---|---|---|
| Global | 一切。它根本不被打 key。 | 这个值从不依赖姿势。 |
| Control | control 的 snap | 它随转身角度而变化——透视、透视缩短。 |
| Pose Layer | pose layer 的 snap,在每一个 control 姿势上都相同 | 它属于表情本身,而不是角度。 |
| Control + Pose Layer | 两者的乘积 | 它确实同时随两者变化。 |
Pose Layer 是全局 layer 唯一能用的 domain
一个挂在 Globals 下的 layer 没有 control 这个维度,所以 Control 和 Control + Pose Layer 都没有东西可供打 key。ORC 会把这些选项灰掉,并说明原因。
look-at 的两种模式各自从同样的四个选项里选择自己的 domain——参见 Look-At。
某个 domain 不可用时¶
ORC 从不隐藏一个它无法提供的选项。它会把它灰掉,并在 tooltip 里给出解决办法:
| 被灰掉的选项 | 原因 |
|---|---|
Control、Control + Pose Layer |
"先选一个 control——Globals 没有 control grid 可供打 key。" |
Pose Layer |
"这个持有者没有可供打 key 的 pose layer。" |
Control + Pose Layer |
"这个 control 下没有 pose layer——一个 Globals 的 layer 不在它下面,所以无法构成乘积。请选择拥有该 layer 的那个 control,或者只跨越 layer 单独打 key。" |
| checkbox 类型 driver 上除 Global 以外的一切 | "Checkbox driver 只能是 Global——选另一种 widget 类型才能限定到某个 Control / Pose Layer。" |
如果某个 domain 暂时不可用——比如你还没选 control——ORC 会记住你的选择,并在这个 dimension 重新存在的那一刻恢复它,而不是悄悄把你降级到 Global。
Snap 地址¶
每一个 snap 都有一个名字,它是由上面这些 domain 从左到右拼出来的:先是 control 的位置,然后是 layer 的位置,然后是 knob 的位置。
你会在日志、preset 预览,以及 Unroll 表格中看到这些地址:
每个 dimension 对应一段,从左到右——先是 control 的 snap,然后是 layer 的:
| 地址 | 读作 |
|---|---|
R5C10 |
第 5 行、第 10 列的一个 control face |
UR0C4:P1LR1C2:P1RR2C0 |
control snap R0C4 · 第 1 页左侧 grid 的 R1C2 · 它右侧 grid 的 R2C0 |
UR1C2:P2LR0C1 |
control snap R1C2 · 第 2 页的左侧 grid |
UBR1C2:P1LR0C0 |
背面(back) face 上的 control snap R1C2 · 第 1 页 grid 的 R0C0 |
G:P1LR1C2 |
一个全局(global) layer——完全没有 control 这一段 |
UR1C2:K1R0C3 |
一个 knob 自己的姿势——所属 control 在 R1C2,knob 在 R0C3 |
UR0C4:P1LR1C2:W3 |
第 1 页的姿势,位于该 layer 的 knob 的第 3 个位置 |
各个前缀:
U |
承载它的 control 的 snap(它的 unit)——无论那个 control 叫什么名字。一个 Torso control 同样用 U 打 key。UB 是它的背面(back)。 |
G |
完全没有 control——一个以无头方式打 key 的全局 layer。 |
P1L / P1R,P2L…… |
第 1 页的左右两个 grid,第 2 页的,以此类推——每一页用同一套编号方案。 |
K1 |
一个正在为自己创作姿势的 knob——K 加上它的轴槽位编号,再加上它的 snap。 |
:W3 |
该 layer 的 knob 的第 3 个位置。 |
control 的名字从不出现在地址里——每个 layer 只属于一个 control,所以 U 永远表示"我所属的那个 control",不需要编号。
为什么这个字母是 U 而不是 C
U 代表 control 的 unit——这是 ORC 内部对 control 的称呼。最直观的字母本该是 control 的 C,但 C 已经被占用了:它是每个 snap 里的列(column)字母。CR0C4 会让两个不同含义的 C 只隔五个字符,而一个地址存在的意义就是能一眼读懂——所以 control 用 U 打 key。
为什么二维 knob 的 :W 是一个扁平的数字
一个二维 knob 用一个单一的索引来表示它的位置——在一个 3 × 3 的 knob 上 :W7 表示第 2 行第 1 列(行 × 列数 + 列)——而不是一个 R2C1 形式的 snap。这是故意的:合成后的 rig 会把每一个 knob 位置以 Toon Boom 自己的布局存成一个堆叠状态文件(stack/0.tbState、1.tbState……),而这个扁平索引正是那个文件的名字。地址与它所指向的东西保持一致。
你永远不需要自己手写地址。但当一条消息、一个 preset 预览,或 Unroll 表格提到某个地址时,这就是读懂它的方法。
Interpolation(插值)¶
在各个 snap 之间,ORC 会做混合。开启 Interpolation 时,姿势是周围四个 snap 的加权混合,权重总和始终为 1。关闭它,则由最近的 snap 直接胜出。
它在成品 rig 里是一个运行时开关,让动画师可以在平滑的 control 和硬切步进的 control 之间选择。一个没有打 key 的 snap 不是一个空洞——它是一个从邻居混合而来的位置。
它也是唯一一个全局性的开关。其他每一个内置开关都是针对它所作用的那个对象存在的,而且只在那个对象存在时才存在:Mirror 需要一对配对的 pose layer,Mirror All 需要不止一对,Front ↔ Back 需要一个同时拥有两个 face 的 control——每个双面 control 都创作自己的翻转。Interpolation 提出的问题——在 snap 之间混合,还是直接切换?——只针对整个 rig 被问一次;如果每个 layer 或每个 control 都有一个 interpolation 复选框,只会徒增控件而不会增加任何一个决策。所以一个复选框统管一切,而只有在一个 rig 完全没有连续可混合的东西——全是开关式 driver,没有任何 grid——时,它才会保持静默。
Dimension 的代价¶
每增加一个轴,都会成倍增加可寻址的姿势数量、Compose 所需的时间,以及它占用的内存。
| Rig | 可寻址的姿势数 |
|---|---|
| 一个 3 × 3 的 layer,全局 | 9 |
| ……放在一个 5 × 3 的 control 内 | 135 |
| ……再加一个 13 状态的 knob | 1,755 |
| ……再加 Front 和 Back 两个 face | 3,510 |
你并不需要把它们全部打上 key。但你添加的每一个 dimension,都是你在承诺要做的创作工作,而随着数量攀升,ORC 会告诉你:
1024 个 snap —— 手动创作这个规模是一项大工程,并且捕捉/合成时间会随每一个被打 key 的 snap 增长。
它会警告,但不会阻止。
唯一真正会阻止 Compose 的事¶
维度数量本身从不会阻止一次 compose。只有一种结构性冲突会:
两个额外的 knob 写入同一个节点和同一个通道时,无法相加。 发生这种情况时,出问题的那一行 Outliner 会整行——名字、标签和图标——亮成红色,并且在你解决之前 Compose 会拒绝执行。
除此之外的一切都只是警告。