ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

OpenUSD 资产校验框架(UsdValidation)完全指南:从核心概念到自定义验证器开发

OpenUSD 资产校验框架(UsdValidation)完全指南:从核心概念到自定义验证器开发 OpenUSD 资产校验框架UsdValidation完全指南从核心概念到自定义验证器开发【免费下载链接】OpenUSDUniversal Scene Description项目地址: https://gitcode.com/GitHub_Trending/ope/OpenUSDOpenUSDUniversal Scene Description的 Validation 框架为资产校验提供了一套统一机制用于验证核心规则core rules、Schema 规则schema rules以及通过插件提供的客户端自定义规则确保资产在不同 USD 工作流之间保持健壮与可互换。本指南以pxr/usdValidation/usdValidation/README.md为骨架结合仓库源码系统讲解 Validator、Registry、Context、Error、Fixer 五大核心抽象并给出 C 与 Python 两种自定义验证器的完整开发实战。框架概述与核心抽象Validation 框架位于 pxr/usdValidation 目录入口文档为 pxr/usdValidation/README.md详细文档见 pxr/usdValidation/usdValidation/README.md。框架的职责是校验资产是否符合核心规则与 Schema 规则保证资产在不同 USD 工作流间可靠交换。框架由五个核心实体组成分工如下实体职责UsdValidationValidator单个校验测试。一次运行可产生零个或多个具名校验错误例如usdValidation:CompositionErrorTest可能同时检测多种合成错误并逐一返回UsdValidationValidatorMetadata验证器的元数据名称、插件指针、关键字、文档、Schema 类型等UsdValidationRegistry集中管理所有验证器与验证器套件Suite的单例注册表UsdValidationContext校验执行上下文负责并行调度一组验证器UsdValidationError/UsdValidationFixer校验结果错误与修复动作修复器从源码结构看validator.h元数据结构UsdValidationValidatorMetadata直接对应plugInfo.json中可声明的字段是整个插件化体系的数据契约。验证器元数据UsdValidationValidatorMetadata每个 Validator 实例都携带元数据字段如下name验证器名称。插件内定义的验证器必须采用插件名:验证器名格式例如usdGeomValidators:StageMetadataChecker。这种全限定命名保证了插件提供验证器名称的唯一性。pluginPtr指向定义插件验证器的插件。用于按需动态加载插件验证器如果验证器是显式创建Explicit Validators该字段为nullptr。该元数据由注册流程隐式处理自定义验证器开发者无需提供。keywords与验证器关联的关键字可用于过滤/分组。doc说明验证器用途的文档字符串。schemaTypes验证器关联的 Schema 类型如有。isTimeDependent验证器测试的规则是否随时间变化。只有 Prim 验证器和 Stage 验证器可以为时间依赖只有它们能求值时变属性默认false对时间依赖属性仍建议优先使用 Prim 验证器。isSuite验证器是否代表一个验证器套件。name与doc是必填字段见 validator.h 源码注释。验证器、套件与注册表RegistryUsdValidationValidator单个测试的载体UsdValidationValidator描述单个测试validator.h。每个实例包含三种测试任务之一UsdValidateLayerTaskFn对给定SdfLayerHandle执行校验UsdValidateStageTaskFn对整个UsdStage执行校验UsdValidatePrimTaskFn对单个UsdPrim执行校验。源码中三种任务函数定义为std::function别名validator.husing UsdValidateLayerTaskFn std::functionUsdValidationErrorVector( const SdfLayerHandle ); using UsdValidateStageTaskFn std::functionUsdValidationErrorVector( const UsdStagePtr , const UsdValidationTimeRange); using UsdValidatePrimTaskFn std::functionUsdValidationErrorVector( const UsdPrim , const UsdValidationTimeRange);验证器实例不可变immutable、不可拷贝non-copyable且一旦注册进 Registry 就在整个 USD 会话期间永生immortal由注册表统一管理生命周期。UsdValidationValidatorSuite验证器套件UsdValidationValidatorSuite将一组验证器打包成套件方便客户端按业务概念批量使用validator.h。要点注册套件时必须在元数据中设置isSuite: true否则套件不会被注册并给出警告套件的isTimeDependent元数据是空操作no-op套件持有的验证器指针始终有效因为其生命周期由更高作用域的 Registry 管理套件可以像单个验证器一样携带 keywords用于上下文过滤。UsdValidationRegistry中心注册表UsdValidationRegistry是所有验证器的中央注册表registry.h通过UsdValidationRegistry::GetInstance()获取单例。其关键特性单例且永生模板特化删除了DeleteInstance()registry.h保证所有注册的验证器在整个应用生命周期内可用线程安全查询元数据、注册新验证器、检索已注册验证器均设计为线程安全内部使用std::shared_mutex统一注册核心 USD 验证器与客户端验证器都注册于此按元数据检索支持通过 name、keywords、schemaTypes、pluginName 查询验证器元数据并可按需加载插件验证器。注册表的主要查询 API均不会触发插件加载除非显式使用GetOrLoad*系列HasValidator(name)/HasValidatorSuite(name)检查是否已注册GetOrLoadValidatorByName(name)/GetOrLoadValidatorsByName(names)/GetOrLoadAllValidators()按名加载缺失时触发插件加载GetOrLoadValidatorSuiteByName(name)/GetOrLoadAllValidatorSuites()加载套件GetValidatorMetadataForKeyword(keyword)/GetValidatorMetadataForKeywords(keywords)/GetValidatorMetadataForSchemaType(schemaType)/GetValidatorMetadataForSchemaTypes(schemaTypes)/GetValidatorMetadataForPlugin(pluginName)/GetValidatorMetadataForPlugins(pluginNames)/GetAllValidatorMetadata()按元数据过滤不加载插件。注册 API 分为插件注册与显式注册两组每组按 Layer/Stage/Prim 任务函数重载均支持可选std::vectorUsdValidationFixerRegisterPluginValidator(name, taskFn, fixers)、RegisterPluginValidatorSuite(name, validators)插件式注册不发送DidRegisterValidator通知RegisterValidator(metadata, taskFn, fixers)、RegisterValidatorSuite(metadata, validators)显式注册成功后全局广播UsdValidationNotice::DidRegisterValidator通知。从 registry.h 可看到注册表初始化时通过_PopulateMetadataFromPlugInfo()解析所有plugInfo.json构建_validatorNameToMetadata、_keywordToValidatorNames、_schemaTypeToValidatorNames、_pluginNameToValidatorNames四个索引结构这就是插件验证器元数据在启动时即可被枚举的原理。框架自带的三个核心验证器框架在 coreValidators.cpp 中通过TF_REGISTRY_FUNCTION(UsdValidationRegistry)注册了三个核心验证器名称 token 见 validatorTokens.h验证器名任务类型校验内容错误名usdValidation:CompositionErrorTestStage遍历stage-GetCompositionErrors()将每个 Pcp 合成错误转为CompositionErrorCompositionErrorusdValidation:StageMetadataCheckerStage检查defaultPrim是否有效或缺失MissingDefaultPrimusdValidation:AttributeTypeMismatchPrim检查属性类型与属性栈中 spec 声明类型是否一致AttributeTypeMismatch三个核心验证器共用关键字UsdCoreValidators见 validatorTokens.h。此外各 Schema 插件也提供了大量验证器例如 usdGeomValidators/validators.cpp 中的 Stage 元数据验证器会检查metersPerUnit与upAxis是否显式设置以及 GeomSubset 系列验证器等是自定义验证器的最佳参考范本。执行校验UsdValidationContext 与 Validate 流程单个验证器可以直接通过UsdValidationValidator::Validate()运行Layer/Stage/Prim 三个重载但更常见的是用UsdValidationContext管理一组验证器并行执行context.h。构建 Context 的六种方式构造函数选择验证器依据UsdValidationContext(keywords, includeAllAncestorstrue)具有指定关键字的验证器含匹配关键字的套件UsdValidationContext(plugins, includeAllAncestorstrue)属于指定插件的验证器含属于插件的套件UsdValidationContext(metadata, includeAllAncestorstrue)指定元数据对应的验证器isSuite为 true 的元数据会展开套件UsdValidationContext(schemaTypes)指定 Schema 类型及所有祖先 TfType的验证器UsdValidationContext(validators)显式传入验证器指针向量UsdValidationContext(suites)显式传入套件指针向量includeAllAncestors 的语义当使用 keywords 或 metadata 构造器时includeAllAncestors默认true。例如若发现针对UsdGeomSphereSchema 类型的验证器其祖先 Schema 类型UsdGeomGprim、UsdGeomImageable等关联的验证器也会一并纳入 ContextREADME.md 及 context.h。这保证了基类规则始终覆盖派生类型。Validate 方法族与并行调度UsdValidationContext::Validate()提供针对 layer、stage、prims向量或UsdPrimRange的重载并支持谓词控制遍历Stage 重载可接受Usd_PrimFlagsPredicate控制 stage 遍历范围默认重载使用 Instance Proxy predicatecontext.h时间范围接受UsdValidationTimeRange默认使用GfInterval::GetFullInterval()-inf 到 inf时间码列表接受std::vectorUsdTimeCode此时非时间依赖验证器只运行一次时间依赖验证器在每个时间码上运行空列表则不做任何校验。内部实现context.h将选中的验证器分发到_layerValidators、_stageValidators、_primValidators与_schemaTypeValidators四个集合通过WorkDispatcher将任务投递到共享的 TBB 线程池并行执行。对于 Schema 类型验证器typed schema 通过IsAschemaType判断applied schema 通过appliedAPISchemas判断。生命周期约定校验可能触发 stage 遍历调用方必须保证被校验的 stage/layer/prim 在校验任务生命周期内存活。返回的UsdValidationError中的 error sites 会引用 stage/layer因此错误向量仅在对象仍有效时可用README.md。校验错误UsdValidationError与修复器UsdValidationFixer错误的信息构成运行校验后返回UsdValidationErrorVector即std::vectorUsdValidationError。每个错误包含error.hName验证器作者为错误提供的名字如MissingDefaultPrimIdentifier用于区分不同验证器产生的相似错误。插件验证器格式为插件名:验证器名.错误名显式验证器格式为验证器名.错误名无错误名时标识符即验证器名。该标识符由GetIdentifier()基于验证器名与错误名构造error.hError typeUsdValidationErrorType枚举表示严重程度None无错误默认构造的 Error 即表示无错误、Error实际错误、Warn警告、Info信息Error sites一个或多个报告位置。错误可报告在SdfLayer如 layer 元数据、UsdStage如 stage 元数据、stage 内的 prim 或 prim 的属性上error.h。UsdValidationErrorSite提供IsValidSpecInLayer()、IsPrim()、IsProperty()、GetPrim()、GetProperty()等便捷方法并支持与SdfPath、layer/stage 联合使用Message验证器作者提供的详细错误消息GetValidator()产生该错误的验证器GetFixers() 系列方法与该错误关联的修复器Error DataVtValue类型由验证器附带、传递给客户端或供关联 Fixer 使用的附加数据。例如验证器测试属性值是否达标时可将符合要求的值放入 error data供 Fixer 更新属性。修复器UsdValidationFixerUsdValidationFixer表示可应用于修复特定校验错误的修复动作fixer.h。设计要点修复器与特定验证器关联可绑定特定错误名也可对该验证器的所有错误通用修复器包含name在同一验证器内必须唯一否则构造时报 coding error、description、keywords用于按部门、剧集等过滤/分组、FixerImplFn执行修复与FixerCanApplyFn判定能否应用修复框架不会自动应用修复器。调用方必须自行通过UsdValidationFixer::CanApplyFix()与ApplyFix()在客户端提供的UsdEditTarget上修复错误README.mdUsdValidationRegistry不直接管理修复器修复器由各自的UsdValidationValidator持有。错误对象本身也提供GetFixers()、GetFixerByName()、GetFixersByErrorName()、GetFixerByNameAndErrorName()、GetFixersByKeywords()等查询入口error.h。创建自定义验证器C 篇自定义验证器可通过 OpenUSD 插件基础设施创建插件验证器支持懒加载或通过UsdValidationValidator与UsdValidationRegistryAPI 显式创建注册显式验证器。粒度选择原则自定义验证器必须实现一个任务函数UsdValidateLayerTaskFn、UsdValidateStageTaskFn或UsdValidatePrimTaskFn并在注册时传入。应选择最合适的粒度如果校验逻辑可以简洁地定义为针对单个 prim应实现UsdValidatePrimTaskFn而非 Stage/Layer 任务函数粒度过粗会损害性能——例如只需在 prim 级别运行却实现为 stage 任务每次运行都会引发不必要的 stage 遍历当 prim 级验证器仅适用于特定 Schema 类型的 prim 时务必设置schemaTypes元数据框架会跳过不匹配的 prim避免无谓的验证器调用。插件式验证器Plugin Validators插件式验证器的元数据声明在插件的plugInfo.json中。示例{ Plugins: [ { Info: { Validators: { keywords : [commonKeyword], Validator1: { doc: Validator that has test for imageable Gprims., schemaTypes: [ UsdGeomImageable ], keywords: [ UsdGeomImageable, keyword1 ] }, ValidatorSuite1: { doc: Suite of validators, keywords: [suite], isSuite: true } } }, LibraryPath: PLUG_INFO_LIBRARY_PATH, Name: newValidatorPlugin, ResourcePath: PLUG_INFO_RESOURCE_PATH, Root: PLUG_INFO_ROOT, Type: library } ] }注意插件级额外keywords条目会追加到该插件定义的所有验证器上。插件内注册代码使用TF_REGISTRY_FUNCTION(UsdValidationRegistry)宏插件加载时自动执行TF_REGISTRY_FUNCTION(UsdValidationRegistry) { UsdValidationRegistry registry UsdValidationRegistry::GetInstance(); const TfToken validatorName(newPlugin:Validator1); // Create our validator UsdValidateStageTaskFn here const UsdValidateStageTaskFn stageTaskFn [](const UsdStagePtr usdStage, const UsdValidationTimeRange timeRange) { UsdValidationErrorVector errors; // ...Validator test logic here, accessing usdStage as needed, // creating errors as needed... return errors; }; registry.RegisterPluginValidator(validatorName, stageTaskFn); // Register the validator suite to include the validator we just registered const TfToken suiteName(newPlugin:ValidatorSuite1); const std::vectorconst UsdValidationValidator * containedValidators registry.GetOrLoadValidatorsByName({ validatorName }); registry.RegisterPluginValidatorSuite(suiteName, containedValidators); }注意UsdValidationError实例通常由校验任务函数创建并返回。显式验证器Explicit Validators显式验证器需要手动构造UsdValidationValidatorMetadata并调用UsdValidationRegistry::RegisterValidator()const UsdValidateStageTaskFn explicitStageTaskFn [](const UsdStagePtr usdStage, const UsdValidationTimeRange timeRange) { UsdValidationErrorVector errors; // ...Validator test logic here... return errors; }; const UsdValidationValidatorMetadata explicitValidatorMetadata { TfToken(ExplicitValidator), // ...other metadata fields... }; registry.RegisterValidator(explicitValidatorMetadata, explicitStageTaskFn);选择注册路径显式Explicit插件Plugin元数据来源调用方提供ValidatorMetadataplugInfo.json可发现性仅注册代码运行后可见启动时元数据即可见验证器懒加载懒加载否每个会话必须注册是首次按名查询时加载适用场景原型、一次性脚本、测试、运行时生成的规则在分发插件中发布验证器如果需要其他代码在验证器加载前查询其元数据keywords、schemaTypes请使用插件注册如果验证器是动态创建的或仅由创建者使用显式注册更简单。添加修复器FixersRegisterPluginValidator()与RegisterValidator()均可选接受std::vectorUsdValidationFixer。每个修复器指定名称、描述、FixerCanApplyFn与FixerImplFn、关键字列表以及可修复的错误名。工具函数示例const std::vectorUsdValidationFixer _ValidatorFixers() { std::vectorUsdValidationFixer fixers; FixerCanApplyFn fixerCanApplyFn [](const UsdValidationError error, const UsdEditTarget editTarget, const UsdTimeCode /*timeCode*/) - bool { // ...fixer logic here... return true; }; FixerImplFn fixerImplFn [](const UsdValidationError error, const UsdEditTarget editTarget, const UsdTimeCode /*timeCode*/) - bool { // ...can apply fixer logic here... return true; }; fixers.emplace_back( TfToken(Example Fixer), An example fixer., fixerImplFn, fixerCanApplyFn, TfTokenVector{}, TfToken(ErrorNameAssociatedWithFixer)); return fixers; }注册时传入registry.RegisterPluginValidator(validatorName, stageTaskFn, _ValidatorFixers());CanApplyFix()会综合修复器关联的错误名与关键字信息判定是否可应用。由于 Registry 不直接管理修复器修复器由各自的验证器持有。监听验证器注册TfNotice通过显式 APIRegisterValidator、RegisterValidatorSuite注册时注册表会发送基于TfNotice的通知插件注册不发送通知其元数据在注册表初始化时已可见。典型应用场景校验 UI 填充UI 初始化时从注册表枚举全部插件验证器同时监听DidRegisterValidator/DidRegisterValidatorSuite通知以增量刷新运行时显式注册的验证器动态上下文管理维护UsdValidationContext的客户端可监听注册通知检测是否有符合条件的新验证器加入进而刷新或重建 Context。C 监听示例#include pxr/usdValidation/usdValidation/notice.h struct MyListener : public TfWeakBase { void OnValidatorRegistered( const UsdValidationNotice::DidRegisterValidator notice) { const UsdValidationValidator *validator notice.GetValidator(); // ... react to the new validator ... } }; MyListener listener; TfNotice::Register( TfCreateWeakPtr(listener), MyListener::OnValidatorRegistered);Python 监听示例from pxr import Tf, UsdValidation def _on_validator_registered(notice, sender): validator notice.GetValidator() # ... react to the new validator ... key Tf.Notice.RegisterGlobally( UsdValidation.Notice.DidRegisterValidator, _on_validator_registered ) # Revoke when no longer needed: key.Revoke()套件通知使用UsdValidationNotice::DidRegisterValidatorSuiteC或UsdValidation.Notice.DidRegisterValidatorSuitePython并调用notice.GetValidatorSuite()。创建自定义验证器Python 篇Python 自定义验证器同样支持两条注册路径插件注册RegisterPluginLayerValidator、RegisterPluginStageValidator、RegisterPluginPrimValidator调用方只提供TfToken形式的验证器名元数据来自插件plugInfo.json在注册表初始化时自动解析显式注册RegisterLayerValidator、RegisterStageValidator、RegisterPrimValidator调用方提供完整ValidatorMetadata无需插件基础设施注册后立即可用。Python 验证器的性能注意点当ValidationContext运行验证器时所有任务C 与 Python都被派发到同一个共享 TBB 工作线程池。Python 任务函数每次调用必须获取 Python GIL执行 Python 任务函数的 TBB 线程会被阻塞等待 GIL由此产生两个后果Python 验证器之间无法并行即使有任务级并行同一时刻也只有一个 Python 验证器任务在运行其余都阻塞在 GIL 上Python 验证器可能饿死 C 验证器如果同时调度的 Python 验证器任务占满所有 TBB 工作线程就绪的 C 验证器任务只能排队等待被 GIL 阻塞的线程释放。因此性能敏感的校验管线应优先使用 C 实现验证器Python 验证器最适合原型开发、工具脚本、或运行频率低且场景小的校验任务。任务函数签名对照注册方法可调用对象签名RegisterLayerValidator/RegisterPluginLayerValidator(layer: Sdf.Layer) - list[ValidationError]RegisterStageValidator/RegisterPluginStageValidator(stage: Usd.Stage, timeRange: UsdValidation.TimeRange) - list[ValidationError]RegisterPrimValidator/RegisterPluginPrimValidator(prim: Usd.Prim, timeRange: UsdValidation.TimeRange) - list[ValidationError]可调用对象必须返回UsdValidation.ValidationError对象的列表或任意可迭代对象校验通过时返回空列表。显式注册示例Layer 验证器——警告 layer 未设置 defaultPrimfrom pxr import Sdf, UsdValidation registry UsdValidation.ValidationRegistry() metadata UsdValidation.ValidatorMetadata( namemyPackage:RequiresDefaultPrim, docWarn when a layer has no default prim set., keywords[myPackage], ) def _CheckDefaultPrim(layer): if not layer.defaultPrim: return [ UsdValidation.ValidationError( MissingDefaultPrim, UsdValidation.ValidationErrorType.Warn, [UsdValidation.ValidationErrorSite( layer, Sdf.Path.absoluteRootPath)], fLayer {layer.identifier} has no defaultPrim., ) ] return [] registry.RegisterLayerValidator(metadata, _CheckDefaultPrim)Stage 验证器——stage 缺少 upAxis 元数据时报错from pxr import Sdf, Usd, UsdGeom, UsdValidation registry UsdValidation.ValidationRegistry() metadata UsdValidation.ValidatorMetadata( namemyPackage:RequiresUpAxis, docError when a stage has no upAxis metadata., keywords[myPackage], ) def _CheckUpAxis(stage, timeRange): if not stage.HasAuthoredMetadata(UsdGeom.Tokens.upAxis): return [ UsdValidation.ValidationError( MissingUpAxis, UsdValidation.ValidationErrorType.Error, [UsdValidation.ValidationErrorSite( stage, Sdf.Path.absoluteRootPath)], Stage is missing upAxis metadata., ) ] return [] registry.RegisterStageValidator(metadata, _CheckUpAxis)Prim 验证器——警告 prim 未设置 kind跳过伪根 primfrom pxr import Sdf, Usd, UsdValidation registry UsdValidation.ValidationRegistry() metadata UsdValidation.ValidatorMetadata( namemyPackage:NoPrimsMissingKind, docWarn when a prim has no kind set., keywords[myPackage], ) def _CheckKind(prim, timeRange): if prim.IsPseudoRoot(): # skip pseudo-root return [] model Usd.ModelAPI(prim) if not model.GetKind(): return [ UsdValidation.ValidationError( MissingKind, UsdValidation.ValidationErrorType.Warn, [UsdValidation.ValidationErrorSite( prim.GetStage(), prim.GetPath())], fPrim {prim.GetPath()} has no kind., ) ] return [] registry.RegisterPrimValidator(metadata, _CheckKind)插件注册示例验证器在plugInfo.json声明后注册时只需名字其余元数据注册表已知{ Plugins: [{ Info: { Validators: { CheckUpAxis: { doc: Error when upAxis is missing., keywords: [stageMetadata] } } }, Name: myPlugin, Type: library, ... }] }from pxr import Sdf, UsdGeom, UsdValidation registry UsdValidation.ValidationRegistry() def _CheckUpAxis(stage, timeRange): if not stage.HasAuthoredMetadata(UsdGeom.Tokens.upAxis): return [ UsdValidation.ValidationError( MissingUpAxis, UsdValidation.ValidationErrorType.Error, [UsdValidation.ValidationErrorSite( stage, Sdf.Path.absoluteRootPath)], Stage is missing upAxis metadata., ) ] return [] # Name must match pluginName:validatorName from plugInfo.json. registry.RegisterPluginStageValidator( myPlugin:CheckUpAxis, _CheckUpAxis )插件验证器套件同理registry.RegisterPluginValidatorSuite( myPlugin:MySuite, [registry.GetOrLoadValidatorByName(myPlugin:CheckUpAxis)] )Python 插件验证器的触发机制C 插件由 Plug 系统加载共享库TF_REGISTRY_FUNCTION(UsdValidationRegistry)宏保证加载时自动执行注册代码。Python 插件同理但依赖__init__.py中的模块级注册代码。懒加载流程启动ValidationRegistry解析所有已发现插件的plugInfo.json验证器元数据name、doc、keywords、schemaTypes在加载任何代码前立即可用查询客户端调用registry.GetOrLoadValidatorByName(myPlugin:CheckUpAxis)注册表发现该元数据属于未加载插件触发加载经UsdValidationContext访问验证器时同样触发加载注册表调用plugin-Load()对 Python 类型插件Plug 系统执行import module_namemodule_name对应plugInfo.json的Name字段注册模块导入时执行__init__.py顶层代码调用RegisterPluginStageValidator或 layer/prim 变体向注册表注册任务函数返回注册表获得完整注册的验证器并返回调用方。Python 插件目录结构——模块目录名必须与plugInfo.json的Name字段一致且plugInfo.json与__init__.py同目录myPlugin/ __init__.py # Registration code runs at import time plugInfo.json # Type: python, Name: myPluginPython 场景的plugInfo.json{ Plugins: [{ Type: python, Name: myPlugin, Info: { Validators: { CheckUpAxis: { doc: Error when upAxis is missing., keywords: [stageMetadata] } } } }] }对应的__init__.pyfrom pxr import Sdf, UsdGeom, UsdValidation _PLUGIN_NAME myPlugin def _CheckUpAxis(stage, timeRange): if not stage.HasAuthoredMetadata(UsdGeom.Tokens.upAxis): return [ UsdValidation.ValidationError( MissingUpAxis, UsdValidation.ValidationErrorType.Error, [UsdValidation.ValidationErrorSite( stage, Sdf.Path.absoluteRootPath)], Stage is missing upAxis metadata., ) ] return [] # Registration at import time — equivalent to TF_REGISTRY_FUNCTION _registry UsdValidation.ValidationRegistry() _registry.RegisterPluginStageValidator( _PLUGIN_NAME :CheckUpAxis, _CheckUpAxis)插件目录必须可被Plug.Registry发现设置PXR_PLUGINPATH_NAME或调用Plug.Registry().RegisterPlugins()且模块父目录必须在sys.path上import才能成功。运行 Python 验证器按名取回验证器后直接调用Validate()或传入ValidationContext与其他验证器并行运行# Direct invocation validator registry.GetOrLoadValidatorByName( myPackage:RequiresUpAxis ) stage Usd.Stage.Open(asset.usda) errors validator.Validate(stage) for error in errors: print(error.GetErrorAsString()) # Via ValidationContext (runs all provided validators in parallel) context UsdValidation.ValidationContext([validator]) errors context.Validate(stage)将验证器分组为套件stage_validator registry.GetOrLoadValidatorByName( myPackage:RequiresUpAxis ) prim_validator registry.GetOrLoadValidatorByName( myPackage:NoPrimsMissingKind ) suite_metadata UsdValidation.ValidatorMetadata( namemyPackage:BaselineChecks, docSuite of baseline asset checks., keywords[myPackage], isSuiteTrue, ) registry.RegisterValidatorSuite( suite_metadata, [stage_validator, prim_validator] )Python 开发注意事项ValidationRegistry是单例一个模块注册的验证器对同进程其他模块可见验证器名在注册表内必须唯一。重复注册已存在的名字会静默失败如需防御注册前用HasValidator()检查任务函数内抛出的 Python 异常会被转换为 Tf 错误且该次调用返回空错误列表。需要更丰富的诊断信息时应在可调用对象内部显式处理异常显式注册的验证器没有关联插件、不做懒加载每个会话都必须重新注册才能使用插件注册的验证器元数据来自plugInfo.json在 Python 任务函数注册前即可发现支持工具在不加载任何插件的情况下枚举可用验证器。时间相关校验UsdValidationTimeRangeUsdValidationTimeRange描述执行校验的时间区间timeRange.h。默认构造表示全时间区间并包含UsdTimeCode::Default()也可用单个UsdTimeCode或GfInterval构造后者可通过includeTimeCodeDefault参数控制是否包含默认时间码。时间区间可传给UsdAttribute::GetTimeSamplesInInterval()取回相关采样时间依赖属性在回调中逐采样校验。校验全部时间采样时使用GfInterval::GetFullInterval()。框架内部时间依赖的处理见 context.h 的_TimeDependencyState支持三种状态仅时间依赖、仅非时间依赖、全部用于在给定时间码列表时正确调度验证器。参考实现与进一步探索usdchecker 工具pxr/usdValidation/bin/usdchecker下的 usdchecker.cpp 已更新为基于验证器实现是使用校验框架的命令行参考其测试基线见 baseRules_validationFramework.txtSchema 验证器插件pxr/usdValidation下的各插件目录提供了丰富的实例包括 usdGeomValidators、usdLuxValidators、usdShadeValidators、usdSkelValidators、usdUtilsValidators 等每个插件都含plugInfo.json、validatorTokens.h与validators.cpp测试用例usdValidation/testenv下覆盖了注册表testUsdValidationRegistry.cpp、ContexttestUsdValidationContext.cpp、Python 插件testUsdValidationPyPlugin.py、核心验证器testUsdCoreValidators.cpp等场景Python 插件测试目录还展示了__init__.pyplugInfo.json的真实组织方式testPyValidatorPlugin核心 API 头文件validator.h、registry.h、context.h、error.h、fixer.h、timeRange.h 是二次开发时的第一手参考。结语OpenUSD Validation 框架通过 验证器Validator 注册表Registry 上下文Context 错误/修复器Error/Fixer 的清晰分层将资产校验从散落的临时脚本收敛为可发现、可复用、可并行、可修复的插件化体系。无论是接入现有 Schema 验证器做资产 QA还是为团队自定义校验规则掌握本文的元数据模型、两种注册路径、Python 插件触发机制与性能约束即可在生产管线中落地可靠的 USD 资产校验。【免费下载链接】OpenUSDUniversal Scene Description项目地址: https://gitcode.com/GitHub_Trending/ope/OpenUSD创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表