这篇文章是在学习USD的过程中龟速写成的,目的是将USD的核心设计、相关概念的说明、以及配套API整理出来,为后续进行的USD开发工作提供中文资料支持。

实际上也只有充分理解了USD设计中的每一个知识点,才能更好掌握这个软件。

目前这个词汇表还会持续更新,这篇博客会非常枯燥,涉及词汇将暂时以重要程度为准排序,在该表大致成型后再考虑对词汇进行分类。

对原文有兴趣的请参考:https://graphics.pixar.com/usd/docs/USD-Glossary.html


USD introduces quite a few terms and concepts, some of which, unavoidably, already have different meanings in other contexts, so it can be quite daunting to make sense of all of our documentation and code until you have become fully indoctrinated.  This glossary attempts to define and explain all the major concepts and behaviors referred to in other parts of the USD documentation.

USD介绍了相当多的术语和概念,不可避免地,其中有些词汇在其他语境中已经有了不同的含义,所以除非你已经完整的被USD灌输了一遍,否则要弄明白USD的文档和代码是非常艰巨的。这个词汇表尝试定义和解释所有的主要概念和软件行为,这些概念和行为也会被USD文档的其他部分引用参考。

词汇表


Layer

A Layer is the atomic persistent container of scene description for USD.  A layer contains zero or more PrimSpecs, that in turn describe Propertyand Metadatavalues.  Each layer possesses an identifier that can be used to contruct references to the layer from other layers.  Although it may be possible to someday remove this restriction, layers must currently correspond to files on a filesystem accessible via POSIX filesystem interfaces.

SdfLayerprovides both the "document model" for layers, and the interface by which USD authors to and extracts data from layers.  The SdfLayer interface serves data according to the USD prim/property/metadata data model, but the actual encoding of data in the backing file is quite flexible, thanks to the SdfFileFormatplugin interface.  By implementing a sub-class of SdfFileFormat and associating it with a unique file extension for USD's consumption, we can enable direct USD referencing of layers expressed as files of any format whose encoding can reasonably be translated into USD.  This is not only how USD supports direct consumption of Alembic (.abc) files, but also how USD's native ascii and crate binary representations are provisioned.

Data authored to layers by applications or scripts will remain in memory until the layer is Save()'d.  If a program is writing more data than fits in the program's memory allotment, we suggest 1) using USD's native binary crate format (which is the default file format for files created with the ".usd" file extension), and 2) calling layer.Save() periodically: doing so will flush all of the heavy property-value data from memory into the file, while leaving the file open and available for continued writing of data.  Only the crate binary format possesses this "flushability" property; USD's ascii representation can only be written out sequentially beginning-to-end, and cannot be digested lazily, therefore it cannot be authored incrementally and must always keep all of its data in-memory; other formats do not allow incremental saving because they must translate USD's encoding into their own format that does not itself allow incremental saving, like the Alembic FileFormatPlugin

Although layers exist first and foremost to define the persistent storage representation of USD data, one can also create temporary, "in-memory" layers for lightweight (in that there is no filesystem access required) USD data storage, via UsdStage::CreateInMemory().

层是USD中容器,具有原子粒度、永久的特性。一个层可以不包含或包含多个PrimSpecs,相应地描述PropertyMetadata的值。每个层都拥有一个标识符用于创建来自其他层的引用。虽然以后可能移除这个限制,但现在层必须与文件系统中的文件对应,确保POSIX文件系统的接口能够访问它。
SdfLayer为图层提供了“文档模型”,以及USD开发者提供的从图层提取数据的接口。 SdfLayer接口按照USD prim / property / metadata数据模型提供数据,但在支持的文件中对数据实际的编码非常灵活,因为使用了SdfFileFormat插件接口。通过实现SdfFileFormat的子类并将它与USD使用的唯一的文件扩展名相关联,我们可以把任意格式的文件作为层引入到USD中,其编码也可以被合理地转换进USD。这不仅仅是USD如何支持直接使用Alembic(.abc)文件的方式,而且还是USD的的原生纯文本文件和二进制文件被规定的表示方式。


Crate File Format

The crate file format is USD's own binary file format, whose file extension is ".usdc", and which is losslessly, bidirectionally convertible to the ".usda" ascii format.  The ".usd" file format is special, as files with that extension can be either crate or ascii files; this facilitates debugging as crate files can be converted to ascii in-place for rapid iterative hand-editing without needing to change any referencing layers.  The primary differences between ascii and crate files (other than the obvious human readability aspect) are that 1) ascii files must be read in their entirety, parsed, and stored in-memory as soon as they are opened, whereas crate files read in only a small index of the file's contents when they are opened, deferring access to big data until a client requests it specifically, 2) except for very small files (under a few hundred kilobytes), crate files will be much more compact than ascii files.

Crate was designed for low-latency and high-performance lazy queries, and we believe it to be the best file format choice for storing scene description consumed by USD.  Some of its features include:

  • Aggressive, multi-level data deduplication yields small file sizes 
  • Lockless data extraction for high-bandwidth multi-threaded reading
  • Access to files either by mmap() or pread(), trading VM pressure for file descriptor consumption and system call overhead. By default crate uses mmap(), but the choice is configurable at runtime.
  • Low latency in "cold file-system cache" network access, as all data needed to open a crate file for USD's use is compacted into a contiguous footer section. 
  • Editing crate files does not copy all data to a new file. Instead, it appends. Disused values consume disk space, so repeated editing may produce files larger than ideal. Use usdcat to rewrite files in their most compact form.

You can convert between file formats using usdcat.

