Maya并行模式初探(Using Parallel Maya)

Maya并行模式初探(Using Parallel Maya)

文章目录

由于Maya2016后新增了并行(Parallel)模式,使用Parallel模式可以并行处理场景的计算任务,从而大大提高帧率,作为CG开发者很有必要深入理解Parallel模式的具体原理,以及如何提升场景性能。

这篇文章内容均来源于 Using Parallel Maya,由于文档中的一些概念有些不好理解,本文将做一些通俗化的解释,如有不当之处,还请指正。

以下为正文(不断更新中)


概述

这篇文档描述在maya里提高播放和操纵动画场景的速度的新特性。涵盖了关键概念、最佳实践和实用提示,并列出将要在后续maya版本中解决的已知限制。

这个指南主要面向对提升maya场景交互性能感兴趣的用户,如绑定师、TD、插件开发者。

如果你想在阅读本文之前先大概了解下与maya并行计算相关的主题,可以查看 Supercharged Animation Performance in Maya 2016


关键概念

从Maya2016开始,Maya可以更好的利用硬件来提升现有场景的交互速度(FPS)。与以往版本的不同之处在于,Maya2016+现在包含了场景级分析和并行化机制(之前的版本仅限节点级并行性)。例如,如果您的场景包含了不同的角色,并且角色之间没有任何依赖,则Maya可以同时对每个角色求值计算(并行处理)。

同样的,如果您的场景里有一个单一但比较复杂的角色,Maya可以同时计算角色Rig的各个部分。因此,您应该能想到,并行度的高低往往取决于您的场景的构建方式。由于并行化构建场景的概念比较复杂,我们稍后将详细讲解这个问题,现在,我们把关注点先放在Maya的求值架构的概念上。

在Maya2016之后,新的求值架构的核心是一个叫做求值管理器(Evaluation Manager,以下简称EM)的东东,EM负责创建一个面向并行机制友好的场景描述,称作求值图(Evaluation Graph,以下简称EG)。当EG图创建完成后,EM则负责利用可用的计算资源去调度已经被EG过的节点再进行计算。

在对您的场景进行求值之前,EM会检查是否存在有效的EG图。这里的EG相当于传统依赖图(Dependency Graph: 简称DG,由节点和属性连接构建)的简化版本。EG连接表示节点级别的依赖关系,下游节点的数据则通过上游节点的数据进行正确的场景求值。由于各种不确定因素,可能检测不到有效的EG图,或者EG图已经失效。例如,您可能加载了新的场景,但场景中没有建立有效的EG,或者场景已经被修改,导致之前的EG失效。

Maya使用脏位传播机制来构建EG。脏位传播是遍历DG图的过程,从动画曲线到可渲染对象,对DG节点属性标记为”需要求值”(比如dirty),与之前的Maya版本不同(maya在每一帧都会进行脏传播),现在如果场景中已经存在有效的EG图,Maya则会禁用脏传播,并且一直重新使用EG图求值,除非当EG图变得失效为止。

禁用脏位传播后,计算一个给定的场景帧时会先遍历EG图,然后调度EG节点,再进行求值计算。由于EG会对节点级的依赖关系进行编码,当对一个EG节点求值时,首先需要确保来自依赖节点的输入已经计算完成。这进一度提升了在流水线中的其他操作被同时调用的可能。特别是,当EG节点没有被依赖时,可以立即启动额外的处理(比如渲染),因为此时没有下游节点需要计算。

小贴士:如果您的场景中包含表达式节点,并且表达式中有使用 getAttr 这样的mel命令,这会让DG图缺少显示的依赖 关系,从而导致生成一个不正确的EG图, 由此降低您场景的并行度(详见调度类型)。避免此类情况,请从表达式中移除 getAttr 相关的语句,或使用节点进行代替。

在您的场景中,EG可能也会包含循环节点级(circular node-level)的依赖关系。如果出现这种情况,EM会产生节点集群(clusters)。这个时候,对场景求值,会先串行处理集群中的节点,再继续与EG图中的其他部分并行计算(多个集群可并行计算)。与Maya2016之前的版本一样,您应该避免创建含有循环关系的属性连接,因为这个在EG中是不支持的,并导致不确定的行为。

默认情况下,EM会调度节点在可用的计算资源中进行计算。并且,EM还具备对EG图中的子部分进行计算求值的能力,使用自定义求值器(custom evaluators)可将计算目标定位在特定的运行时间和/或者硬件资源。这方面的案例请参考 GPU Override ,GPU Override可调用显卡中的处理器(GPU)进行变形加速。


支持的求值模式

从Maya2016开始,支持下面三种求值模式:

模式 解释
DG 对您的场景使用基于依赖关系图的求值模式。在 Maya 2016 之前,这是默认的求值模式
串行(Serial) 使用求值管理器,但是将求值限制到单个核心(串行求值)。使用“串行”(Serial)可排除场景故障,因为它使场景保真度优先于性能,以便您可以找出求值错误。
并行(Parallel) 并行求值并使用所有可用的核心对场景求值。如果此模式导致场景问题,则禁用它并返回到上一标准:DG 求值模式。请参见分析场景以提高性能

 

当使用串行或并行EM模式时,您可以激活 GPU Override 选项从而使用GPU加速多边形的变形处理。

注: “GPU 覆盖”(GPU Override)仅适用于 Viewport 2.0(详情参见 GPU Override)。

切换不同的求值模式,请打开首选项窗口(Windows > Settings/Preferences > Preferences > Animation)。也可以使用 MEL/Python命令: evaluationManager, 详情请查看技术文档。

要查看当前场景的求值模式,请勾选 Display > Heads Up Display > Evaluation 菜单项。


首先确保方法正确,再做加速处理

在讨论如何使用并行模式对您的 Maya 场景进行快速计算之前,必须确保在 DG 和 EM 模式中的求值产生相同的结果。 如果你在动画场景中看到不同的结果(与之前的Maya版本相比), 或者测试显示数值错误,那么理解这些错误的原因是至关重要的。 错误可能是由于不正确的 EG、线程,或其他问题导致。

下面,我们对求值图的正确性和线程安全性这两个重要概念进行回顾,从而理解出错的原因。


求值图的正确性

如果您看到计算结果有出入,首先尝试在串行模式中测试您的场景(参见支持的求值模式),串行求值模式使用EM来构建场景的EG图,但是求值过程都限制在一个核心里,这样可以消除因为线程导致的差异性。这里需要注意,由于为调试提供了串行求值模式,为了结果的正确性,没有针对速度进行优化,串行模式中运行速度可能会比DG模式还慢,这属于正常情况。

如果切换到串行模式后可以解决计算的错误结果,则导致计算错误的原因很可能是因为与线程相关的问题。但是如果错误持续存在(串行模式下),则表明您的场景中构建的EG是不正确的,导致EG构建不正确的原因往往有以下几个:

自定义插件:如果您的场景有依赖于 MPxNode::setDependentsDirty 函数来管理属性的脏位机制,这可能是问题的根源。插件开发者有时候使用 MPxNode::setDependentsDirty 来避免MPxNode中的重复计算,同时监控和/或者调整依赖关系并存储计算结果以备重复使用(或者可以理解为缓存机制)。

由于EG依赖于脏位传播来构建EG图,任何有基于改变依赖关系逻辑的自定义插件都可能干扰正确的EG图的构建。此外,由于EM求值不会在MPxNode中传播脏位信息,所以在有使用 MPxNode::setDependentsDirty 的情况下,任何自定义缓存或计算都不会被调用。

如果您怀疑您的求值错误与自定义插件有关,请临时从您的场景中删除相关节点,并验证 DG 和串行求值模式都会产生相同的结果。 一旦确定了这种情况,您需要重新设计插件逻辑。 Api 扩展部分涵盖了 Maya SDK 的更改,这将帮助您将插件调整到并行求值模式。

另一个调试选项是使用调度类型覆盖,从而强制的使自定义节点启用更保守的方式参与计算。这种方式可以用在并行求值模式,即使只有一些节点是线程安全的。 (调度类型在线程安全部分中有更多的细节描述。)

内置节点出错:尽管我们已经尽最大的努力确保所有的Maya内置节点能正确地表达依赖性,但有时不排除场景中以意想不到的方式在使用节点。 如果是这样的话,请让我们知道您的场景所面临的问题,我们将尽快解决。


线程安全

在Maya2016之前,求值计算是单线程的,开发人员不需要去担心他们的代码是否线程安全。在每一帧计算中,Maya会在完成一个节点之后再计算另一个节点。这种方式允许在全局内存中缓存中间结果,并且保证在使用外部库的情况下可以不考虑它们从多个线程同时调用时是否能产生正确的结果。

到了Maya2016之后,这些保证不再适用。在Maya2016之后,插件开发者必须更新插件,以确保在并行模式下的计算正确。

更新插件时需要考虑的两件事:

  • 同一节点类型的不同实例不应共享资源,非托管的共享资源可能会导致求值错误,因为同一类型的不同节点可以同时调用 compute() 方法。
  • 避免非线程安全的懒求值,在EM中,求值将从前到后遍历每个节点,一旦前面的节点计算完成,结果就会被缓存起来,并通过属性连接提供给后面的节点。任何执行非线程安全的懒求值都可能对不同的下游节点产生不同的结果,或者根据bug的性质不同产生不稳定性的情况。

下面是一个由4个节点组成的简单节点网络案例:

 

在这个图中,求值首先计算Node1(即 Node1.A, Node1.B, Node1.C)的输出,然后对Node2、Node3和Node4进行并行求值 (Node2使用Node1.B的数据,Node3使用Node1.B的数据等)。

以上,我们知道开发者去解决代码中与线程安全相关的遗留问题需要时间,因此我们添加了新的调度类型来控制 EM调度节点的方法。调度类型提供了一个简单的迁移路径,您不需要因为个别节点的性能改进问题,影响现有的工作。

4种调度类型:

调度类型 相关解释
并行 Parallel 断言节点及所有来自第三方库的节点是线程安全的,调度器可以充分利用可用资源同时并行计算此节点的任何实例。
串行 Serial 断言节点及节点所依赖的其他节点都是线程安全的,所有具有此调度类型的节点在求值序列中依次进行计算。
全局串行 Globally Serial 断言所计算的节点及节点所使用的其他节点类型是线程安全的,该节点是线程安全的,但是这个节点类型的单个实例应该同时运行。如果节点的依赖属性是静态的,则使用此调度类型,如果同时对多个节点实现进行求值,则可能导致不可预测的结果,同样的,当第三方库对状态进行存储的时候,这个限制也依然存在。
不可信 Untrusted 断言该节点不是线程安全的,在对此节点的实例进行求值时,不应对其他节点进行求值。不可信任的节点会尽可能的被延迟计算(即直到没有任何依赖他们的节点需要被计算的时候才会被求值),这会导致过慢的实时反馈速度。

 

