ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

OpenUSD SdrShaderNode 完全指南:着色器节点核心字段、元数据体系与命名规范

OpenUSD SdrShaderNode 完全指南:着色器节点核心字段、元数据体系与命名规范 OpenUSD SdrShaderNode 完全指南着色器节点核心字段、元数据体系与命名规范【免费下载链接】OpenUSDUniversal Scene Description项目地址: https://gitcode.com/GitHub_Trending/ope/OpenUSDSdrShaderNode 是 OpenUSD 中 Shader Definition RegistrySdr体系的核心抽象它以统一的数据结构描述任意着色系统OSL、Args、MaterialX 等中可参与数据流连接的计算节点。本文基于 shaderNode.md 系统讲解其核心字段、元数据Metadata体系与 identifier/name/function 命名规范并结合 shaderNode.h、shaderNodeMetadata.h 等源码说明底层实现帮助你掌握如何为渲染器或着色系统编写符合 Sdr 标准的节点定义。SdrShaderNode 是什么SdrShader Definition Registry为管线提供了一个可扩展框架用于发现、懒加载解析并查询着色器信息。在这个框架中SdrRegistry 通过两阶段插件流程填充着色器信息Discovery发现阶段定位着色器定义文件并产出SdrShaderNodeDiscoveryResultParsing解析阶段读取着色器定义并产出最终的SdrShaderNode。SdrShaderNode表示一个可进行数据流连接的计算单元dataflow-connectable computation即计算网络computational network中的一个节点。它屏蔽了各着色系统内部表示方式的差异——管线只需持有identifier和shadingSystem两个数据即可找到原始着色器实现implementation着色器的输入/输出属性propertiesSdr 标准化的公共元数据与自定义元数据核心字段SdrShaderNode拥有以下核心字段字段描述identifier简明字符串包含节点功能、类型特化type specialization与版本信息name简明字符串包含节点功能与类型特化function简明字符串描述节点做什么versionSdrVersion表示节点版本shadingSystem描述一个通常拥有自身标准、语言和/或运行时的系统properties表示计算输入与输出SdrShaderPropertydefinitionURI提供节点定义资源的 URI在 Discovery 阶段确定implementationURI提供节点计算实现资源的 URI在 Parsing 阶段确定在 shaderNode.h 中这些字段通过SDR_NODE_FIELD_KEY_TOKENS令牌化_identifier、_name、_function、_shadingSystem其中_sourceType已废弃并被_shadingSystem取代。节点数据可通过GetDataForKey按特殊键获取例如SdrNodeFieldKey-Identifier返回持有TfToken的VtValueSdrNodeFieldKey-Name返回持有std::string的VtValue非字段键则回退到节点元数据中查找。唯一标识规则SdrShaderNode由identifiershadingSystem的组合唯一标识。根据上述字段含义节点也可等价地由nameversionshadingSystem唯一标识。SdrRegistry提供了便捷 API允许使用这些字段的各种组合来查找节点。需要注意在某些情况下definitionURI与implementationURI可能相同例如定义与实现位于同一文件。与源码的对应关系从 shaderNode.h 可以看到核心字段均有对应访问器GetIdentifier()、GetShaderVersion()、GetName()、GetFunction()返回节点标识、版本、名称与功能GetShadingSystem()返回节点来源的着色系统GetSourceType()已废弃GetResolvedDefinitionURI()与GetResolvedImplementationURI()返回已完全解析的定义/实现 URIGetSourceCode()与IsValid()当节点通过SdrRegistry::GetShaderNodeFromSourceCode()构造且尚未解析时sourceCode非空但属性为空此时节点视为无效解析成功后才变为有效构造函数签名shaderNode.h也印证了上述字段结构identifier、version、name、function、shadingSystem、definitionURI、implementationURI、propertiesSdrShaderPropertyUniquePtrVec以及可选的metadataSdrShaderNodeMetadata和sourceCode。注意旧构造函数中的context参数已废弃改为在元数据中指定。元数据MetadataSdrShaderNodeMetadata保存SdrShaderNode的具名元数据同时支持用户自定义元数据。这些具名元数据项在 shaderNodeMetadata.h 中通过SDR_NODE_METADATA_TOKENS令牌化代码中引用某个键时使用形如SdrNodeMetadata-Label的令牌。解析器生成的元数据键应以__SDR__前缀开头以降低与着色器内真实元数据冲突的风险。常用具名元数据键描述labelUI 提示用于用户友好的字符串展示help该节点的帮助信息domain定义最宽泛的系统类别分组默认值为 renderingsubdomain定义域内子系统例如 rendering 域下的 shading、filtering、lightingcontext描述子域内的使用分组例如 shading 子域下的 pattern、surface、bxdfrole为包含大量节点的 context 提供更细粒度targetRenderer描述该节点是为但不限于某个特定渲染器设计的collections提供一种以其他元数据无法捕捉的方式任意分组节点implementationName实现源码中的着色器名称某些运行时需要openPages默认应打开/展开的页面pagesShownIf每页的shownIf表达式参见SdrShaderProperty::GetShownIfprimvars该节点使用的 primvars在 shaderNodeMetadata.h 中还定义了常用的域/子域/上下文/角色令牌Domainrendering、generalSubdomainrendering 域内shading、filtering、lighting、renderingContextshading 子域下pattern、surface、volume、displacementlighting 子域下light、lightFilterfiltering 子域下displayFilter、pixelFilter、sampleFilter、volumeFilter、energyFilterrendering 子域下integrator、projectionRoleprimvar、texture、field、math其中category、departments、pages、target已被废弃但客户端仍可设置这些键的元数据只是便捷 API 被移除。元数据的 UI 分组层级以下元数据项与核心字段共同构成一个用于 UI 展示逻辑分组的层级参见辅助函数SdrShaderNodeQueryUtils::GroupQueryResultsdomain → subdomain → context → role → function → name → identifier从 shaderNodeQueryUtils.h 可以看到GroupQueryResults会把查询结果构建为嵌套的VtDictionary树每一层对应一个分组值最内层叶子为按节点 identifier再按 shadingSystem字母序排序的std::vectorSdrShaderNodeConstPtr空值也会被保留为键。例如查询结果[[context1, id1]]会得到{context1: {id1: [...]}}。注意SdrShaderNodeMetadata 中domain有默认值 rendering即在构造时未指定的 domain 会被初始化为SdrNodeDomain-Rendering见 shaderNodeMetadata.h。元数据作者是谁通常元数据既可以由**着色器编写者shader writers编写也可以由解析器插件编写者parser plugin writers**编写。具体何时由谁编写取决于期望的工作流。例如Maya 的 .args 文件可能由 shader writer 直接书写 label/help而基于源码解析的 OSL 解析器则可能由 parser 在读取源码注释时生成这些项。与源码的对应关系SdrShaderNodeMetadata提供HasItem/SetItem/GetItemValue/GetItemValueAsT/ClearItem等通用接口内部以VtDictionary存储并为具名元数据提供类型安全的便捷访问器如GetLabel()、GetDomain()、GetSubdomain()、GetContext()、GetRole()、GetTargetRenderer()、GetCollections()、GetHelp()、GetOpenPages()、GetPagesShownIf()、GetPrimvars()、GetImplementationName()等shaderNodeMetadata.h。它兼容旧版SdrTokenMap可从该结构隐式构造但旧接口SdrShaderNode::GetMetadata()已废弃仅返回字符串型元数据新代码应使用GetMetadataObject()。节点的GetPrimvars()与GetAdditionalPrimvarProperties()配合使用可得到完整 primvar 需求列表前者返回节点已知需要/使用的 primvar如normals后者返回值为 primvar 名称的字符串输入属性列表如varname。这与SdrShaderNodeMetadata::GetPrimvars并不等价——前者是在拥有SdrShaderProperty信息后处理得到的。命名风格规范Style Guidelines虽然SdrShaderNode允许不符合上述描述的使用方式但遵循这些软性标准有助于保持一致的组织结构。identifier / name / function 格式identifier、name与function应遵循以下格式各部分用下划线分隔identifier: function_typeSpecialization_version name: function_typeSpecialization function: functionfunction描述节点做什么version形如major_minor或majortypeSpecialization表示节点类型遵循以下建议类型特化表示应在最大化含义的同时将所有相同 function 的节点区分开。此规则优先于下列规则需发挥最佳判断优先使用着色器输出类型的表示尽可能使用小写的 Sdr 类型表示参见 SdrShaderProperty 类型若类型是固定大小容器使用类型表示并拼接固定大小例如float3或color4若类型是大小不固定的容器使用vector并拼接首字母大写的容器内类型camel case见示例 2若需要多个类型规格才能区分一个 function用下划线拼接优先输出类型必要时使用输入类型若某个简短单词/短语既能描述一个或多个类型表示又能区分该着色器与其他着色器优先使用简短形式见示例 3命名示例字段示例 1示例 2示例 3identifieradd_float_3position_vectorFloat_1_9convert_float4_surfaceShader_1nameadd_floatposition_vectorFloatconvert_float4_surfaceShaderfunctionaddpositionconvert解读这三个示例示例 1add_float_3function 为add输出类型为float版本为3major形式。若存在add_float_3_1则表示addfloat 主版本 3、次版本 1。示例 2position_vectorFloat_1_9function 为position类型为大小不固定的容器vector内含类型Floatcamel case版本为1_9major_minor形式。示例 3convert_float4_surfaceShader_1function 为convert输入类型为float4context/角色特化为surfaceShader版本为1。这里用简短词surfaceShader而非冗长的类型罗列即为规则中优先简短形式的体现。输入与输出的访问SdrShaderNode将输入与输出统称为 property并提供系列访问 APIshaderNode.hGetShaderInputNames()/GetShaderOutputNames()按顺序返回所有输入/输出名称GetShaderInput(name)/GetShaderOutput(name)按名称获取属性不存在时返回nullptrGetAssetIdentifierInputNames()返回所有标记为资产标识符的输入GetDefaultInput()返回被标记为默认输入的第一个输入当节点被视为禁用或无法产生输出值时默认输入及其值可用于获取回退值GetPages()/GetPropertyNamesForPage(pageName)聚合节点所有属性的page元数据未分配到页面的属性可用空字符串获取GetAllVstructNames()返回节点中所有 vstruct 名称此外静态方法CheckPropertyComplianceshaderNode.h可检查多个节点的同名属性是否兼容类型与默认值一致以第一个提供该属性的节点为准其余不一致的节点记为不合规返回属性名到节点列表的映射空映射表示无合规问题。节点属性SdrShaderProperty简介节点上的每个输入/输出均为SdrShaderProperty详见 shaderProperty.md其核心字段为name、typeSdr 类型与isOutput是否为输出。属性可连接性由CanConnectTo与IsConnectable描述。Sdr 类型与 Sdf 类型是两套类型系统构造时解析逻辑 Sdr 类型调用GetTypeAsSdfType时自动换算为SdfValueTypeName。struct、terminal、vstruct是 Sdr 特有、无对应SdfValueTypeName的特殊类型会被映射到SdfValueTypeNames-Token此时应通过renderType元数据补充完整类型信息如renderType terminal surface。在 Sdr 生态中的位置与最佳实践SdrShaderNode是 Sdr 框架三层文档体系front.md 概述、registry.md 注册表、shaderNode.md 节点、shaderProperty.md 属性中的核心数据对象。编写自定义 discovery 插件或 parser 插件时应遵循以下实践Discovery 插件实现SdrDiscoveryPlugin基类负责找到着色器定义位置并产出SdrShaderNodeDiscoveryResult同时遵守本文的 identifier/name/function 命名风格。仓库中的 UsdMtlx discovery 插件是参考实现pxr/usd/usdMtlx/discovery.cppParser 插件实现SdrParserPlugin基类按需解析节点并填充属性信息、节点元数据等通常只能通过阅读源码实现文件获得的信息。仓库中的 UsdMtlx parser 插件是参考实现pxr/usd/usdMtlx/parser.cpp元数据编写根据工作流决定由 shader writer 还是 parser writer 编写具名元数据将domain、subdomain、context、role等组成层级即可借助SdrShaderNodeQueryUtils::GroupQueryResults直接构建 UI 分组树遵循上述字段语义与命名规范能够让不同着色系统OSL、.args、MaterialX 等的节点在 Sdr 统一模型下被一致地发现、解析、查询与展示这也是 OpenUSD 跨渲染器/跨着色系统管线集成的基础。【免费下载链接】OpenUSDUniversal Scene Description项目地址: https://gitcode.com/GitHub_Trending/ope/OpenUSD创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进