crate file format(可以译作封装文件格式,在这里暂译作二进制文件格式)是USD独有的二进制文件格式,它的文件扩展名是“.usdc”,它支持与“.usda”这种ascii(纯文本)文件格式之间进行无损的、互相转换。“.usd”文件格式是特殊的,作为文件既可以是二进制的也可以是纯文本的;这样做有利于调试,因为二进制文件可以转换为纯文本文件就地进行快速迭代手动编辑,而无需更改任何参考图层。二进制文件与纯文本文件的主要不同是:

1.纯文本文件必须完整的读取或解析,在打开他们的时候就会全部存入内存,而二进制文件在打开的时候只会读取文件内容中的一个小索引,大数据的访问会被延迟进行,直到客户端明确请求了,大数据的访问才会开始。

2.除了非常小的文件(100kb以下),二进制文件比纯文本文件更紧凑。

二进制文件为低延迟和高性能的lazy查询方式而设计,我们相信它会是存储场景描述的最佳的文件格式选择,它有以下特点:

  • 极力地、多级地数据重复删除会产生较小的文件尺寸。
  • 为了高带宽、多线程的读取提供了无锁的数据提取。
  • 通过mmap()或pread()访问文件,用文件描述符的消耗和系统调用的开销转移成虚拟内存的压力。默认情况下二进制文件使用mmap(),但这是可以实时修改的。(VM指代linux中的虚拟内存,USD原生基于linux,这也是官方强调USD在linux之外系统中尚不完善的原因)
  • ”冷文件系统缓存“中低延迟的网络访问,需要打开的二进制文件的数据,都被压缩进连续的底部扇区。
  • 编辑二进制文件不需要拷贝所有的数据到新文件中,相应的,原基础上添加就行。不用的数据会消耗硬盘空间,所以重复的编辑会产生比想象中要大的文件,使用usdcat可以将文件以紧凑的方式再写入一次。

你可以查看这篇文章:convert between file formats using usdcat


Asset

Asset is a fairly common organizational concept in content-producing pipelines.  In the most generic terms in USD, an asset is something that can be identified and located (via asset resolution) with a string identifier.  To facilitate operations such as asset dependency analysis, USD defines a specialized string type, asset , so that all metadata and attributes that refer to assets can be quickly and robustly identified.  In content pipelines, assets are sometimes a single file (e.g. a UV texture), or a collection of files anchored by a single file that in turn references others.  A non-defining, but important quality of assets is that they are generally published and version-controlled.  As an aid to asset management and analysis of composed scenes, USD provides an AssetInfo schema.  The ascii USD format uses a special syntax for asset-valued strings to make them easily differentiable from ordinary strings, using the "@" symbol instead of quotes to delimit their values. See AssetInfo for an example.

在内容生产流程中,资产是一个十分普遍的组织概念。在大部分USD的通用术语中,资产就是通过字符串标识符能被确认、能被定位的东西。为了方便诸如资产依赖关系分析的操作,USD定义了一个专用的字符串类型: asset ,这样所有引用资产的元数据和属性就能被快速稳定的识别。在内容流程中,资产是单一文件的东西,或者被一个文件(该文件内部引用了一组文件)绑定的一组文件,资产的一个未定义,但重要的特点是他们能被广泛地发布或控制版本。作为资产管理和分析组装完成的场景的辅助手段,USD提供了AssetInfo模式,ascii编码的USD格式使用了特殊的语法使得资产数值的字符串与普通的字符串区分开来,使用“@”符号而不是使用引号来分隔它们的数值。


AssetInfo

AssetInfo is a metadata dictionary that can be applied to any UsdPrim or UsdProperty to convey asset-identification-and-management-related information.  Typically a UsdStage pulls in many assets through composition arcs.  When interacting with prims and properties on the stage, however, the presence and location of the arcs and the identity of the assets they target is, by design, fairly deeply hidden as an implementation detail.  We do provide low-level tools for examining the arc-by-arc index for each prim, but it can be difficult to reconstruct intent and asset identity from the arc structure alone. AssetInfo provides a mechanism for identifying and locating assets that survives composition (and even stage flattening) to allow clients to discover the namespace location at which an asset is introduced, and generally how to construct a reference to the asset.

assetInfo authored in USD files is advisory data one supplies for client applications to use. It is not consulted or consumed by the USD core in any way during Stage loading/composition.

The AssetInfo dictionary can contain any fields a client or pipeline finds useful, but promotes four core fields, which each have direct API:

  • identifier -  typeName asset  - provides the asset identifier one would use to target the asset with a composition arc.
  • name - typeName string  - provides the name of the asset as it would be identified, for example, in an asset database query.
  • payloadAssetDependencies - typeName asset[] - provides what can be a substantial optimization for dynamic asset dependency analysis.  If your asset build/publish process can pre-compute, at publish-time, the external asset dependencies contained inside the asset's payload(s), then shot/render-time dependency analysis (for asset isolation) need not load the payload. 
  • version - typeName string  provides the version of the asset that was/would-be targeted. In some pipelines, it may make sense to inject an asset's revision control version into the published asset itself.  In other pipelines, version is tracked in an external database, so the version assetInfo must be added in the referencing context when we add a reference to an asset.

A continuation of the example above that illustrates assemblies:

AssetInfo on a published assembly asset
def Xform "Forest_set" (
assetInfo = {
asset identifier = @Forest_set/usd/Forest_set.usd@
string name = "Forest_set"
}
kind = "assembly"
)
{
# Possibly deep namespace hierarchy of prims, with references to other assets
}

AssetInfo(资产信息)是一个元数据字典,可以被应用到任何UsdPrimUsdProperty以传递资产识别和关联管理的信息。通常情况下UsdStage通过合成器把许多资产拉进来。然而在stage中当合成器与prim和property交互的时候,合成器的存在和位置以及合成器指向的资产的身份,作为实现细节都被设计成完全深层次的隐藏了。我们提供了底层工具为每个prim逐个检查合成器的索引,但仅通过合成器来重建含义以及资产标识会很困难。AssetInfo提供了识别并定位合成器中的资产的机制,以允许客户端在资产被引进的时候发现它的命名空间位置,以及一般如何构建资产的引用的方式。