默认情况下,处于串行调度类型的节点在性能和稳定(安全)性之间处于平衡状态。在某些情况下,对于计算结果来说可能不够精确,那么请将节点降级为全局串行(Globally Serial)或不可信任(Untrusted)模式,而在其他情况下,一些节点又可以被提升为并行模式。在此,您应该能想到,在EG图中,节点的并行度与场景的并行度成正比关系(节点所支持的并行度越高,场景进行计算的时候,并发性也就越高,从而交互性越好)。

小提示:当使用并行模式测试插件时,一个简单的策略是先对节点设置最严格的调度类型(即不可信 Untrusted),待结果验证无误时,再将单个节点提升到下一个调度级别,并重复测试。

有三种方法可以改变节点的调度类型:

求值工具包(Evaluation Toolkit):使用此工具可查询或修改不同节点类型的调度类型。

C++/Python API方法:使用OpenMaya API来重写MPxNode::schedulingType,并制定所需节点的调度类型。此函数返回 类型为 MPxNode::schedulingType 的枚举值。详情请查阅 Maya MPxNode类参考

Mel/Python命令:使用 evaluationManager 命令可以在运行时调整节点的调度类型。下面,我们将说明如何对场景中的transform节点类型进行调度类型的调整:

调度类型 命令
并行 Parallel evaluationManager -nodeTypeParallel on "transform"
串行 Serial evaluationManager -nodeTypeSerialize on "transform"
全局串行 Globally Serial evaluationManager -nodeTypeGloballySerialize on "transform"
不可信任 Untrusted evaluationManager -nodeTypeUntrusted on "transform"

 

求值工具包和 mel / python 命令使用节点类型覆盖的方法来调整节点的调度级别。它们给指定的节点类型的 所有节点进行覆盖操纵。 使用 C++/Python API方法并重写 MPxNode: : schedulingType 函数,从而灵活的更改每个节点实例的调度类型。 例如,如果表达式输出的是纯数学函数,则表达式节点被标记为全局串行。

表达式引擎不是线程安全的, 所以一次只能运行一个表达式, 但它可以与任何其他节点并行运行。 但是, 如果表达式使用不安全的命令(表达式可以使用任何命令来访问场景的任何部分) , 则该节点被标记为不可信任, 因为在对表达式进行求值时, 什么也不能运行。

这就改变了调度类型应该被查询的方式。 在查询模式中使用带有上述标志的 evaluationManager 命令, 无论是使用”求值工具包”还是”mel / python”命令, 将返回节点类型是否设置了覆盖的结果。

求值工具包窗口允许您在构建调度图时查询节点类型的覆盖类型(不能从相同类型的一个节点变为另一个节点)或节点使用的实际调度类型(可以从一个 节点实例到另一个)。


安全模式

在极少的情况下, 你可能会注意到Maya在操作或回放过程中从并行到串行求值。 这是由于安全模式, 它试图捕捉可能导致不稳定的错误, 例如崩溃。 如果 Maya 发现多个线程正在尝试同时访问单个节点实例, 那么求值将被迫进行串行执行以防止问题的发生。

提示:如果安全模式迫使您的场景进入串行模式, 那么在操作时, EM 可能不会产生预期的错误结果。 在这种情况下, 你可以禁用 EM:

evaluationManager -mode "off";

或者禁用 EM-accelerated 操作:

evaluationManager -man 0;

虽然安全模式可以捕捉许多问题,但它无法捕捉到所有问题。因此, 我们还开发了一个特殊的分析模式,对您的场景进行更全面和更费时的检查。分析模式专为需要在Rig创建过程中排除求值问题的绑定师/技术总监而设计。(避免在动画中使用分析模式,因为它会减慢场景。)


求值图失效

如前所述, EG 向 DG 添加了必要的节点级调度信息。 为了确保求值正确, EG必须保持最新的状态,这样才能实时响应场景的状态。 检测事物已经改变并且重建EG的过程被称为求值图失效。

不同的行为可能使 EG 失效, 包括:

  • 添加 / 删除节点
  • 更改场景变换(DAG)层次
  • 添加 / 删除扩展属性
  • 加载一个空的场景或打开一个新的文件

其他不那么明显的行为包括:

  • 静态动画曲线。尽管动画曲线是时间相关的,但DG评估会将具有相同(静态)键的曲线视为时间无关,以避免不必要的计算。 EG使用类似的优化,排除和避免调度静态动画曲线。 这使EG保持紧凑,使其能够快速构建,调度和评估。 这种方法的一个缺点是对静态动画曲线的更改会导致EG无效; 按时更改Maya将重建EG并确定曲线是否应视为时间相关并添加到EG中。
  • 跨过求值图的脏传播。 DG 体系结构允许隐式依赖关系(即不通过连接表达的依赖关系) , 在脏位传播过程中使用它们。 当检测到这些隐式依赖关系的脏传播时, EG 将自动失效, 因为这可能表明需要向 EG 添加新的依赖关系。

频繁的图形失效可能会限制并行求值的性能增益, 因为Maya需要 DG 脏传播和求值来重建 EG。 为避免不必要的图形重建,请考虑立即为您希望经常使用的Rig属性添加2个具有稍微不同的值的键。 您还可以锁定静态通道,以防止在键控期间创建静态动画曲线。 我们希望继续调整Maya的这个领域,目标是尽可能使交互性尽可能的一致。

提示:您可以使用 controller命令来标识将在场景中使用动画源的对象。 如果设置了在评估图表中包含控制器选项(请参阅Windows>设置/首选项>首选项,然后设置>动画),标记为控制器的对象将自动添加到评估图表中,即使它们尚未生成动画。 这将允许并行评估操作,即使它们尚未被键入。


自定义求值器

在本节中,我们描述了对节点子图进行有针对性求值的机制。 Maya使用此方法来加速GPU上的变形,并可对场景中的特定节点捕捉求值错误。 Maya 2017还引入了新的Open API扩展,允许用户定制自定义求值器。

提示:使用evaluator命令查询可用/激活的求值器或修改当前激活的求值器。一些求值器支持使用nodeType标志来过滤或包含特定类型的节点。查询模式下通过使用求值器上的info参数可以获得更多关于它的帮助信息。

# Returns a list of all currently available evaluators. 
import maya.cmds as cmds
cmds.evaluator( query=True )
# Result: [u'invisibility',
u'frozen',
...
u'transformFlattening',
u'pruneRoots'] # 

# Returns a list of all currently enabled evaluators.
cmds.evaluator( query=True, enable=True )
# Result: [u'invisibility',
u'timeEditorCurveEvaluator',
...
u'transformFlattening',
u'pruneRoots'] # 

GPU覆盖

Maya包含一个自定义变形求值器,其目的是通过给 GPU 增加变形任务来加速 Viewport 2.0的变形。 GPU非常适合解决诸如网格变形等需要对顶点和正常数据流进行相同操作的问题。 我们在动画场景中包含了几种最常用变形器的GPU实现:skinCluster,blendShape,cluster,tweak,groupParts,softMod,deltaMush,lattice,nonLinear和tensioin。

与Maya以前的变形器堆栈在CPU上执行变形并随后将变形几何图形发送到显卡进行渲染不同,GPU覆盖会向图形卡发送未变形的几何图形,在OpenCL中执行变形并将数据交给Viewport 2.0进行渲染,而不会有回读的开销。 我们已经观察到这种方法在密集几何场景中有显着的速度提升。

即使您的场景仅使用支持的变形器,由于在场景中使用了不受支持的节点功能,GPU替代可能仍未启用。 例如,除softMod之外,不支持不完整的组组件。 下面列出了额外的变形器特定限制:

变形器 限制(这些属性值将被忽略)
 skinCluster – bindMethod
– bindPose
– bindVolume
– dropOff
– heatmapFalloff
– influenceColor
– lockWeights
– maintainMaxinfluences
– maxInfluences
– nurbsSamples
– paintTrans
– smoothness
– weightDistribution
blendShape – baseOrigin
– icon
– normalizationId
– origin
– parallelBlender
– suportNegativeWeights
– targetOrigin
– topologyCheck
cluster n/a
tweak 只支持相对模式,relativeTweak必须设置为1
groupParts n/a
softMod 当距离缓存被禁用时,仅支持体积衰减
Falloff必须在所有轴向上都出现
必须禁用 Partial resolution
deltaMush n/a
lattice n/a
nonLinear n/a
tension n/a

 

还有一些其他的原因会阻止场景中的 GPU 覆盖:

  • 网格不够密集: 除非网格具有大量的顶点,否则在CPU上执行变形仍然更快。 这是由于将数据发送到GPU进行处理时发生的驱动程序特定开销。 对于GPU上发生的变形,当使用AMD/NVIDIA显卡时,网格分别需要超过500/2000个顶点。 使用MAYA_OPENCL_DEFORMER_MIN_VERTS环境变量来更改阈值。 将值设置为0,会将所有连接到支持的变形器的网格发送到GPU。
  • 下游图节点需要变形网格作为输入: 由于 GPU 回读是 GPGPU 领域已知的瓶颈,没有节点、脚本或视口可以读取 GPU 覆盖的网格数据。 这意味着 GPU 覆盖不能加速变形节点上游的EG部分, 如依赖变形网格信息的毛囊(follicle)或 pointOnPolyConstraint。 随着软件/硬件功能的成熟, 我们将重新审视这个局限。 当诊断 GPU 覆盖问题时, 可能会将此情况报告为不支持的扇形输出(fan-out)模式。 有关详细信息,请参阅下面的deformerEvaluator命令。
  • 动画拓扑: 如果您的场景在播放过程中,网格的边、顶点或面的数量处于变化状态,则相应的变形链会从 GPU 变形路径中移除。
  • 使用了Maya Catmull-Clark 光滑网格预览(Maya Catmull-Clark Smooth Mesh Preview): 我们在OpenSubDiv(OSD)平滑网格预览中添加了加速功能,但是不支持Maya传统的Catmull-Clark。 要利用OSD OpenCL加速,请选择OpenSubDiv Catmull-Clark作为细分方式,并确保在OpenSubDiv控件中勾选了OpenCL加速。
  • 发现不支持的数据流: 根据您为几何图形选择的绘图模式(例如,shrunken faces,hedge-hog normals 等)以及分配给几何图形的材质,Maya必须分配不同的数据流并将其发送到图形卡。 由于我们已将工作重点放在生产中使用的最常见设置上,GPU覆盖目前不支持所有数据流的组合。 如果由于不支持的流而导致网格无法加速,请更改显示模式和/或更新几何图形材质。
  • 启用了背面剔除
  • 与驱动有关的问题: 我们意识到与OpenCL的驱动程序支持/稳定性相关的各种硬件问题。 为了最大限度地提高Maya的稳定性,我们已经在导致问题的特定情况下禁用GPU Override。 我们预计未来将继续取消限制,并积极与硬件供应商合作解决检测到的驱动程序问题。

你也可以使用新的 API 扩展来增加对新的自定义 / 专有的变形器的支持(详情请参阅自定义 GPU 变形器)。

