今天分享的是Pixar在Siggraph2019上关于USD的分享,整个系列包含五篇文章,这是第三篇,其他几篇可以通过下面的链接访问,PPT地址见参考文献[1]。
第一篇 【Siggraph2019】USD Introduction and Overview
第二篇 【Siggraph2019】USD Composition
整篇文章将从如下几个方面进行展开:
• Authoring API and Authoring Performance
• USD’s File Formats
• Native Scene Graph Instancing
• Value Clips
• Dynamic File Formats
首先来看下USD的Authoring部分,Authoring指的是对USD Layers(.usd文件)的写入操作。
这些写入包括Prim的创建、Attribute的创建与修改以及Composition Structure的添加等。


上面展示的是C++代码,但是使用python其实也是可以的。通过上述方式可以很方便的完成对Prim层次结构的定义。

这里展示了两个USD操作符,def(‘define’)表示创建一个prim,而over(‘override’)表示当对应的prim存在时,这些对于Attribute的修改才会生效。

创建一个带有类型的Prim可以通过上述方式完成。

Schema Class在使用的时候是不会判断有效性(即不会判断当前是否存在一个schema)的,因此在某些prims还没有依附到对应的schema之前可以用来做一些特定schema的数据Authoring工作(比如调用schema的API等)。


对属性的修正可以通过上述方式完成,USD的默认长度单位是cm,但是通过‘metersPerUnit’ metadata可以指定不同的长度单位。

与Composition Arcs相关联的API在上图中给出了,每个API都提供了一些类似于列表的操作功能(添加、删除、设置以及清除),通过这些API可以完成对Composition的Authoring工作:


每个Stage包含了很多的Layers,那么我们这里给出的Authoring是发生在哪个Layer上的呢?这个是通过什么方式指定的?
实际上Stage有一个当前的Edit Target对象(对应UsdEditTarget Class),我们可以直接编辑EditTarget来实现对不同Layer的切换。

比如上图中下面的三张小图分别对应的是(黄色箭头表示的是当前的EditTarget):
- 指定对应的Layer(第四个)
- 指定对应的Composition Arcs(第二个)
- 添加一个TimeCode偏移(?)

也可以将上述EditTarget组装到一起,比如先干啥,后干啥等。

这里给了一个EditTarget的应用案例,比如首先将EditTarget设置为Stage的session layer(默认情况下,UsdStages都有一个特有的in-memory layer,这个layer的话语权要比任何layer都要强,这是为了实现一些临时的override覆写而设计的,这些覆写不会被保存,就像是草稿本,这里的这个layer就是session layer)上,并将这个layer的Ghost Prim的visibility设置为invisible。

这里演示了如何对Variants进行Authoring,代码比较简洁,这里就不再解释了。

Edit Target在实际工作中用得非常多,而且也非常的有用,通常可以通过如下过程来实现对Edit Target的创建:
- 首先获取需要覆写的某个Prim的PcpPrimIndex,之后根据这个Index实现对composition structure的遍历
- 遍历完成后,可以得到对应的PcpNodeRefs,从这个结构我们可以构建出对应的Edit Target,从而可以实现对任意Prim的覆写。
下面是关于Edit Target的一些额外信息:
- 此外,后面还会发布一个新的高级别的USDPrimCompositionQuery接口,也可以实现对应的功能
- 如果是在项目制作中,可以为这个过程创建一个图形化的界面。

Authoring的性能表现不是特别好,对于只读操作而言,其表现经过优化后其实是不错的,而实际上我们在使用中绝大部分的工作都是读数据而非写数据。
Pixar的Presto一直在用这个东西,质量上应该是有所保障的,不过因为USD本身就是为了能够实现动态修正而设计的,因此在性能上相对于静态不变的场景表达方式有所不如也是正常的。

这里是Authoring的一些使用建议:
- 尽量避免多过的兄弟prims
- 因为每个改动,都会触发name列表的重新构建
- 添加兄弟prim的复杂度为O(n^2)
- 当prim数目超过10,000时,建议使用Grouping

这里介绍了一个延时通知的修改接口SdfChangeBlock,可以提升一点性能表现,不过相应的会有一些问题,比较适合用在bulk prim的创建上面。

这里给出了这个接口使用的一些坑或者说限制。

后面Pixar可能会考虑提供一套性能表现更好的编辑选项。

这里介绍了USD内置的几种文件格式,前面介绍过,.usda是可读版本,.usdc是二进制版本,.usd则是二者之一,使用.usd的话在两者之间切换不会破坏引用关系,这几种格式都是无损的,且支持全部的USD数据。

USDZ是压缩文件格式,这是跟Apple合作开发的用于网络传输的数据格式,这个格式能够支持包含贴图以及其他资源的USD文件。

这里介绍了.usda文件的一些特性,说到.usda文件的内容是在打开的时候完全加载到内存的。


.usdc文件的特性:
- 除了人类不可直接读写之外,没有任何缺点
- 编解码快速、无损压缩
- 在打开的时候,只会加载prim & property hierarchy信息
- attributes以及time samples数据是在需要的时候才会加载
- 数组数据在内存中是采用memory-mapped data存储的,因此在传输的时候基本上是零拷贝(相当于C++的指针或者引用)
- 只在Save的时候才会触发复制
- 数据是按照TimeCode升序组织的

插件文件格式中,提供了对Alembic文件的原生支持,此外还可以自定义自己的文件格式。

USD还有一些其他进阶特性:
- 提供了对Scene Graph Instancing的原生支持
- 支持Value的Clip操作(将某个数据块分拆成一个个小碎片(clip)放到多个clip文件中)
- 支持动态文件格式

USD的Prim本身就是为了Instancing而设计的,Usd会在运行时决定哪个'instanceable' prim是可以被共享的。

这里有一些使用规则:
- 具有相等Key的Prims只会被Composed一次
- 会共享一个生成出来的Master prim层级
- 支持对instance root prim的局部覆写
- 不支持对descendant prim的局部覆写
- 提供了两个有用的API:UsdPrim API: IsInstance() and GetMaster()
- 支持嵌套instancing

上面给出了Instancing的两种做法,分别对应效率优先与易用优先。

易用优先是通过Instance Proxy来完成的,Instance Proxy是不断往前追溯直到对应的Master的只读UsdPrim,在Instance Proxy的机制下,用户将完全感知不到Instancing的存在,相当于直接访问到了原始的Prim数据。

Master是运行时动态创建的,因此不可以手动修改;通过一个未显示声明的Master可以实现显示的Instancing,实际上有很多种方法可以通过composition实现对Scene Description的共享(比如Inherit)。

使用Value Clips可以实现对来自于不同的clip layer的animation的组装、调序以及重新调整时间等功能,这在很多工作流上都十分有用。

这里是具体使用案例,比如三个不同的clip,按照顺序组合到一起,就形成了一个组合版的clip,其中的数据也按照前一个clip的最后一个数据顺延,而通过active就可以指明三个clip的起始位置坐标(5, 1)表示的是clip_1是从第5个timesamples开始计算的。

所谓的动态文件格式指的是:
- 根据场景的参数化输入,生成Scene Description
- 能够获得后面塞入到文件格式插件所需要的composed “argument”数值
- 目前仅限于自定义的plugin-registered的metadata
- 当数值发生变化时,文件格式会自动触发重新生成content的机制
- 在使用的时候需要注意,这个文件格式对于其他需要读权限的用户必须要是线程安全的。


网友评论