USD文件中创建的资产信息是给客户端应用程序作为参考的数据。在Stage载入或组装期间,USD核心不会查询和使用资产信息。

资产信息字典可以包含任意客户端或者流程中找到的有用的任何字段,但特别的提供了四个核心字段,核心字段会有直接的API:

  • identifier 类型名资产 - 提供资产标识符,用于通过合成器指向资产。
  • name - 类型名字符串 - 当被验证的时候提供资产的名称,举个栗子:在查询资产数据库的时候。
  • payloadAssetDependencies - 类型名资产数组 - 为动态资产依赖关系的分析提供实际的优化。在发布的时候,被包含在资产的负载中的外部资产依赖,如果在你的资产构建或发布的过程能被提前计算,那么之后预览或渲染时候阶段中的依赖关系分析过程就不需要加载负载了。
  • version - 类型名字符串 - 提供了被指向的资产的版本,在一些流程中,把资产的修订控制版本添加到发布的资产中是有意义的。在其他的流程中,版本可以在外部的数据库中被跟踪,这样在我们引用一个资产的时候,必须把关于版本的资产信息添加到引用环境中。

下面是一个关于说明组装过程的例子:见原文。


Asset Resolution

Asset resolution is the process by which an asset identifier is translated into the location of a consumable resource.  We use the general term "resource", though in reality parts of USD currently assume resolved assets are files.  USD provides a plugin point for asset resolution, the ArResolver interface, which clients can implement to resolve assets discovered in a USD scene, using whatever logic and external inputs they require.  Because USD itself always calls into the ArResolver plugin to resolve an identifier before consuming it, the plugin provides an opportunity for clients to fetch resources and make them into files for USD's consumption, so that they can work around the assumption of resource-as-file until such time as we may be able to remove it.

If a USD-using site provides no asset resolver plugin, we fall back to a default resolver that operates off of a search-path to locate assets referenced via relative paths like the one in the example for AssetInfo.

资产解析是把资产标识符转换成可用资源的地址的过程。我们使用通用术语“resource”。我们使用通用词汇“resource”,即使实际上部分USD会假定处理的资产是文件。USD为资产解析提供了一个插件对接点,称为ArResolver接口,客户端可以使用任意逻辑和外部输入来实现这些接口,来处理在USD场景中发现的资产。 因为USD本身会一直在使用识别符之前调用ArResolver插件来解析标识符。在我们能移除这个特性之前,插件给客户端提供了一个机会来获取资源和使用资源,以便它们能工作在资源即文件的假定上。

如果使用USD的地点没有提供资产解析插件,我们会返回到默认的解析器,在一个搜索路径中定位通过相对路径引用进来的资产,比如AssetInfo的例子。


Composition Arcs

Composition arcs are the "operators" that allow USD to create rich compositions of many layers contain mixes of "base" scene description and overrides.  The five kinds of arcs are subLayers, inherits, variantSets, referencespayloads, and specializes.  We refer to these operators as arcs because each one targets either a layer, a prim, or a combination of layer and prim, and when diagramming a prim's index to understand how a scene or value is composed, the composition operators represent the directional arcs that combine layers and primSpecs into an ordered graph that we traverse when performing value resolution

Except for payloads and subLayers, all composition arcs are list editable, which means that each layer in a layerStack can sparsely add, remove, reset, or reorder targets, which allows us to non-destructively edit the composition structure of a scene as it evolves or passes through multiple stages of a pipeline.  Following is an example of list-edited references.  The resolved value of references on </MyPrim> that will be consumed during composition  of superLayer.usd is a two-element list: [ @file1.usd@, @file3.usd@ ]

Contents of file "base.usd"
#usda 1.0

def "MyPrim" (
references = [ @file1.usd@, @file2.usd@ ]
)
{
}
Contents of file "superLayer.usd"
#usda 1.0
(
subLayers = @./base.usd@
) # Removes reference to file2.usd, while adding a reference to file3.usd at the end of the list
over "MyPrim" (
delete references = [ @file2.usd@ ]
add references = [ @file3.usd@ ]
)
{
}

Composition arcs(暂译作“合成器”)允许USD将包含基础场景描述及覆盖方法的多个层联合起来,以创建多种组合。有这样五类运算符:subLayersinheritsvariantSetsreferencespayloadsspecializes。我们之所以称这些运算符为“arcs”是因为每个运算符都会指向一个层、一个prim,或者层与prim的组合,当我们画一个prim的索引的图标来理解场景或数值是如何合并起来的时候,合并运算符会体现为一个有向弧,它来把层和primSpecs合并到到一个有序的拓扑图中,当我们做数值解析的时候会遍历这个拓扑图。

除了负载和子层,所有的合成器都可以以列表的形式编辑,这就意味着每个layerStack中的层可以被稀疏地添加、移除、重置、或重新排序,这允许我们在制作进行的时候,或者在穿过流程中多个stage的时候非破坏性地编辑场景的合并结构。下面是一个列表化地编辑引用的例子,在</MyPrim>中的references的数值是一个双元素的列表[ @file1.usd@, @file3.usd@ ],它会用到superLayer.usd的合并步骤中。


References

After SubLayers, References are the next most-basic and most-important composition arc.  Because a PrimSpeccan apply an entire listof References, References can be used to achieve a similar kind of layering of data, when one knows exactly which prims need to be layered (and with some differences in how the participating opinions will be resolved).  

But the primary use for References is to compose smaller units of scene description into larger aggregates, building up a namespace that includes the "encapsulated" result of composing the scene description targeted by a reference. Following is a simple example of referencing, with overrides.