如果已启用 GPU 覆盖和 HUD 报告启用(0 k) , 则表示 GPU 上没有发生变形。 造成这种情况的原因可能有很多,例如上面提到的。

要排除限制GPU特定场景使用的因素,请使用deformerEvaluator命令。 支持的选项包括:

命令 解释
deformerEvaluator 不支持打印链或每个选定的节点
deformerEvaluator -chains 打印所有活动的变形链
deformerEvaluator -meshes 如果不支持, 则为每个网格打印一个链或一个原因

 


动力学求值器

从Maya 2017开始,动力学求值器完全支持Nucleus(nCloth,nHair,nParticle),Bullet和Bifrost动力学的并行计算。传统动力学节点(例如,粒子,流体)依然不支持。 如果动力学求值器在EG中发现不支持的节点类型,则Maya将恢复为基于DG的求值。动力学求值器还管理正确场景求值所需的复杂计算。这是自定义求值器可以用来更改Maya默认求值行为的方式之一。

动力学求值器支持一些配置标志来控制其行为:

标记(Flag) 解释
disablingNodes 强制动力学求值器对指定的节点集禁用EM。 有效参数值为: legacy2016, unsupported, 和 none
handledNodes 将动力学求值器对指定的节点集捕获并按其将要管理的集群进行调度。 有效参数值为: dynamics 和 none
action 指定动态求值器如何处理其节点。 有效参数值为: none, evaluate 和 freeze

 

在Maya2017年,默认配置对应于:

evaluator -name dynamics -c "disablingNodes=unsupported";

evaluator -name dynamics -c "handledNodes=dynamics";

evaluator -name dynamics -c "action=evaluate";

以下是不被支持的(也就是黑名单)节点:

  • collisionModel
  • dynController
  • dynGlobals
  • dynHolder
  • fluidEmitter
  • fluidShape
  • membrane
  • particle (unless also a nBase)
  • rigidNode
  • rigidSolver
  • spring
  • nodes derived from the above

如果遇到任何不支持的节点,此配置将禁用求值,并对场景中的其他已处理节点执行求值。

若要恢复到 Maya 2016 / 2016 Extension 2行为, 请使用以下配置:

evaluator -name dynamics -c "disablingNodes=legacy2016";
evaluator -name dynamics -c "handledNodes=none";
evaluator -name dynamics -c "action=none";

以下是不被支持的(也就是黑名单)节点:

  • field
  • fluidShape
  • geoConnector
  • nucleus
  • particle
  • pointEmitter
  • rigidSolver
  • rigidBody
  • nodes derived from the above

提示:要获取将使动力学求值器在当前配置中禁用EM的节点列表,请使用以下命令:

evaluator -name "dynamics" -valueName "disabledNodes" -query;

您可以配置动力学求值器忽略不受支持的节点。 如果您想在一个场景中尝试并行求值, 但存在不受支持的节点类型, 请使用以下命令:

evaluator -name dynamics -c "disablingNodes=none";
evaluator -name dynamics -c "handledNodes=dynamics";
evaluator -name dynamics -c "action=evaluate";

注意: 在不支持的节点上使用动力学求值器可能会导致求值问题和 / 或应用程序崩溃,这是不受支持的行为。 请谨慎行事。

提示:如果您希望动力学求值器跳过对场景中所有动力学节点的求值, 请使用以下命令:

evaluator -name dynamics -c "disablingNodes=unsupported";
evaluator -name dynamics -c "handledNodes=dynamics";
evaluator -name dynamics -c "action=freeze";

当模拟解算对动画性能有很大影响时, 这可以快速禁用动力学。

动态仿真结果对求值顺序非常敏感,这在DG和基于EM的求值模式时可能会有所不同。 即使是基于DG的求值,求值顺序也可能取决于多种因素。 例如,在将模拟结果渲染到视口时,在DG模式下,求值顺序可能与以“无头模式(headless mode)”执行模拟时不同。 尽管基于EM的求值结果不能保证与基于DG的求值结果相同,但求值顺序是一致的, 一旦求值顺序通过EM进行调度,无论结果是否得到显示,还是在批处理中使用Maya, 都将保持一致。 这个原理同样适用于依赖于顺序的非动力学节点。


参考求值器

当参考被卸载时,它会在场景中留下几个代表参考编辑的节点来保存。 尽管这些节点可能会继承上游节点的动画,但它们不会影响呈现的内容,并且在求值期间可以安全地忽略它们。 参考求值器确保在求值期间跳过所有这些节点。


不可见性求值器

切换场景对象可见性是艺术家用于减少视觉混乱和加速性能的关键工作流程。为了将此工作流程引入并行求值,Maya 2017及以上版本包含不可见性求值器,其目标是跳过对任何可见对象无贡献的节点的求值。

当DAG节点满足以下任何一个条件的时候,不可见性求值器将对其跳过求值:

  • visibility 属性为 false
  • intermediateObject 属性为 true
  • overrideEnabled 属性为 true 并且overrideVisibility 属性为 false
  • 节点属于一个显示层 enabled属性为true,并且visibility 属性为 false
  • 每个实例路径至少包含一个节点, 其中一个节点满足上述任一条件

从Maya 2018开始,不可见性求值器支持隐藏对象的隔离选择(isolate select)方法。 如果只有一个视口,并且其中有一个或多个对象被隔离,则所有其他不相关的对象都将被求值器视为不可见。

同样,在Maya 2018中也支持表达式节点上的动画属性。当此属性设置为1时,即使只有不可见对象连接到该表达式节点,该表达式节点也不会被不可见性求值器跳过。

注意: animated 属性的默认值为1, 因此在表达式较重的场景中,您可能会看到从Maya 2017到Maya 2018的减速。要恢复性能,请运行以下脚本以在所有表达式节点上禁用此属性。 (只有当表达式具有连接外部的某种副作用时才需要,例如打印消息或检查缓存文件大小。)

for node in cmds.ls( type='expression' ):

    cmds.setAttr( '{}.animated'.format(node), 0 )

提示: 不可见性求值器在Maya2017中默认处于关闭状态。启用可使用求值工具包或以下命令:

cmds.evaluator(enable=True, name='invisibility')

不可见性求值器只考虑静态可见性,即使节点符合上述标准,具有动态可见性的节点仍会被求值。如果节点处于循环中,则所有循环节点都必须被认为是不可见的,以便跳过求值。最后,如果一个节点的父级路径至少有一个可见,那么所有父级路径都将被求值。

提示: 不可见求值器只根据节点的可见性状态来确定其可见性的定义,如果您的 UI 或插件代码要求不可见节点进行求值,则不要使用不可见性求值器。


冻结求值器

冻结求值器可用于从求值中排除EG图的子区域。它适用于冻结属性,允许使用由求值器配置设置的规则将冻结状态传播到相关节点。仅当您熟悉 DAG 和求值图中的连接和传播概念时才使用冻结求值器。否则,请使用更简单的不可见性求值器,它为大多数情况提供了更简单的界面 / 工作流程。

冻结属性

自Maya 2016以来,节点就有冻结属性了。它可用于控制是否在串行或并行EM求值模式下对节点求值。 原则上,当设置冻结属性时,EM会跳过对该节点的求值。但是,还有其他的细微差别会影响到是否如此处理:

  • 冻结节点下游的所有节点都将被求值,除非它们也设置了冻结属性,或者受冻结求值器的影响,如下所述。
  • 某些节点可能会执行优化,导致其输出无效且求值容易发生变化。冻结这些节点可能会产生意想不到的结果,因为没有保留旧值。有关如何在要冻结的节点上专门启用缓存的方法,请参阅nodeState属性上的文档。
  • 当冻结属性被动画化时, 您可能会有不一致的每帧结果。 当属性设置时, 节点”冻结”, 所以如果你从一帧跳到另一帧, 你的对象状态反映了你最后一次访问一个未冻结状态。 只有当你的对象在第一帧中没有被冻结时, 播放才是一致的
  • 当冻结节点处于一个循环链的中间环节时,它将不被遵守。循环链使用拉模型进行求值,拉模型不考虑冻结的属性值。
  • 自定义求值器可能会也可能不会遵守被冻结的属性值。在实施过程中请考虑到这一点。

警告: 由于所有冻结属性都会跳过求值,所以在文件存储过程中不会保存当前的节点数据,如果你加载一个带有冻结属性集的文件,则节点可能会丢失在存储它们时的数据。

处理过程

求值管理器不会对任何冻结属性设置为True的节点进行求值,这里称为显式冻结节点。隐式冻结的节点是由于冻结求值程序的操作而被禁用的节点,但其冻结属性未设置为True。当冻结求值器被启用时,它也将防止根据与启用的选项相对应的规则以任何组合来求值相关节点。

冻结求值器分三个阶段进行操作。 在第一阶段,收集标记为不可见的节点和标记要冻结的 displayLayers 选项。在第二阶段,,根据下游和上游选项的值,通过求值图向外传播冻结状态。

第一阶段:收集节点

传播节点列表如下:

  • frozen属性设置为 True 的节点会被发现。(注:这里不包含frozen属性有动画数据的节点,这些节点会在第三阶段处理)
  • 如果不可见选项为True,则任何显示冻结且不可见性的节点(直接或者因为其父节点都不可见),将其所有DAG子节点都添加到第二阶段的节点列表中。
  • 如果 displayLayers 选项为 True, 则任何显示冻结,启用和不可见的显示层成员节点都会拥有该节点,并将其所有DAG子节点都添加到第二阶段的节点列表中。

第二阶段:冻结传播

第一阶段收集的节点清单将全部冻结。另外,下游和上游选项可以隐含的冻结与它们相关的节点。对于目前为止所收集的每个节点,求值图会在两个方向上遍历,根据以下选项隐式冻结被遍历到的节点:

  • 下游 选项值
    • “none” : EG下游没有其他节点将被隐式冻结
    • “safe” : EG中的下游节点只有在每个上游节点已经隐式或明确冻结的情况下才会被隐式冻结
    • “force” : EG下游的节点将被隐式冻结
  • 上游 选项值
    • “none” : EG上游没有其他节点将被隐式冻结
    • “safe” : 只有在每个下游节点已经隐式或明确冻结的情况下,EG中的上游节点才会被隐式冻结
    • “force” : EG上游的节点将被隐式冻结

第三阶段:运行时冻结

如果一个节点的冻结或可见性状态已设置动画,求值器依然需要调度它。运行时冻结仍然可以帮助Maya防止不必要的求值。通常,任何显示冻结的节点都会跳过对其求值,其他所有节点都正常求值。启用运行时选项后,跳过对显示冻结节点的评估后,不会再发生下游节点的调度。因此,如果下游节点没有其他解冻输入,它们也将被跳过。

注意: 运行时选项并不真正修改求值器操作,它修改了节点的调度已供求值。您不会再求值器信息中看到受此选项影响的节点(例如 cmds.evaluator( query=True, clusters=True, name='frozen' ) 的输出)

设置选项