We start with a trivial model asset, "Marble".  Note that, for brevity, we are eliding some of the key data usually found in published assets (such as AssetInfo, shading of any kind, Inherits, a Payload, detailed model substructure).

SubLayers之后,Reference就是下一个最基础的也是最重要的合成器。因为一个PrimSpec可以应用到一整个引用的列表上,所以当一个Reference确切的知道哪些prim需要被划分为层的时候,Reference也可以用于实现类似的数据分层。

但Reference的主要用途是把更小的场景描述单元合并到一个更大的集体中,构成一个命名空间,包含reference指向的场景描述合并后的封装结果。下面是一个简单的带有override概念的renference案例。

我们以一个小的模型资产开始,资产名为Marble。注意,简洁起见,我们现在编辑一些在发布的资产中找到的关键数据。

Marble.usd, defines a single, green marble
Marble.usd定义了一个唯一的绿色弹珠
#usda 1.0
(
defaultPrim = "Marble"
) def Xform "Marble" (
kind = "component"
)
{
def Sphere "marble_geom"
{
color3f[] primvars:displayColor = [ (0, 1, 0) ]
}
}

Now we want to create a collection of marbles, by referencing the Marble asset multiple times, and overriding some of the referenced properties to make each instance unique.

现在我们通过多次引用弹珠资产的方式,创建一系列弹珠,覆盖一些引用的特性,以使每个实例唯一。

MarbleCollection.usd, an assembly of referenced Marble assets
MarbleCollection.usd,一个引用弹珠资产的组装文件
#usda 1.0

def Xform "MarbleCollection" (
kind = "assembly"
)
{
def "Marble_Green" (
references = @Marble.usd@
)
{
double3 xformOp:translate = (-10, 0, 0)
uniform token[] xformOpOrder = [ "xformOp:translate" ]
} def "Marble_Red" (
references = @Marble.usd@
)
{
double3 xformOp:translate = (5, 0, 0)
uniform token[] xformOpOrder = [ "xformOp:translate" ] over "marble_geom"
{
color3f[] primvars:displayColor = [ (1, 0, 0) ]
}
}
}

To understand the results, we'll examine the result of flattening a Stage opened for MarbleCollection.usd, which provides us with the same namespace and resolved property values that the originating Stage would, with all of the composiiton arcs "baked out".

为理解结果,我们测试了展开MarbleCollection.usd的stage的的结果,所有的合成器都会被烘焙,这个结果展示给我们与原来stage相同的命名空间和相同的解析完毕的特性数值。

FlattenedMarbleCollection.usd demonstrates how references combine namespaces
#usda 1.0

def Xform "MarbleCollection" (
kind = "assembly"
)
{
def Xform "Marble_Green" (
kind = "component"
)
{
double3 xformOp:translate = (-10, 0, 0)
uniform token[] xformOpOrder = [ "xformOp:translate" ] def Sphere "marble_geom"
{
color3f[] primvars:displayColor = [ (0, 1, 0) ]
}
} def Xform "Marble_Red" (
kind = "component"
)
{
double3 xformOp:translate = (5, 0, 0)
uniform token[] xformOpOrder = [ "xformOp:translate" ] def Sphere "marble_geom"
{
color3f[] primvars:displayColor = [ (1, 0, 0) ]
}
}
}

Things to note:

  • In the composed namespace, the prim name "Marble" is gone, since the references allowed us to perform a prim name-change on the prim targeted by the reference.  This is a key feature of references, since without it, we would be unable to reference the same asset more than once within any given prim scoping, because sibling prims must be uniquely named to form a proper namespace.
  • Even though the asset prim named </Marble/marble_geom> shows up twice in the flattened scene, which indicates that there were indeed two distinct prims on the Stage, when we opened a stage for the original MarbleCollection.usd, the file Marble.usd was only opened once and shared by both references.  For deeper sharing of referenced assets, in which the prims themselves are also shared, see Instancing.
  • References can apply a Layer Offset to offset and scale the time-varying data contained in the referenced layer(s).
  • References can target any prim in a LayerStack, excepting ancestors of the prim containing the reference, if the reference is an internal reference targeting the same LayerStack in which the reference is authored.  When targeting sub-root prims, however, there is the potential for surprising behavior unless you are aware of and understand the ramifications.  One such ramification is that if the targeted sub-root prim has an ancestor prim that contains a VariantSet, the referencer will have no ability to express a selection for that VariantSet.  For a more complete discussion of the ramifications of referencing sub-root prims, see the UsdReferences class documentation.

See List Editing for the rules by which referenences can be combined within a LayerStack

注意事项:

  • 在组装后的命名空间中,prim的名称“Marble”已经消失,因为引用允许我们在引用的目标对象上修改prim的名称。 这是引用的一个关键特征,因为没有它,我们将无法在任意prim的作用域中多次引用相同的资产,因为同级prim必须命名唯一才能形成一个合适的命名空间。
  • 即使名为</Marble/marble_geom>的资产prim在展开的场景文件中出现了两次,这表示Stage中确实上有两个不同的prim,当我们打开原始MarbleCollection.usd的stage时,Marble.usd只会被打开一次,然后被两个reference共享使用。为了更深入的使用引用资产的共享特性,prim自身也是可以共享的。
  • Reference可以添加一个Layer Offset来偏移或缩放被引用的层中随时间变化的数据。
  • 如果引用的reference是创建在同一个LayerStack中的内部reference,那么除了reference中prim的祖先,Reference可以指向LayerStack中的任意prim。然而当指向次级路径中的prim的时候,除非你知道并明白后果,否则会产生惊人的行为。其中一个后果就是被指定的次级路径的prim有一个包含VariantSet的祖先,引用不能表示VariantSet的内容。关于引用次级路径中prim的后果的更多的讨论,可以看UsdReferences class documentation

LayerStack中组合reference的规则,请看List Editing


Relationship

A Relationship is a "namespace pointer" that is robust in the face of composition arcs, which means that when you ask USD for a relationship's targets, USD will perform all the necessary namespace-manipulations required to translate the authored target value into the scene-level namespace.  Relationships are used throughout the USD schemas; perhaps most visibly in the UsdShadeMaterial schema's binding of gprims to their associated Materials. Relationships can have multiple targets, as, for instance, a UsdGeomCollectionAPI's relationship targets all of the objects that belong to the named collection; therefore, relationships are List Edited.  Following is an example that deomstrates how a relationship's targets must be remapped to provide useful pointers.

Let's enhance the asset example from the References entry to have a shading Material and binding:

Marble.usd, with a bound Material
#usda 1.0
(
defaultPrim = "Marble"
) def Xform "Marble" (
kind = "component"
)
{
def Sphere "marble_geom"
{
rel material:binding = </Marble/GlassMaterial>
color3f[] primvars:displayColor = [ (0, 1, 0) ]
} def Material "GlassMaterial"
{
# Interface inputs, shading networks, etc.
}
}

Now, because each marble in the MarbleCollection.usd scene has its own copy of the "GlassMaterial" prim, we expect that when we:

Resolving referenced relationships
stage = Usd.Stage.Open("MarbleCollection.usd")
greenMarbleGeom = stage.GetPrimAtPath("/Marble_Collection/Marble_Green/marble_geom")
print UsdShade.Material.GetBindingRel(greenMarbleGeom).GetTargets()

we will get: </MarbleCollection/Marble_Green/GlassMaterial>  as the result, even though that was not the authored value in Marble.usd.

Relationship(关系)是一个类似“命名空间指针“的概念,在合成器中是稳定不变的。这意味着当你向USD询问relationship的目标的时候,USD会执行所有必需的命名空间操作,把创建的目标值转换成层级式的场景命名空间。Relationship通过USD模式来使用,可能最明显的例子就是UsdShadeMaterial模式把gprims绑定到相关材质上。Relationship可以有多个目标,举个例子,UsdGeomCollectionAPI的relationship指向所有的、属于有名称的集合的对象;因此,relationship是可以列表式的编辑方式。下面是一个例子,展示怎样必须映射relationship的目标来提供有用的指针。

让我们给References中资产示例添加prim,使其具有着色材质和绑定:代码见原文。

现在因为在MarbleCollection.usd中的每一个Marble层都有自己的一份GlassMaterial prim拷贝,我们希望我们能:解析引用的关系。

通过原文中的代码示例我们会获得</MarbleCollection/Marble_Green/GlassMaterial>对象,即使那不是在Marble.usd中创建的。


Value Resolution

Value Resolution is the algorithm by which final values for properties or metadata are "composed" from all of the various PropertySpecs or PrimSpecs that contain data for the property or metadatum.  Even though value resolution is the act of composing potentially many pieces of data together to produce a single value, we distinguish value resolution from composition because understanding the differences between the two aids in effective construction and use of USD:

  • Composition is cached, value resolution is not. The "indexing" performed by the composition algorithm when a Stage is opened, prims are loaded, or new scene description is authored, is cached at the prim-level for fast access.  The USD core does not, however, pre-compute or cache any per-composed-property information, which is a principal design decision aimed at keeping latency low for random-access to composed data, and keeping the minimal memory footprint for USD low.  Instead, for attribute value resolution, the USD core provides opt-in facilities such as UsdAttributeQuery and UsdResolveInfo, objects a client can construct and retain themselves that cache information that can make repeated value queries faster.
  • Composition is internally multi-threaded, value resolution is meant to be client multi-threaded.  Composition of a large stage can be a big computation, and USD strives to effectively, internally multi-thread the computation; therefore clients should realize they are unlikely to gain performance from opening multiple stages simultaneously in different threads.  Value resolution, however, is a much more lightweight process (moreso for attributes than relationships), and USD's primary guidance for clients wishing to maximize USD's performance on multi-core systems is to perform as much simultaneous value resolution and data extraction as possible; USD's design was guided by this access pattern, and we continue to work on eliminating remaining impediments to efficient multithreaded value resolution.
  • Composition rules vary by composition arc, value resolution rules vary by metadatum.  The composition algorithm is the process of interpreting a collection of composition arcs into an "index" of data-containing sites for each composed prim.  Value resolution simply consumes the ordered (strong-to-weak) list of contributing sites, and is otherwise insensitive to the particular set of composition arcs that produced that list; but how the data in those sites is combined depends on the particular metadatum being resolved. 

Resolving Metadata: The basic rule for the metadata value resolution provided by UsdObject::GetMetadata() is: strongest opinion wins. Certain metadata such as prim specifier, attribute typeName, and several others have special resolution rules; the only one we will discuss here is dictionary-valued metadata, because it is user-facing, as, for example, the customData dictionary authorable on any prim or property.  Dictionaries are resolved element-wise, so that customData["keyOne"] authored on a referencing prim will not block, but rather compose into a single dictionary with customData["keyTwo"] on the referenced prim.

Resolving Relationships: Because relationship targets are list edited, we must, in general, combine all of the opinions about the relationship's targets, not just the strongest.  The rules for how the opinions combine (in weak-to-strong order) are contained inside SdfListOp::ApplyOperations().