可通过以下两种方式为冻结求值器进行选项设置:

  • 通过求值工具包( Evaluation Toolkit )进行访问
  • 使用求值器命令的配置选项:
    cmds.evaluator( name='frozen', configuration='KEY=VALUE' )

关于上面命令中的KEY和VALUE的设置如下:

KEY VALUES 默认值
runtime True/False False
invisible True/False False
displayLayers True/False False
downstream ‘off’/‘safe’/‘force’ ‘off’
upstream ‘off’/‘safe’/‘force’ ‘off’

与大多数求值器不同,冻结求值器的选项设置会存储在用户偏好设置中,并在会话之间保持不变。

限制

  • 为了指示冻结求值器关闭受影响节点的求值,您必须至少将一个冻结属性设置为True。 这个最实际的用法是在显示层上,这样节点可以作为一个组被隐式冻结。
  • 如果冻结属性或任何用于定义相关隐式节点以便冻结(例如,不可见性)的属性已设置动画,则该求值器不会将其从求值中移除。这些属性仍会进行调度,但是只有运行时选项才有助于避免进行不必要的求值。
  • 除非循环的所有输入均已冻结,否则该求值器不会冻结循环成员。这是因为循环作为一个整体进行求值,冻结循环的单个成员毫无意义。

其他求值器

除了上述求值器以外,还有其他求值器负责专门的任务:

求值器 功能解释
curveManager 使用未设置动画的节点对求值图进行预设,以便在交互式操作时随时能并行求值。(该功能处于原型阶段,仍处于开发中)
timeEditorCurveEvaluator 查找所有与时间编辑器节点相连接的 paramCurves 节点,并将它们放入一个集群中,以防止它们在当前时间进行求值,因为时间编辑器将管理其求值状态。
ikSystem 在EG中存在IK解算器时自动禁用EM。 对于常规IK链,它将在并行执行之前执行所有的惰性更新。
disabling 如果用户指定的节点存在于EG中,则自动禁用EM。 此求值器主要用于故障排除。它允许Maya保持稳定工作,直到异常节点的问题得到解决。
hik 通过识别HumanIK常见连接模式,以高效的方式处理HumanIK角色的求值。
transformFlattening 合并含有动画的父节点和静态子节点的深度变换层级, 从而提高求值速度。合并将对相对关系中的父 / 子转换进行快照,允许对下游节点进行并发求值。
pruneRoots 我们发现有数千个 paramCurves 节点的场景由于EG节点产生的调度开销而陷入停滞状态,并且由于并行性增加而失去潜在速度提升。为了处理这种情况,创建了特殊群集,将paramCurves分组为少量求值任务,从而减少了开销。

随着我们加入新的求值器并加强这些功能后,自定义求值器的名称可能会有变更。

求值器冲突

有时候,多个求值器会希望同时为一个节点“要求承担责任”。这可能会导致冲突,从而对性能产生负面影响。为了避免这些冲突,每个求值器在注册时应设定相应的优先级别,并将节点分配给具有最高优先级的求值器。内置的求值器首先考虑的是求值的正确性和稳定性,而不是速度。


API 扩展

已经添加了几个 API 扩展和工具, 以帮助你在流程中充分利用EM。本节回顾与API扩展相关的内容,包含并行求值,自定义GPU变形器,自定义求值器API,和分析器插件

并行求值

如果您的插件运行在DG模式,则可能不需要进行许多更改即可使插件在并行模式下工作。将您的插件移植到并行版本中可能会像重新编译OpenMaya最新版本一样简单!

如果EM生成的结果与基于DG的求值结果不同,请确保您的插件满足以下条件:

  • 覆盖 MPxNode::compute()对于以前从MPxTransform类派生并依赖asMatrix()的尤其如此。请参考SDK中的rockingTransform案例。对于派生自MPxDeformerNode和MPxGeometryFilter的类,请覆盖 deform() 方法。
  • 处理插件树中所有级别的求值请求:虽然DG可在任何级别请求plug值,但EM始终请求root plug。例如,对于plug N.gp[0].p[1],您的compute()方法必须对N.gp, N.gp[0], N.gp[0].p和N.gp[0].p[1]求值。

如果您的插件依赖于自定义依赖关系管理,则需要使用新的API扩展来确保正确的结果。 如前所述,EG是使用传统的脏传播机制构建的。 因此,用于限制DG求值期间脏传播的优化(例如MPxNode :: setDependentsDirty中的优化)可能会在EG中出错。注:可使用 MEvaluationManager::graphConstructio-nActive() 来检测此类情况的发生。

有些新的虚方法需要考虑添加:

  • MPxNode::preEvaluation. 为了避免每次调用求值方法  MPxNode::compute() 时执行昂贵的计算,插件作者使用的一种策略是存储先前求值的结果,然后依靠 MPxNode::setDependentsDirty 去触发重新求值。如前所述,一旦EG被建立,脏传播则会被禁用且EG会被重新使用。因此,插件中依赖 setDependentsDirty 的任何自定义逻辑不再使用。MPxNode::preEvaluation 允许您的插件确定哪些 plugs/attributes 是脏(dirty)的,以及是否需要执行任何操作。使用新的 MEvaluationNode 类可检测已被 dirtied的 plug/attributes。有关如何使用 MPxNode::preEvaluation 可参考devkit中的 simpleEvaluationNode 案例。
  • MPxNode::postEvaluation:到目前为止,很难确定指定节点实例的所有处理是在哪个环节完成的。用户有时采用复杂的并且会添加额外计算工作量的 bookkeeping/callbacks 方案来检测这种情况,例如自定义渲染,这种机制非常麻烦并且容易出错。一旦在指定节点实例上执行了所有的计算后,就会调用新的  MPxNode::postEvaluation 方法。由于此方法是从 工作线程(worker thread)调用的,因此它会为下游图形操作执行计算,而不会阻止非依赖节点的其他Maya处理任务。请参考devkit中 simpleEvaluationDraw 案例了解如何使用此方法。如果在常规求值中运行此示例,则Maya会减慢速度,因为执行昂贵的计算时会阻止求值。在并行求值模式运行时,工作线程会调用 postEvaluation 方法,并为后续绘制操作准备数据。测试时,在常规的并行或串行求值中您将看到更高的帧速率。注意:postEvaluation 中的代码必须是线程安全的。

友好提示:

  • 避免将状态存储在静态变量中: 将节点状态/设置存储在属性中,这样可以在写入/读取Maya文件时自动保存/恢复插件状态。
  • 节点计算不应该有任何超出输入值的任何依赖关系:Maya节点应该像函数一样。输出值应该根据输入状态和节点特定的内部逻辑进行计算,你的节点不应该依赖图中其他的节点或者绕过DG。

自定义 GPU 变形器

为了让GPU Override在包含自定义变形器的场景上工作,Maya提供了新的API类,允许创建快速的OpenCL变形器后端。

虽然当你在GPU上不能达成目标时,依然需要有一个CPU实现(参考 GPU Override ),您可以继承 MPxGPUDeformer 来增强这个功能。这适用于自定义节点及Maya内置的标准节点。

继承GPU时您需要确保以下条件:

  • 声明何时有效使用基于GPU的后端(例如,您可能希望将GPU版本限制为各种属性已修复的情况,省略特定属性值的用法等)
  • 提取 MDataBlock 输入值并将值上传到GPU
  • 定义并调用OpenCL内核来执行所需的计算
  • 向 MGPUDeformerRegistry 系统注册。这将告诉系统您要为之负责的变形器。

完成此操作后,请不要忘记在启动时加载插件。devkit包含两个可用的示例(offsetNode 和 identityNode) 可以帮助您。

提示:通过为特定的变形器提供GPU后端,您可获得最大速度提升,告诉Maya将特定节点视为传递通道,以下是一个应用于 polySoftEdge 的示例:

   GPUBuiltInDeformerControl
       -name polySoftEdge
       -inputAttribute inputPolymesh 
       -outputAttribute output
       -passthrough;

虽然结果不正确,但此测试可以确实是否值得投入时间编写OpenCL版本的节点。

自定义求值器 API

Maya2017版引入了自定义求值器的API类和方法,方便您控制如何对Maya场景进行求值。

创建自定义求值器,继承MPxCustomEvaluator 类即可,以下我们介绍下该类的几个重要方法的重写方式。

基础知识

新的求值器在使用之前必须先进行注册:

MStatus registerEvaluator(
    // 求值器的名称
    const char *     evaluatorName,  

    // 求值器的优先级,优先级越高求值会越靠前
    unsigned int     uniquePriority,

    // 返回新的求值器实例的函数指针 
    MCreatorFunction creatorFunction
)

然后是撤销注册:

MStatus deregisterEvaluator(
    // 求值器的名称
    const char* evaluatorName 
)

依然使用 MFnPlugin 方法,用于在插件初始化:

MStatus initializePlugin( MObject obj )
{
    MFnPlugin plugin( obj, PLUGIN_COMPANY, "3.0", "Any");
    MStatus status = plugin.registerEvaluator(
        "SimpleEvaluator", 
        40, 
        simpleEvaluator::creator);
    if (!status) 
        status.perror("registerEvaluator");
    return status;
}

然后是卸载(uninitialization)插件时:

MStatus uninitializePlugin( MObject obj )
{
    MFnPlugin plugin( obj );
    MStatus status = plugin.deregisterEvaluator( "SimpleEvaluator" );
    if (!status)
        status.perror("deregisterEvaluator");
    return status;
}

如上所诉。

一旦插件加载成功,你可以使用Python或MEL命令来启用自定义的求值器:

import maya.cmds as cmds
cmds.evaluator(enable=True, name='SimpleEvaluator')

# Result: False #

或者禁用:

cmds.evaluator(enable=False, name='SimpleEvaluator')

# Result: True # 

以及查询求值器的信息:

print cmds.evaluator(query=True)

[u'invisibility', ... u'SimpleEvaluator']

注: 这里的 evaluator 命令返回的是求值器先前的状态 (如文档所述),如果求值器无法启用,此命令也将失败。

要查看所有已加载的求值器的优先级,可使用 evaluator 命令的 priority标志:

for evaluatorName in cmds.evaluator():
    print "%-25s : %d" % (
        evaluatorName,
        cmds.evaluator(name=evaluatorName, query=True, priority=True))

invisibility              : 1003000
frozen                    : 1002000
curveManager              : 1001000
timeEditorCurveEvaluator  : 104000
dynamics                  : 103000
ikSystem                  : 102000
disabling                 : 100000
hik                       : 7000
reference                 : 6000
deformer                  : 5000
transformFlattening       : 3000
pruneRoots                : 1000
SimpleEvaluator           : 40

API参考

本节提供了有关不同 MPxCustomEvaluator API方法的更多详细信息。

声明集群(clusters)

在EG分区期间,每个求值器都可以使用以下命令来声明求值节点:

bool MPxCustomEvaluator::markIfSupported(const MEvaluationNode* node)