Resolving Attributes: Value resolution for attributes, as performed by UsdAttribute::Get(), is unique in three ways:

    1. Time Offsets.  UsdAttribute::Get() is a function of time, so all queries except those evaluated at UsdTimeCode::Default() are affected by time-scaling operaters such as Layer Offsets.
    2. Interpolation.  If the requested time ordinate falls between two samples, and the stage is configured for linear interpolation (which it is by default), then we willattempt to apply linear interpolation of the bracketing timeSamples, before falling back to holding the earlier of the two timeSamples.
    3. Three value sources for each site.  For each site in a prim's Index that may affect a metadatum or relationship, there is just a single place to look for a value - if none is found, we move on to the next site looking for values.  For attributes, however, we must examine three possible sources for a value for each site, before moving on to the next site in strong-to-weak order:

      1. Value Clips
        that are anchored at the site or an ancestor site in namespace.  If no
        clips are found, or if clips do not provide a value for the attribute,
        then...

      2. TimeSamples authored directly at the site.  If there are no TimeSamples, then...

      3. Default Value authored directly at the site

Value Resolution(数值解析)是获得properties(特性)或metadata(元数据)的最终数值的算法,最终数值是从所有各种各样的包含特性及元数据的PropertySpecsPrimSpecs合并而来。即使数值解析是将潜在的许多数据片段组合到一起生成一个单一数值的行为,我们还是要将数据解析与composition(组装)区分开来,因为理解两者的不同会帮助我们高效的创建和使用USD。

  • Composition是会被缓存的,Value Resolution不会。当打开Stage时、当载入prim时、或者当编写了新的场景描述时,被组装算法执行的“索引”会在prim级别缓存以加快访问速度。USD核心不会提前计算或缓存任何的组装的特性信息,这是一个主要的设计决策旨在保持低延迟地随机访问组装数据,保持USD
    low使用最小的内存空间。相反的,对于属性的数值解析来讲,USD核心提供了可选的工具比如UsdAttributeQueryUsdResolveInfo,对象客户端可以构造并保留自己的缓存信息,使重复的查询更快。
  • Composition是内部多线程,Value Resolution意味着客户端多线程。组装大stage会是一个大计算,USD力求有效地内部地多线程的计算,这个过程得到了充分的优化,因此客户端应该明白他们不太可能通过在不同线程中同时打开多个stage来获得更好的表现。然而,数值解析则是一个更加轻量的过程(对比关系,对于属性来讲更是如此),数值解析过程对多核心的使用不会很充分,所以计算机性能会有余量,对于想要在多核系统最大化USD表现的客户来讲,USD的主要建议是尽可能的同时进行数值计算和数据提取;USD的设计由这个访问模式所指导,我们会继续消除遗留障碍以提高多线程数值解析效率。
  • Composition规则根据合成器而变化,Value Resolution规则根据元数据而变化。组装算法是把一系列合成器分析成包含数据的索引的过程。数值解析只是消耗存放有用地址的有序列表,对产生列表的特定的合成器集合也是不敏感的;但地址中数据如何联系起来是基于待解析的特定的元数据。

Resolving Metadata:UsdObject::GetMetadata()提供的元数据数值解析的基本规则是:最强opinion优先。某些元数据比如prim分类符,属性类型名称,和好几个其他的有着特殊的解析规则;这里我们唯一会讨论的是字典型元数据,因为它是面向用户的,举个栗子,任意prim和property上都能创建的自定义数据型字典。字典会被逐元素的解析,所以在引用prim上的创建customData["keyOne"]不会被阻止,而是会在引用的prim上把custom["keyTwo"]添加进唯一字典。

Resolving Relationships:因为关系对象是以列表形式编辑的,一般来讲,我们必须把关系对象的opinion合并起来,而不只是最强的opinion。合并opinion的规则(从弱至强排序)被包含在SdfListOp::ApplyOperations()中了。

Resolving Attributes:属性的数值解析由UsdAttribute::Get()用以下三种方式执行:

  1. Time Offsets。UsdAttribute::Get()是时间方法,所以除了在UsdTimeCode::Default()求值的默认值,所有的请求都会被时间尺度的操作影响,比如Layer Offsets
  2. Interpolation。如果请求时间的坐标落在了两个采样之间,stage是被设置为线性插值的(这是默认的),在回落到保留早期两个时间采样之前,我们尝试对包围时间采样进行线性插值。
  3. Three value sources for each site。每一个prim索引中的每个地址都可能影响到元数据和关系,只有唯一的位置来查找数值,如果找不到这个位置,我们会去下一个地址查找数值。对于属性,我们必须在按照强弱顺序移动到下一个地址之前检测三个可能的来源:
    1. 数值片段被固定在命名空间中的地址或原型地址中。如果没有找到片段,或者如果片段没有为属性提供数值,那么查看下一个
    2. 时间采样直接固定在地址上,如果没有时间采样,那么查看下一个
    3. 默认数值直接固定在地址上。

Stage

A stage is the USD abstraction for a scenegraph derived from a root USD file, and all of the referenced/layered files it composes.  A stage always presents the composed view of the scene description that backs it.   The UsdStage class embodies a Stage, and caches in memory just enough information about the composed namespace and backing files so that we can rapidly traverse the stage and perform efficient data queries

场景图概念由USD的根文件及组装它的引用文件/分层文件派生而来,Stage就是场景图在USD中的抽象。stage一直表示组装好的场景描述的视图。Stage概念在USD源码中是由UsdStage class表现的,UsdStage class会将组合的命名空间和支持的文件缓存到内存中,以便我们能快速的遍历stage、高效的运行数据查询操作(data queries)。


Prim

A Prim is the primary container object in USD: prims can contain (and order) other prims, creating a "namespace hierarchy" on a Stage, and prims can also contain (and order) properties that hold meaningful data.  Prims, along with their associated, computed indices, are the only persistent scenegraph objects that a Stage retains in memory, and the API for interacting with prims is provided by the UsdPrimclass.  Prims always possess a resolved Specifier that determines the prim's generic role on a stage, and a prim may possess a schematypeName that dictates what kind of data the prim contains.  Prims also provide the granularity at which we apply scene-level instancingload/unload behavior, and deactivation.  