您可在此调用中安全的求值,但这样做会增加分区和求值的时间。开发者可以确定是否需要求值(调用 .inputValue / .inputArrayValue )或者重新使用先前求值的数据块值(带调用 .outputValue / .outputArrayValue )。如果多个求值器标记了一个特定的节点,则在运行时为那个求值器分配节点是由优先级确定。例如,如果您有两个求值器A和B,并对C节点进行标记,如果求值器A的优先级为100,求值器B的优先级为10,则在图的分区期间,求值器A将有机会在求值B之前抓取节点C。求值器不应该试图抓取被优先级更高的求值器抓取的节点。

调度

要确定求值器是否可以并行集群求值,请使用:

MCustomEvaluatorClusterNode::SchedulingType schedulingType(
    // 自定义求值器图层上的一组不连续的节点
    const MCustomEvaluatorClusterNode * cluster 
)

在以下求值模式下:

调度类型 细节描述
kParallel 任何同类型的节点都可以并行运算
kSerial 此类型的所有节点都应该被链接起来并按顺序执行
kGloballySerial 只有一个节点可以同时运行
kUntrusted 没有其他方法可以执行这个节点,因为我们无法预测将会发生什么

处于EG调度过程中:

bool MPxCustomEvaluator::clusterInitialize(
    const MCustomEvaluatorClusterNode* cluster // 集群求值节点
)

可用于执行所需的群集准备,指向集群的指针在图失效之前保持有效,例如场景拓扑发生变化时。

在集群被删除之前,

void MPxCustomEvaluator::clusterTerminate(
    const MCustomEvaluatorClusterNode* cluster // 该集群终止
)

被调用以允许进行必要的清理,例如释放求值器特定的资源。由自定义求值器觉得是否清楚其内部表示。

执行

在执行过程中有三种主要的方法

在图表执行之前,EM调用:

void MPxCustomEvaluator::preEvaluate(
    const MEvaluationGraph* graph // 该图即将被求值
)

在执行期间,EM调用:

void MPxCustomEvaluator::clusterEvaluate(
    const MCustomEvaluatorClusterNode* cluster // 要求值的群集
)

您会仅收到属于此求值器的群集。此调用始终发生在 clusterInitialize 之后,并且始终在 clusterTerminate 之后发生,最后,

void MPxCustomEvaluator::postEvaluate(
    const MEvaluationGraph* graph // 被求值的图
)

在图求值完成后立即调用。

SimpleEvaluator API 案例

现在我们已经温习了相关的API方法,以下是通过缓存先前的结果来限制求值频率的示例。simpleEvaluator 是假定存在使用动画标记控制器节点的场景节点,其工作方式如下:

在 clusterInitialize ,我们建立一个变换和旋转属性插头的列表:

// 通扫描场景中的控制器节点来构建插头列表
// 在调度阶段调用
bool simpleEvaluator::clusterInitialize(const MCustomEvaluatorClusterNode* cluster)
{
    if (fControllerPlugs.length() == 0)
        buildPlugListWithControllerTag();
    return true;
}

// 扫描场景中的任何控制器节点,填充进插头列表
// 在调度阶段调用
void simpleEvaluator::buildPlugListWithControllerTag()
{
    MStatus stat;
    MItDependencyNodes dgIter(MFn::kControllerTag, &stat);
    if (stat != MS::kSuccess)
        return;

    const char* values[] = {
        "translateX", 
        "translateY", 
        "translateZ", 
        "rotateX", 
        "rotateY", 
        "rotateZ"
    };

    for (; !dgIter.isDone(); dgIter.next()) 
    {
        MFnDependencyNode controllerTagNode(dgIter.thisNode(), &stat);
        if (stat != MS::kSuccess)
            continue;

        MPlug currControllerTagPlug = 
            controllerTagNode.findPlug("controllerObject", &stat);
        if (stat != MS::kSuccess)
            continue;

        // 找到控制器标记节点,现在获取它的源控制器
        MPlugArray source;
        bool retval = currControllerTagPlug.connectedTo(
            source, 
            true /* asDst */, 
            false /* asSrc */, 
            &stat)
        if ((retval == false) || (stat != MS::kSuccess))
            continue;

        // 控制器标记节点应该只有一个源节点
        // 作为目标
        MObject controllerNode = source[0].node(&stat);
        if (stat != MS::kSuccess)
            continue;

        MFnDependencyNode currControllerNode(controllerNode, &stat);
        if (stat != MS::kSuccess)
            continue;

        for (unsigned int j = 0; j < 6; j++)
        {
            MPlug currPlug = currControllerNode.findPlug(values[j], &stat);
            if (stat == MS::kSuccess)
                fControllerPlugs.append(currPlug);
            else
                std::cerr 
                    << "NO PLUG: " 
                    << currControllerNode.name().asChar() 
                    << "." 
                    << values[j] 
                    << std::endl;
        }
    }
}

之后,在 preEvaluate期间,根据当前帧的插值计算散列值。

void simpleEvaluator::preEvaluate(const MEvaluationGraph* graph)
{
    buildHashValue();
}

void simpleEvaluator::buildHashValue()
{
    unsigned int length = fControllerPlugs.length();
    MStatus stat = MS::kSuccess;

    for (unsigned int i = 0; i < length; i++)
    {
        float value = 0;
        stat = fControllerPlugs[i].getValue(value);

        if (stat == MS::kSuccess)
        {
            boost::hash_combine(fCurrentHashValue, value);
        }
        else
        {
            std::cerr 
                << "NO VALUE: " 
                << fControllerPlugs[i].name().asChar() 
                << std::endl;
        }
    }
}

该值与 clusterEvaluate 中前一帧的散列进行比较,如果散列不同,则求值持续进行,否则什么也不做。

void simpleEvaluator::clusterEvaluate(const MCustomEvaluatorClusterNode* cluster)
{
    if (fOldHashValue != fCurrentHashValue)
        cluster->evaluate();
}

为了确保散列值是最新的,散列值存储在 postEvaluate中。

void simpleEvaluator::postEvaluate(const MEvaluationGraph* graph)
{
    fOldHashValue = fCurrentHashValue;
    fCurrentHashValue = 0;
}

最后,当图形拓扑结构变得无效时,我们调用 clusterTerminate 来清除缓存的插头列表。

void simpleEvaluator::clusterTerminate(const MCustomEvaluatorClusterNode* cluster)
{
    if (fControllerPlugs.length() > 0)
        fControllerPlugs.clear();
}

由于 simpleEvaluator 控制整个图形,因此 markIfSupported 对所有节点都返回True。另外,没有什么特别的做法来改变集群的调度行为。

bool simpleEvaluator::markIfSupported(const MEvaluationNode* node)
{
    return true;
}

MCustomEvaluatorClusterNode::SchedulingType 
simpleEvaluator::schedulingType(const MCustomEvaluatorClusterNode* cluster)
{
    return cluster->schedulingType();
}

更多信息及完整的源代码,请参考devkit中的 simpleEvaluator 示例。

分析器插件

若要在新的分析工具中显示自定义插件的使用时间(请参见”分析您的场景“) ,您需要设置您的代码。 Maya为你提供 C++, Python 和 Mel 接口。 有关更多详细信息, 请参考 使用 MEL 或 Python 或 API 分析 的技术文档。


分析您的场景

在过去, 了解Maya在哪里消耗时间是一件很难的事情。为了消除性能诊断中的猜测工作,Maya 集成了一个新的分析器,它可以让您了解不同任务所花费的时间。

你可以通过下面方式打开分析器:

  • 通过 Windows > General Editors > Profiler 菜单项打开
  • 或者从 Persp/Graph Layout 中直接选择 Panel Layout > Profiler 切换

当打开分析器窗口后:

  1. 打开您的场景并进行播放
  2. 在”分析器”中单击”开始”可以在预先分配的记录缓冲区中记录信息
  3. 等待记录缓冲区填满,或者在Profiler中单击停止按钮。Profiler会显示一个图表,显示场景动画的处理时间。
  4. 尝试在DG,串行(Serial),并行(Parallel),和 GPU覆盖(GPU Override)模式下分别录制场景。

提示:默认情况下, 分析器分配一个20mb 的缓冲区来存储结果。 记录缓冲区可以通过用户界面或者使用 profiler -b value 来扩展缓冲区大小。 对于更复杂的场景来说, 这可能是必要的。

分析器(Profiler)包含所有已检测代码的信息,包括播放,操作,创作任务和UI / Qt事件。在分析场景时,请确保捕获多帧数据,以确保收集的结果能够反馈场景瓶颈。

分析器可分为几个不同的视图模式。 默认为类别视图,如下所示,按类型对事件进行分类(例如: dirty、 VP1、 VP2、 evaluate 等)。线程和 CPU 视图则显示了函数链如何在可用的计算资源之间进行细分。 目前,分析器不支持与 GPU 相关计算事件的可视化。

现在你已经对 分析器 工具的功能有了大致的了解,接着讨论一下计算场景结果的关键环节以及图表显示的结果分别代表什么含义。这样您能更好的理解场景为什么速度缓慢,并且有针对性的进行场景优化。

Maya每更新一帧,它都必须计算和绘制场景中的元素。 因此,计算可以分为两大类:

  1. 求值(通过数学计算场景元素的最新情况)
  2. 渲染(在视图中绘制计算后的场景元素)

当您的场景中的主要瓶颈是求值环节时,我们称场景是求值约束(evaluation-bound)。当您的场景中的主要瓶颈是渲染时, 我们说场景是渲染约束(render-bound)。

求值约束时的表现

有几个不同的问题可能导致求值约束时的性能。

锁争用(Lock Contention): 当许多线程尝试访问共享资源时,由于锁定资源不能使用,其他线程访问该资源时就需要一直等到资源被解锁。发生这种情况时,无论您使用哪种求值模式,求值的持续时间大致相同。

这里的分析器显示了许多独立的相同任务,这些任务几乎同时在不同的线程上开始,在不同的时间完成。这种类型的图示意味着,可能许多线程同时在访问一些共享资源。

下面是另一张显示类似问题的图片:

在这种情况下,由于几个线程正在执行 Python 代码,所以它们都必须等待 全局编译锁定(Gloabl Interpreter Lock: GIL)变得可用。 当有较高的并发水平时,例如当计算机有许多核心时,由于争用问题导致的瓶颈和性能损失可能会更加明显。

如果遇到争用问题,请尝试修复有问题的代码。 对于上述示例,更改节点调度会将上述分析结果调整为下面的样子,从而提供不错的性能增益。出于这个原因,默认情况下,Python插件设置为全局串行。因此,它们将被一个接一个地调度,并且不会阻塞等待GIL可用的多个线程。

集群 (Clusters):如前所述,如果 EG 包含节点级的循环依赖关系,那么这些节点将被分组成一个集群,这个集群表示一个单独的工作单元,并按顺序求值。虽然可以同时对多个集群进行求值,但大型集群会限制可同时执行的工作量。集群在分析器中被标识为 opaqueTaskEvaluation ,如下所示:

如果您的场景包含集群,请分析您的Rig结构,以了解为什么循环存在。理想情况下,你应该努力去除Rig各部分之间的耦合关系,这样才能独立的评估各个部件(如头部、身体等)。

提示:在排查场景性能问题时,可以使用每节点的冻结属性,临时禁用费时的节点。这样就会从EG中删除特定的节点。虽然你看到的结果会有改变,但这是检查场景瓶颈的简单方法。

渲染约束时的表现

以下是对一个具有很多动画网格的大场景放大到单一帧时的分析结果,由于物体的数量,材质的不同以及几何体的数量,这个场景的渲染成本非常高。

图示中有四个主要方面:

  • Evaluation (A)
  • GPUOverridePostEval (B)
  • Vp2BuildRenderLists (C)
  • Vp2Draw3dBeautyPass (D)

在这个场景中,大量的网格物体正在使用GPU 覆盖进行求值,并且一些分析块的显示方式与其他方式不同。

Evaluation: 区域 A 描述了计算Maya场景状态所花的时间。在这种情况下,场景求值达到了良好的并行状态。橙色和绿色块代表了 DG 节点的软件求值。黄色块则是通过 GPU 覆盖启动网格求值的任务事件。GPU上的网格求值从这些黄色块开始,并与CPU上的其他工作同时进行。

场景求值中出现并行瓶颈的时候是在求值部分中心的空白处。右侧的大量 GPU 覆盖 块依赖于场景的单个部分,必须等待其完成才能开始。

Area A2 (above area A):A区中蓝色的任务块,显示了VP2在场景求值的并行工作。在这个场景中,大部分的网格工作是由 GPU 覆盖的,所以它大部分是空的。在对网格进行软件求值时,该部分显示准备用于渲染的几何缓冲区。

GPUOverridePostEval:B区是GPU覆盖完成其部分工作的地方。 在此块中花费的时间量因不同的GPU和驱动程序组合而异。 在某些时候,如果GPU负载过重,则会等待GPU完成求值。 这一次可能会出现在这里,也可能会出现在 Vp2BuildRenderLists 部分。

Vp2BuildRenderList:C区,一旦场景求值完成,VP2将生存要渲染的对象列表。这一部分的时间通常与场景中的物体数量成正比。

Vp2PrepareToUpdate:区域C2,图表中非常小。 VP2维护着一个全局世界的内部副本,并使用它来确定在视口中绘制什么。 在渲染场景时,我们必须确保已修改VP2数据库中的对象以反映Maya场景中的更改。 例如,对象可能已经变得可见或隐藏,它们的位置或拓扑可能已经改变,等等。 这由VP2 Vp2PrepareToUpdate完成。

当形状拓扑,材质或对象可见性更改时,Vp2PrepareToUpdate速度较慢。 在这个例子中,Vp2PrepareToUpdate几乎不可见,因为场景对象只需要很少的额外处理。

Vp2ParallelEvaluationTask 是另一个可以出现在这个区域的分析块。如果在这里花费了时间,那么求值管理器的主要求值部分(A区)的一些求值将推迟到该区之后进行求值。本节的求值使用传统的DG求值。

在并行评估中, Vp2BuildRenderLists 或 Vp2PrepareToUpdate 的常见情况是:

  • 大量需渲染的对象 (如本例所示)
  • 网格拓扑发生变化
  • 对象类型,例如图像平面(image planes),需要在渲染之前进行传统的求值
  • 除非回调的第三方插件

Vp2Draw3dBeautyPass:D 区,一旦所有的数据都准备好了,就进入渲染场景环节,这就是实际的 OpenGL 或 DirectX 渲染发生的地方。根据视区效果,如深度剥落、透明模式和屏幕空间的抗锯齿效果,这个区域被分成多个小节。

Vp2Draw3dBeautyPass 出现慢的情况有:

  • 大量需渲染的对象 (如本例所示)
  • 使用了透明度:由于默认透明度算法使场景合并效果较差,因此大量透明对象的成本可能很高。 对于非常大量的透明对象,将透明度算法(在vp2设置中)设置为Depth Peeling而不是Object Sorting可能会更快。 切换到无纹理模式也可以绕过这个开销。
  • 使用许多材质:在VP2中,对象在渲染之前按照材质排序,因此,有很多不同的材质时,这个过程会非常耗时。
  • 使用视口特效:诸如SSAO(屏幕空间环境光遮挡 Screen Space Ambient Occlusion),景深,运动模糊,阴影贴图或深度剔除等许多效果都需要额外的处理。

其他因素:虽然上面描述的关键阶段适用于所有场景,但您的场景可能有不同的表现特征。

对于动画效果有限的静态场景,或不需要变形的动画对象,则使用合并来提高性能(如树、房屋等)。并且合并组的实例对象共享同样的材质,因为渲染的对象减少,可降低 Vp2BuildRenderLists 和 Vp2Draw3dBeatyPass 上的时间消耗。

保存和恢复图表数据

分析数据可在分析器窗口点击 Edit -> Save Recording... 或 Edit -> Save Recording of Selected Events... 菜单保存,以便随时。所有内容都存储为纯字符串数据(参见 附录中:分析器文件格式 一节的描述),这样您可以使用编辑器中的Edit -> Load Recording... 菜单来加载来自任何场景的分析数据。


排除场景故障

分析模式

分析模式的目的是对你的场景进行更严格的检查,从而捕捉求值中的错误。由于分析模式会增加场景运行中的计算开销,所以只适合在调试状态下使用该模式,日常工作中,动画师不应启用分析模式。请注意, 分析模式不是线程安全的,所以它仅限于串行(Serial)模式,在并行求值中不能使用分析模式。

分析模式的主要功能:

  • 对每个播放中的帧搜索错误:这与安全模式不同,它只是试图在并行执行开始时识别问题。
  • 监视节点属性的读取访问:确保节点在EG中具有正确的依赖结构。
  • 返回诊断结果,从而更好的了解哪些节点影响求值:目前仅限于一次报告一个目标节点。

提示:要激活分析模式,请使用 dbtrace -k evalMgrGraphValid; MEL命令。

禁用分析模式,可使用:dbtrace -k evalMgrGraphValid -off;

让我们假设你的场景包含以下三个节点。 由于依赖性, 评价管理器必须在计算 A 的状态之前计算节点 B 和 C 的状态。

现在让我们假设分析模式返回以下报告:

Detected missing dependencies on frame 56
{
     A.output <-x- B
     A.output <-x- C [cluster]
}
Detected missing dependencies on frame 57
{
    A.output <-x- B
    A.output <-x- C [cluster]
}

<-x- 符号表示缺失依赖的方向。[cluster] 术语表示该节点位于循环簇内,这意味着循环中的任何节点都可以负责求值顺序之外的属性访问。

在上面的例子中,B访问A的 output 属性,这是不正确的。这些类型的依赖关系不会出现在求值图中,并且在并行模式下运行求值可能导致崩溃。

发生缺失依赖的原因有很多,如何处理依赖关系取决于问题的原因。如果分析模式发现场景中的错误来自于不良依赖,则:

  • 用户自定义插件: 重新审视您在节点中管理脏传播的策略。确保任何使用 “clever” 的脏传播的尝试都会每次都脏位标记相同的属性。避免使用不同的通知消息来触发拉动计算属性。
  • 内置节点: 您应该把这些信息反馈给我们。这样可以突出显示我们不知道的错误。为了帮助我们更好的诊断此错误的原因,如果您能向我们提供导致问题的场景,我们将不胜感激。

图表执行顺序

显示图形执行顺序有两种主要方法。

最简单的方法是使用“计算”跟踪对象来获取计算顺序的记录。 如前所述,这只能在串行模式下使用。 计算跟踪的目标用于比较DG和EM求值结果,发现这两种模式之间的不同排序或缺失执行相关的任何求值差异。

请记住,自从EM执行从根向前的图形之后,运行之间会有很多差异,而DG使用树叶的值。 例如,在前面显示的简图中,EM确保B和C将在A之前进行求值,但不提供有关B和C相对顺序的信息。但是,在DG中,A将B和C中的输入拉入 由节点A的执行决定一致的顺序.EM可以显示“B,C,A”或“C,B,A”作为它们的求值顺序,尽管两者可能都是有效的,但用户必须决定它们是否相等 或不。 在调试周期计算中的问题时,这种信息排序可能更加有用,因为在两种模式下都会进行拉取求值,这将使排序更加一致。

求值工具包

这一组调试工具曾被当做Maya Bounus Tools的特定工具架使用,现在已经内置在Maya中。求值工具包可以查询和分析场景,以及具备激活或禁用各种模式的功能。需要了解更多功能请参阅随附的 求值工具包文档 。

已知限制

本节列出了新的求值系统的已知限制:

  • VP2 中的运动模糊会禁用并行求值:为了使运动模糊起作用,必须在不同的时间点对场景进行求值。目前EM不支持这一点。
  • 使用FBIK的场景会进入串行模式: 近几年来,Autodesk一直在弃用FBIK。 我们建议使用HIK作为全身的定位和解算。
  • dbtrace 命令不支持并行模式:分析模式部分所述,dbtrace命令仅适用于串行求值。 在并行模式下启用dbtrace可能会导致Maya崩溃。
  • DG分析器在并行模式小会造成崩溃:除非您处于DG求值模式,否则您将无法使用旧版DG分析器。 如果时间允许,我们希望将DG分析器的功能移植到新的集成了线程安全特性的分析器中。
  • 批量渲染带XGen的可能产生错误的结果。
  • 串行和并行模式下的求值管理器改变了属性缓存的方式:这样做是为了允许安全的并行求值,并防止多线程重新计算相同的数据。 这意味着如果在一个求值周期中出现同一属性的多个计算,则某些场景可能会有不同的求值结果。 通过求值管理器,第一个值将被缓存。
  • VP2直接更新不适用于polySoftEdge节点。

附录

分析器文件格式

分析器将记录的数据以可读的字符串形式进行存储。这个格式随着Maya的不断升级,也会有版本之间的区别,该文件格式支持向下兼容(向下兼容有一定不确定因素,即老版本的Maya导入新版本的分析器文件)。

下面是对V1版的格式描述,现在的版本是Maya2018。

首先,我们看看一个实际内容的案例:

1     #File Version, # of events, # of CPUs
2     2\t12345\t8
3     Main\tDirty
4     #Comment mapping---------
5*    @27 = MainMayaEvaluation
6     #End comment mapping---------
7     #Event time, Comment, Extra comment, Category id, Duration, \
          Thread Duration, Thread id, Cpu id, Color id
8*    1234567\t@12\t@0\t2\t12345\t11123\t36\t1\t14
9     #Begin Event Tag Mapping---------
10    #Event ID, Event Tag
11*   123\tTaggy McTagface
12    #End Event Tag Mapping---------
13    #Begin Event Tag Color Mapping---------
14    #Tag Label, Tag Color
15*   Taggy\tMcTagface\t200\t200\t13
16    #End Event Tag Color Mapping---------
EOF

下表通过引用前面的内容来描述文件格式结构:

行数 描述
1 包含一般文件信息名称的标题行
2 包含标题信息的制表符分隔行
3 包含事件使用的类别列表(类别 ID 是列表中的类别的索引)
4 指示注释映射开始的标题(从 ID 映射到它所表示的字符串)
5* 以@LINE = STRING的形式建立行数和字符串之间的映射关系。该 ID 不对应文件之外的任何东西。
6 映射结束的注释
7

表示事件信息开始的标题。 名称是事件列的标题。

  • Event time 记时周期数内的绝对时间,表示事件的起始时间
  • Duration 表示整个事件的总计算时间
  • Thread duration 表示该事件所处的线程的总计算时间
  • Comment and Extra comment 使用上面注释映射的ID
  • Category id 是第3行列表中事件类别的索引
  • Cpu id and Thread id 是事件发生的地方。实际值是随机的,只是为了区分是哪个CPU核心和线程。
  • Color id 是应用程序内部颜色映射的索引(颜色数据不存储在文件中)。
8* 零或多个制表符分隔线映射到存储在文件中的所有事件
9 指示事件标签映射表开始的地方
10 标题行显示事件标签映射列中的值
11* 零个或多个标签分隔行,通过分析器工具定义的事件标签到特定的事件 ID。 事件 ID 将与注释映射部分给出的 ID 相对应。
12 事件标签映射结束的注释
13 标示事件标签颜色映射开始的标题
14 标题行显示事件标记颜色映射列中的值
15* 零个或多个标签分隔行映射上面定义的标签定义到 r, g, b 颜色值
16 标示事件标记颜色映射结束的标题
EOF

 

版本2是一个关于4个 CPU的案例,其中包含一个”ETName”的事件, 描述”ETCategory”, 在”ETCategory”类别中, 使用颜色索引7,持续时间为100秒,从计时周期数999开始,在一个带有 ID 为22的线程上, 标有”TagMe”的红色值(25500)

#File Version, # of events, # of CPUs
2   1   4
ETCategory
Category description
#Comment mapping---------
@0 = ETName
#End comment mapping---------
999 @0  @0  1   100 100 22  1   7
#Begin comment description mapping---------
@1 = ETDescription
#End comment description mapping---------
#Begin Event Tag Mapping---------
#Event ID, Event Tag
1   TagMe
#End Event Tag Mapping---------
#Begin Event Tag Color Mapping---------
#Tag Label, Tag Color
TagMe   255 0 0
#End Event Tag Color Mapping---------

调试命令

这些命令可用来显示您的场景信息,从而辅助调试和优化。这是一些比较常见的摘要,仅代表可用的运行时信息。 请参阅Maya在线技术文档中的命令文档以获取有关每个命令的更多信息。

dbcount

Maintains embedded code location counters for higher-level debugging of scene operation. Generally, this uses specialized code that is only available in custom builds.

Synopsis: dbcount [flags]
Flags:
   -e -enabled      on|off
   -f -file         String
   -k -keyword      String
   -l -list        
  -md -maxdepth     UnsignedInt
   -q -quick       
   -r -reset       
   -s -spreadsheet 

Command Type: Command

dbmessage

监控添加和删除DAG和DG节点的信息。

Synopsis: dbmessage [flags]
Flags:
   -f -file     String
   -l -list    
   -m -monitor  on|off
   -t -type     String

Command Type: Command

dbtrace

Turns on conditional code, typically to print out status information or to take different code paths when enabled.

To find available trace objects use dbtrace –q to list currently-enabled traces, and dbtrace –q –off to list currently-disabled traces.

See below for information on specific keywords.

Note: Work is currently in progress to make these trace objects more flexible. It is a current design constraint that sometimes they are visible in a release, even though they only function internally, and some cannot be used when using Parallel evaluation.

Synopsis: dbtrace [flags]
Flags:
   -q -query
   -f -filter   String
   -i –info
   -k -keyword  String (multi-use)
              (Query Arg Optional)
   -m -mark    
   -o -output   String
 -off -        
   -t -title    String
  -tm -timed    on|off
   -v -verbose 

Command Type: Command
Keyword Description Contents(Default Output File)
cipEM  Shows what Customer Improvement Program data is being collected.  Generic usage information. No longer being used (n/a)
 cmdTracking  Enables the tracking of counts of commands. Use the dbpeek ‘cmdTracking’ operation to view the results.  No output, but enables tracking of the counts for all commands being executed. (For example, you can turn it on during file load to get a count of the number of createNode calls, including those in referenced files, a task that is difficult to do manually) (n/a)
 compute  High level trace of the compute path  Nested output showing compute methods being called. Typically in EM mode you should see nesting only in cycles. DG mode will show the full set of nodes triggered by a single evaluation request (_Trace_Compute.txt)
 dbCache  Data block manipulation  Details of the creation and manipulation of datablock information (_Trace_DataBlockCache.txt)
 deformerEvaluator  Statistics for the deformer evaluator setup  Shows statistics on what the deformer evaluator was able to ingest, once enabled (cerr)
evalMgrGraphCreation Internal use only (n/a)
evalMgrGraphSched Internal use only (n/a)
evalMgrGraphValid Evaluation manager execution graph validation errors and warnings Nodes that were evaluated while in EMS mode using the pull (DG) model. This indicates missing dependencies in the evaluation graph, possibly caused by custom dirty propagation (_MayaEvaluationGraphValidation.txt)
evalMgrSched Internal use only (n/a)
idleBuild Operation of the idle build mechanism for the evaluation graph When the idle build is active, this appears when the idle build is triggered and executed (_Trac_EGBuild.txt)
nodeTracking Enables tracking of counts of created nodes. Use the dbpeek ‘nodeTracking’ operation to view results. (n/a)
peekData Shows progress of the dbpeek -op data operation Dumps data collected by the dbpeek operation, and how (_Trace_DbPeekData.txt)
peekMesh Shows progress of the dbpeek -op data operation Dumps data collected by the dbpeek operation, and with what flags (_Trace_DbPeekMesh.txt)

dgdebug

Historical debugging command; not robust or documented. Deprecated: Use the newer dbpeek command.

No help is provided for this command.

dgdirty

Forces dirty/clean states onto specified plugs and everything downstream from them. Meant to be a safety net for restoring proper states to your scene when something has gone wrong.

You should not need to use this command, but it will continue to exist as a “reset button”, just in case.

Synopsis: dgdirty [flags] [String...]
Flags:
   -q -query
   -a -allPlugs    
   -c -clean       
   -i -implicit    
   -l -list         String
   -p -propagation 
  -st -showTiming  
   -v -verbose     

Command Type: Command

dgeval

Forces the node to compute certain plugs. Like dgdirty, this command is meant to be a safety net if computation has not occurred in the proper order. Similar in function to the getAttr command, but since it returns no results, it can handle all attribute types, not only those supported by getAttr.

Synopsis: dgeval [flags] String...
Flags:
 -src -        
   -v -verbose 

Command Type: Command

dgInfo

Dumps information about the current state of the graph. Be aware that when plug dirty states are reported, they represent the connection associated with the plug. In fan-out or in-out connections there will be more than one dirty state associated with the connection attached to the plug. This means it is legal to see A->B as dirty but B->A as clean if A has multiple connections. Being Deprecated: Use the newer dbpeek command.

Synopsis: dgInfo [flags] [String...]
Flags:
 -all -allNodes     
   -c -connections  
   -d -dirty         on|off
   -n -nodes        
  -nd -nonDeletable 
  -nt -type          String
  -of -outputFile    String
   -p -propagation   on|off
   -s -short        
 -sub -subgraph     
  -sz -size         

Command Type: Command

dgmodified

Checks on the reason a file requests saving when no changes have been made.

Synopsis: dgmodified

No Flags.

dbpeek

This command is called out intentionally, as it combines multiple operations into a single command by use of various operations.

It runs one of several operations that provide a view into the data internals in the scene. This is the most useful and flexible of the debugging commands, and new variations of it are often being introduced. Use dbpeek -q -op to show a list of currently available operations and dbpeek -op X -q to show detailed help for operation X.

See below for information on specific keywords.

Note: The syntax of the argument flag allows for both keyword argument=’key’ and keyword/value argument=’key=value’ forms.

Synopsis: dbpeek [flags] [String...]
Flags:
   -q -query
   -a -argument         String (multi-use) (Query Arg Mandatory)
 -all -allObjects      
   -c -count            UnsignedInt
  -eg -evaluationGraph 
  -of -outputFile       String
  -op -operation        String (Query Arg Optional)

Command Type: Command

dbpeek -op attributes

Analyzes node or node-type attributes and dumps information about them based on what the selected operation type.

Various arguments to the operation change the content of the output. The essence remains the same; the attributes belong to the node or node type.

Argument Meaning
detail Adds all internal details from attributes being dumped, otherwise dumps only the names and structure. The details are output as object members of the attribute, including the children.
nodeType Dumps all attributes belonging to the selected node(s) types. If nothing is selected, it dumps the attributes for all available node types. This includes all node types up the hierarchy to the base node class.
noDynamic Skips dynamic attributes in all output.
noExtension Skips extension attributes in all output.
noStatic Skips static attributes in all output.
onlyPlugins Restricts any output to nodes and node types that originate from a plug-in.
type=affects Dumps attribute structure and affects relationships in the graphical .dot format.
type=detail Dumps attribute information in .json format. This is the default if no type is specified.
type=validate  Validates flags and structure for consistency and validity.

 

If no nodes are selected, then this command prints the list of all attributes on all nodes. For example, if you had a node type called reversePoint with a vector input and a vector output.

type=detail would output this JSON data:

{
  "nodes" :
  {
    "reversePoint" :
    {
      "staticAttributes" : [
        { "pointInput" : [
            "pointInputX",
            "pointInputY",
            "pointInputZ",
          ]
        },
        { "pointOutput" :
          [
            "pointOutputX",
            "pointOutputY",
            "pointOutputZ",
          ]
        }
      ],
      "extensionAttributes" : []
    }
  }
}

type=affects would output this DOT data:

digraph G
{
    compound=true;
    subgraph cluster_NODENAME
    {
        label="Node NODENAME, Type NODETYPE";
        color=".7 .0 .0";
        ia [label="ia/inputAttribute",style="rounded",shape=ellipse];
        oa [label="oa/outputAttribute",style="rounded",shape=rectangle];
        ia -> oa;
    }
}

and type=validate would output this JSON validation summary:

{
  "Attribute Validation" :
  {
    "NODENAME" :
    {
      "staticAttributes" :
      [
        {
          "Both input and output attributes in compound" :
          [
            { "root" : "rootAttribute",
              "inputs" : ["inputChild"],
              "outputs" : ["outputChild"],
            }
          ]
        }
      ]
    }
  }
}

dbpeek -op cmdTracking

By default, when no detail argument is present it shows a list of all commands run since the last reset as well as a count of how many of each type were executed.