在USD中Prim(译作图元,在场景中一般以物体的方式存在) 是主要的容器对象:prim能包含和排列其他的prim,能在Stage中创建命名空间层级树,prim还能包含和排列存储有用数据的属性。在USD中,prim和与之相关的计算好的索引,是Stage保存在内存中的唯一的、永久的场景图对象,而与prim交互的API则由UsdPrim类提供。Prims会一直拥有一个Specifier(分类符),该分类符决定prim在Stage中的属性角色,prim可能会拥有一个schema类型名来规定prim应该装载什么样的数据。在我们实例化场景层次、装载卸载行为属性、去活某些对象的时候,prim会提供相应粒度的支持。


PrimSpec

Each composed Primon a Stageis the result of potentially many PrimSpecs each contributing their own scene description to a composite result.  A PrimSpec can be thought of as an "uncomposed prim in a layer".  Similarly to a composed prim, a PrimSpec is a container for propertydata and nested PrimSpecs.  Importantly, composition arcs can only be applied on PrimSpecs, and those arcs that specify targets are targeting other PrimSpecs.

每个stage中组装好的图元都是潜在的许多图元分类符向混合结果贡献自己场景描述的结果。一个图元分类符也可以被认为是“layer中未组装的图元”。与组装好的图元相似的是,图元分类符是一个包含property数据和嵌套图元分类符的容器。重要的是,合成器只能包含图元分类符,或包含指向其他图元分类符的对象的合成器。


PrimStack

A PrimStack is a list of PrimSpecs that contribute opinions for a composed prim's metadata. This information is condensed from the prim's index, and made available through UsdPrim::GetPrimStack().

一个图元栈(PrimStack)是图元分类符的列表,向一个由其组成的图元的元数据贡献opinions,这个信息是由图元的索引组成,通过UsdPrim::GetPrimStack()获得。


Specifier

Every PrimSpec possesses a specifier, which conveys the author's (authoring tool's) intent for how the PrimSpec should be consumed and interpreted in a composed scene.  There are three possible values for a prim's specifier in USD, defined by SdfSpecifier

  • def - a concrete, defined prim
  • over - a speculative override
  • class - prims from which other prims inherit

A prim's resolved specifier on a UsdStage determines which kinds of traversals (as defined by "prim flags") will visit the prim.  The most common, default traversals, which are meant to be used for rendering and other common scenegraph processing, will visit only definednon-abstract prims.

每个图元分类符都拥有一个分类符,来说明在组合的场景中应该怎样使用和解释图元分类符。在USD中图元的分类符会有三个可能的值,由SdfSpecifier定义:

  • def     - 一个明确定义好的图元
  • over   - 一个试探性的重写
  • class  - 供其他图元继承的图元

在UsdStage中一个图元的解析完毕的分类符决定了哪类遍历器会访问当前图元。最常见的情况是,默认的非抽象的图元会由渲染和处理其他场景图的默认遍历器访问。


Attribute

Attributes are the most common type of property authored in most USD scenes.  An attribute can take on exactly one of the legal attribute typeNames USD provides, and can take on both a default value and a value each at any number of  timeSamples.  Resolving an attribute at any given timeCode will yield either a single value or no value.  Attributes resolve according to "strongest wins" rules, so all values for any given attribute will be fetched from the strongest PrimSpec that provides either a default value or timeSamples.  Note that this simple rule is somewhat more complicated in the presence of authored clips.  One interacts with attributes through the UsdAtttributeAPI.

A simple example of an attribute that has both an authored default and two timeSamples in the same primSpec:

An attribute with both Default and TimeSamples
def Sphere "BigBall"
{
double radius =
double radius.timeSamples = {
: ,
: ,
}
}

属性是USD场景中创建的最普遍的特性。一个属性只能采用一个USD提供的合法属性类型名,可以在任意数量的timeSamples上同时采用默认数值和给定数值。在一个给定时码上解析一个属性会产生一个数值或不产生数值。属性解析会根据“强者优先”的规则,所以任意给定属性的所有数值都可以从最强的图元分类符获取到。图元分类符提供了默认数值或时间采样值。注意当创建clips时,这个简单的规则会变得更复杂,可以通过UsdAtttributeApi与属性交互。

下面是一个primSpec中一个属性既创建了默认值又有两个时间采样值的例子:见原文。


Opinions

Opinions are the atomic elements that participate in Value Resolution in USD.  Each time you author a value for a Metadatum, Attribute, or Relationship, you are expressing an opinion for that object in a PrimSpec in a particular Layer.  On a composed Stage, any object may be affected by multiple opinions from different layers; the ordering of these opnions is determined by the LIVRPS strength ordering.

Opinions是原子的(独立的)元素,参与到USD中数值解析。每次你为一个元数据、属性、或者关系创建一个数值,你都在向特定Layer中的一个PrimSpec的对象表达一个opinion。在组装好的Stage上,任何对象都可能被来自不同Layer的多个opinion影响;这些opinion的顺序是由LIVRPS strength ordering决定的。


Active / Inactive

Activation is a metadatum/behavior of prims  that models a "non destructive and reversible prim deletion" from a stage. Prims are active by default, which means they and their active children will be composed and visited by stage traversals; however, by making a prim inactive, via UsdPrim::SetActive(false), we prevent the prim itself from being visited by default traversals, and we also prevent the prim's descendant prims from even being composed on the stage, which makes deactivation a useful tool for pruning unneeded scene description for scalability and complexity management.

Activation是图元模仿stage“非破坏性且可逆的删除行为”的一个元数据/行为。默认情况下图元是激活的,这意味着它和它的子图元都会被stage遍历器所组装和访问;然而也可以通过UsdPrim::SetActive(false)使Prim失活,我们能够阻止prim自身被默认的遍历行为访问。也能阻止在stage中组装Prim的后代prim,这就使得deactivation在可伸缩性及复杂度管理中、在削减不需要的场景描述的时候成为一个有用的工具。