Outputs in command/count pair form, one per line, with a tab character separating them.

Argument Meaning
reset Set all of the command tracking statistics to zero

 

dbpeek -op connections

By default, when no type argument is present, shows a list of all connections in the DG.

Argument Meaning
summary Reduces the output to show only the connection counts on the nodes. It separates by single and multi but no further information is added. Useful for getting basic usage information.
verbose  Shows extra information about every connection, including dirty/propagation states, plug ownership, and type connectivity of the connection. Connections can be single or multi, and be connected either to each other or to plugs.

 

dbpeek -op data

Dumps the current contents of a node’s plug data in a standard format. By default the output is in CSV format consisting of 5 columns: NODE PLUG DATA_TYPE CLEAN_STATE DATA_AS_TEXT

Example for a simple integer attribute with a dirty value of 5: MyNode MyPlug Int32 0 5

Argument Meaning
eval Evaluates plugs first to guarantee that they are clean. Note: Some plugs are always dirty so there may still be plugs that show a dirty value.
full Includes plugs with default values in the output.
json Uses JSON format for the output. The general form is { "NODE" : { "PLUG" : { "TYPE", "CLEAN", "VALUE" } } }. For example, a simple numeric attribute with a dirty value of 5 { "MyNode" : { "MyPlug", "0", "5" } }
matrix Includes all plugs with a “matrix” data type in the output. This does not include generic data that may have a matrix value at runtime, only attributes that are exclusively matrix types.
number Includes all plugs with any numerical data type in the output. This does not include any generic data that may have numerical value at runtime, only attributes that are exclusively numeric types. It includes all types of numeric values, including linear, angular, time, and unitless values.
state Includes the current dirty state of the data in the output.
time=TIME Rather than evaluating at the normal context, evaluates at a context using the given time. This is somewhat equivalent to getAttr -t TIME.
vector  Rather than evaluating at the normal context, evaluates at a context using the given time. This is somewhat equivalent to getAttr -t TIME.

dbpeek -op context

Analyzes context evaluation to detect various errors violating the design.

Argument Meaning
isolationType=animatedAttributes Filters errors, reporting only those involving animated attributes
isolationType=animatedNodes Filters errors, reporting only those involving animated nodes
isolationType=staticAndAnimated Reports all errors
test=isolation During evaluation, detects when evaluation context is violated causing data to be read or written into a state that belongs to some other evaluation context
test=correctness Evaluates the scene in the background, comparing evaluation data stored for background and main context; compares traversing evaluation graph visiting nodes only if all upstream nodes generate equivalent data in both the background and the main context
time=TIME Takes a string value indicating the frame time at which evaluation should be performed.
verbose  Adds extra information to output report. Each test will have its own verbose data. Isolation: Adds callstack information to the report for each detected error. Correctness: Adds attributes which compare failed to compare (due to missing logic)

 

Sample output for isolation tests:

{
    "context isolation": {
        "frame": 5.0,
        "type": "animatedNodes",
        "verbose": true,
        "errors": [
            {
                "node": "ikHandle1",
                "type": "ikHandle",
                "attribute": "ikFkManipulation",
                "call stack": [
                    "METHOD Line NUMBER",
                    "METHOD Line NUMBER",
                    "METHOD Line NUMBER"
                ]
            },
            {
                "node": "shape",
                "type": "mesh",
                "attribute": "displaySmoothMesh",
                "call stack": [
                    "METHOD Line NUMBER",
                    "METHOD Line NUMBER",
                    "METHOD Line NUMBER"
                ]
            }
        ],
        "time out": true
    }
}

Sample output for correctness tests:

{
    "context correctness": {
        "frame": 14.0,
        "verbose": true,
        "errors": [
            {
                "node": "IKSpineCurveShape",
                "type": "nurbsCurve",
                "attributes": [
                    "worldSpace"
                ]
            }
        ],
        "failed to compare": [
            "input",
            "clusterXforms",
            "clusterTransforms",
            "target",
            "mySpecialAttribute"
        ],
        "time out": true
    }
}

dbpeek -op edits

Shows a list of all nodes for which tracking is currently enabled. The “track” flag is mandatory.

Argument Meaning
track Shows a list of all nodes for which tracking is currently enabled.

 

dbpeek -op evalMgr

Outputs the current state of all of the custom evaluators used by the Evaluation Manager.

Argument Meaning
custom Outputs the custom evaluators registered with the evaluation manager.
global Adds output that is independent of scene contents, for example, node types enabled for the custom evaluators.
local Adds output that is specific to the scene contents, for example, nodes supported by a custom evaluator.

 

dbpeek -op graph

Gets a list of nodes or connections from either the dependency graph or the underlying evaluation graph.

Argument Meaning
connections Dumps the list of all connections in the chosen graph. The sorting order is alphabetical by destination plug name.
dot Dumps the graph information in .dot format for parsing and display by an external application such as graphViz.
evaluationGraph Gets the structure information from the evaluation graph, otherwise uses the raw dependency graph. The dbpeek command flag “evaluationGraph” does the same thing.
graph Dumps the graph state and contents, not including what is dumped by any of the other flags.
nodes Dumps the list of all nodes in the chosen type of graph, in alphabetical order by full node name.
plugs For the evaluation graph option, dumps the list of all plugs in its dirty plug list in the evaluation nodes. For the DG option, dumps the list of plugs currently in the plug trees.
scheduling Dumps the scheduling type used for all nodes in the type of graph in the form NODE = SCHEDULING_TYPE. If a node type is specified, the default scheduling type for nodes of that specific node type is returned in the same format.
verbose  When dumping the scheduling graph in .dot format, adds all of the names of the nodes to the clusters. Otherwise, it is only a count of nodes in each cluster

dbpeek -op mesh

Dumps the current contents of the mesh to a standard format. There are two types of formatting and two levels of detail to present.

Argument Meaning
eval Evaluates mesh plugs first to guarantee they are clean. Otherwise the values currently present in the mesh shape are used as-is.
json Dumps data in JSON format instead of CSV.
verbose Puts full values for all of the data in the output. Otherwise, only a number count of each type is returned. See the flag descriptions for more information on which data can be requested and what is returned for each type.
vertex  Includes vertex position or vertex count in the output. The short return is a count of vertices in the mesh. The verbose values are a list of vertex number and the {X,Y,Z} positions of the vertex, with W factored in, if appropriate.

 

For the default level of detail, the default CSV format output will look like this:

NODE_NAME,DATA_TYPE,DATA_COUNT

For example, a cube containing 32 vertices would have these lines:

Node,DataType,Count
pCubeShape1,outMesh,32

The JSON equivalent format would look like this:

{
   "pCubeShape1" : {
       "outMesh" : "32"
    }
}

If the full detail is requested, then the (abbreviated) output for CSV format will look like this:

Node,Plug,Clean,Value
pCubeShape1,outMesh[0],1,0.0 0.0 0.0
pCubeShape1,outMesh[1],1,0.0 0.5 0.0
...
pCubeShape1,outMesh[32],1,1.0 1.0 1.0

and like this for JSON format:

{
 "pCubeShape1" : {
    "outMesh" : {
      "clean" : 1,
      "0" : { ["0.0", "0.0", "0.0"] },
      "1" : { ["0.0", "0.5", "0.0"] }
      ...
     "32": { ["1.0", "1.0", "1.0"] }
   }
 }
}

dbpeek -op metadata

Shows node metadata. The default operation shows a list of all nodes containing metadata.

Argument Meaning
summary Shows a single line per node, with metadata indicating how many channels, streams, and values are present in the metadata.
verbose  Shows a detailed list of all metadata on nodes, including a dump in the debug serialization format for each of the metadata streams.

 

dbpeek -op node

Show select debugging information on DG nodes. See also the “plug” and “connection” operations for display of information specific to those facets of a node. If no arguments are used then the ones marked as [default] will all be enabled, for convenience.

Argument Meaning
datablock [default] Shows the values in the datablock(s)
datablockMemory Shows raw datablock memory. This is independent of the other other datablock flags.
dynamicAttr Shows dynamic attributes.
evaluationGraph [default] Includes evaluation graph information on the node
extensionAttr Shows the extension attributes
node [default] Shows information specific to individual node types, such internal caches, flags, or special relationships it maintains. All other data shown is common to all node types
plug [default] Shows the nodes plug information
skipClean Does not include datablock values that are clean
skipDirty  [default] Does not include the datablock values that are dirty
skipMulti  Does not include the datablock values that are multi (array) attributes
staticAttr  Shows the static attributes
verbose  Shows much more detail where available. This will include things such as flags set on objects, full detail on heavy data, and any extra detail specific to a node type, such as caches.

 

dbpeek -op nodes

By default, when no detail argument is present, shows a list of all currently registered node types.

Argument Meaning
binary Also includes the IFF tag used to identify each node type in the “.mb” file format

 

dbpeek -op nodeTracking

By default, when no argument is present, shows a list of all nodes created since the last reset along with a count of how many of each type were created. Output is in the form of nodeType/count pairs, one per line, with a tab character separating them.

Argument Meaning
reset Erases all of the node tracking statistics.

 

dbpeek -op plugs

Shows information about all of the plugs in a scene. By default, when no argument is present, shows static plug footprint. A lot of this is only displayed in specially-instrumented builds, and generally only of use internally.

Argument Meaning
details Includes the full plug/node name information in the output. Otherwise only the total and summary counts are dumped.
group=stat Groups all output by statistic name
group=node Groups all output by node name
mode=footprint Reports size information for currently-existing networked plugs.
mode=usage Reports dynamic code path statistics, if they have been enabled in the current build
mode=reset When used in conjunction with “usage”, resets the statistics back to zero.
mode=state Gets unevaluated state information for boolean plugs. Only available on specially-built cuts.
nodeType=TYPE Restricts the operation to the node types specified in the argument. This includes inherited types, for example if the value is “transform”, then the operation also applies to “joint” nodes, as the node type “joint” inherits from the node type “transform”. See the node type documentation or the nodeType command for complete information on which node types inherit from each other.
stat=STAT  If this argument has no STAT, then sorts by the name of the statistic. If this argument does have a STAT, for example, “stat=addToNet”, then only reports that statistic. Only available on specially-built cuts.

 


修订记录


2018

2017

2016 Extension 2

  • 添加关于“控制器”命令的提示。
  • 更新“自定义求值器”部分中的“其他求值器”子部分,以描述新的求值器。
    • 新的求值器:
      • transformFlattening
      • reference
    • 动力学求值器默认为启用状态。
    • 动力学求值器具有默认禁用的新选项,以支持有动力学的场景的并行求值。
    • 更新“自定义求值器”部分的“求值器冲突”段落。
  • 更新Python插件调度到全局串行。
  • 更新“分析您的场景”部分的“渲染约束表现”段落。
  • 为图形示例添加了新图像。
  • 其他错别字修正和小的更正。

2016

  • 文档的初始版本。

发表评论

电子邮件地址不会被公开。 必填项已用*标注