Schema

USD defines a schema as an object whose purpose is to author and retrieve structured data from some UsdObject.  Most schemas found in the core are "prim schemas", which are further refined into IsA Schemas and API Schemas, for which the USD distribution provides tools for code generation to create your own schemas.   However, there are several examples of "property schemas", also, such as UsdGeomPrimvar and UsdShadeParameter.  Schemas are lightweight objects we create to wrap a UsdObject, as and when needed, to robustly interrogate and author scene description.  We also use schema classes to package type/schema-based computations, such as UsdGeomImageable::ComputeVisibility().

USD定义了一个模版对象,目的是用于编写或检索UsdObject中的结构化数据。大部分在core中找到的模式对象都属于“图元模版”,IsA SchemasAPI Schemas对这些模版进行了扩展,为此,USD的发行版本提供了代码生成工具来创建你自己的模版。另外还有一些"属性模版",比如UsdGeomPrimvarUsdShadeParameter。模版是一个轻量对象,按照实际需求,我们可以通过包装UsdObject来创建它,并稳定地查询和编辑场景描述文件。我们也使用模版类来封装基于类型或模版的计算过程,例如UsdGeomImageable::ComputeVisibility()


API Schema

An API schema is a prim Schema that does not represent an object's type-identity, but simply serves as an interface or API for authoring and extracting a set of related data.  See the UsdModelAPI class reference as an example.  In terms of the USD object model, an API schema is one that derives from UsdSchemaBase, but not from its subclass UsdTyped.  That means UsdPrim::IsA<UsdModelAPI>() will never return true, for example, and there is no entry for UsdModelAPI in the UsdSchemaRegistry

Choose to create an API Schema when you have a group of related properties, metadata, and possibly associated behaviors that may need to be applied to multiple different types of prims.  For example, if your pipeline has a set of three attributes that get authored onto every gprim, and you want to have a robust schema for authoring and extracting those attributes, you could create an API schema for them.  Why not instead subclass the typedUsdGeomGprim schema and add the attributes there?  Because you would then need to redefine all of the schema classes that derive from Gprim, thus preventing you from taking advantage of built-in DCC support for the UsdGeom GPrim-derived classes.  API schemas provide for "mix in" data organization.   

API schemas can be generated using the USD schema generation tools, but they can also be created manually.

API模版是一个图元模版,但它并不表示对象的类型,只是充当一个编辑、读取相关数据的接口或者API。具体可以看UsdModelAPI类的参考说明作为例子。根据USD的对象模型,API模式派生自UsdSchemaBase,而不是派生自它的子类UsdTyped。举个栗子,这意味着UsdPrim::IsA<UsdModelAPI>()永远不会返回真值,在UsdSchemaRegistry中也不能访问UsdModelAPI。

当你有一组相关属性、源数据,或者可能是相关的行为需要应用到多个不同类型的图元时,请创建API模版。举个栗子,如果在你的流程中要编辑每一个gprim对象上的三值属性(比如rgb、xyz),你又想有一个稳定的模版来编辑和读取这些属性,你就可以为他们创建API模版。为什么不创建一个UsdGeomGprim子类的模版并在子类模版上添加这个属性呢?因为你可能之后还需要重新定义派生自Gprim的所有模版类,这样你就无法在DCC软件中享受到USD对UsdGeom这种派生自GPrim的类的原生支持了。API模版提供了一种“混合”的代码组合方式。

API模版可以用USD模版生成工具生成,当然也可以手动创建。


IsA Schema

An IsA schema is a prim Schema that defines the prim's role or purpose on the Stage.  The IsA schema to which a prim subscribes is determined by the authored value of its typeName metadata, from which it follows that a prim can subscribe to at most one IsA schema - unlike API schemas, to which a prim can subscribe many.  In terms of the USD object model, IsA schemas derive from the C++ class UsdTyped. and derive their name from the fact that UsdPrim::IsA<SomeSchemaClass>() will return true for any prim whose tyepName is or derives from SomeSchemaClass.

IsA schemas can be either abstract or concrete;  UsdGeomImageable is an abstract IsA schema: many prims will answer true to UsdPrim::IsA<UsdGeomImageable>(), but there is no UsdGeomImageable::Define() method because you cannot create a prim of type "Imageable".  UsdGeomMesh, however, is a concrete IsA schema, since it has a Define() method and prims can possess the typeName Mesh.

IsA schemas can provide fallback values for the properties they define, which will be reflected at runtime in the UsdSchemaRegistry

IsA schemas can be generated using the USD schema generation tools, but they can also be created manually.

IsA模版是一个图元模版,它定义了图元在stage中的角色或目的。一个图元添加的IsA模版是由要编辑的值的typeName的元数据来决定的,不像API模版可以添加多个,一个图元最多只能添加一个IsA模版。根据USD的对象模型,IsA模版派生自UsdTyped这个c++类,对于typeName是SomeSchemaClass或者typeName派生自SomeSchemaClass的图元,UsdPrim::IsA<SomeSchemaClass>()都会返回真值。

IsA模版既可以是抽象类,又可以是具体类;UsdGeomImageable是一个抽象的IsA模版:在调用UsdPrim::IsA<UsdGeomImageable>()时,许多图元都会返回真值,但却没有UsdGeomImageable::Define()方法,因为你并不能创建一个“Imageable”类型的图元。与此同时,UsdGeomMesh是一个具体的IsA模版,因为它有Define()方法,图元也可以拥有某种类型的mesh。

IsA模版可以为它们定义的属性提供备用的值,在UsdSchemaRegistry的运行时中可以获得。

IsA模版既可以用USD模版生成工具来生成,也可以手动创建。


05-11 05:16