OpenUSD usdLux GeometryLight 详解:从几何体光源 Schema 到 MeshLight 迁移实践
【免费下载链接】OpenUSDUniversal Scene Description项目地址: https://gitcode.com/GitHub_Trending/ope/OpenUSD
GeometryLight 是 OpenUSD usdLux 体系中的一个具体类型(ConcreteTyped)光源 Schema,用于让几何体(典型如 Mesh)向外发光充当光源。本文以仓库内 GeometryLight 官方 Schema 文档 为骨架,完整讲解其属性定义、继承体系与源码实现,并说明它为何被标记为弃用(deprecated)、以及如何迁移到官方推荐的 MeshLightAPI 方案,帮助你写出正确、可运行的光照 USD 场景。
一、GeometryLight 是什么
根据 GeometryLight 官方文档 的定义,GeometryLight 是:
从一个几何 Prim(Geometric Prim,即
UsdGeomGprim)向外发射的光,该几何体通常是 Mesh。该 Schema 已弃用,请改用应用于 Mesh 的 MeshLight。
其关键信息有三点:
- 发光方式:光从几何体表面向外辐射,而不是从点、方向或环境贴图发出;
- 几何来源:光所依赖的几何体通过
geometry关系(relationship)指定; - 弃用状态:文档明确标注 deprecated,官方推荐使用 MeshLight(即
MeshLightAPI应用于 Mesh 的方案)。
在 schema.usda 中,GeometryLight 的定义如下:
class GeometryLight "GeometryLight" ( inherits = </NonboundableLightBase> doc = """\deprecated Light emitted outward from a geometric prim (UsdGeomGprim), which is typically a mesh.""" ) { rel geometry ( doc = """Relationship to the geometry to use as the light source.""" ) uniform token light:shaderId = "GeometryLight" ( customData = { bool apiSchemaOverride = true } ) }其中\deprecated标记直接写进了 Schema 的 doc 字符串,generatedSchema.usda中也保留了同样的声明,说明这是官方在 Schema 层面正式废弃的类型。
二、GeometryLight 的属性(Properties)详解
官方文档为 GeometryLight 定义了 2 个自有属性,均为 Schema 直接声明:
1.geometry(关系属性)
- USD 类型:
rel(relationship) - 含义:指向用作光源的几何体的关系。
该属性用于将具体的几何体(通常是 Mesh,也支持其他UsdGeomGprim派生类型)与光源 Prim 关联起来。在源码 geometryLight.h 中对应两个 API:
/// Relationship to the geometry to use as the light source. USDLUX_API UsdRelationship GetGeometryRel() const; /// See GetGeometryRel(), and also /// \ref Usd_Create_Or_Get_Property for when to use Get vs Create USDLUX_API UsdRelationship CreateGeometryRel() const;即通过GetGeometryRel()读取、CreateGeometryRel()创建该关系。注意它是普通 relationship(非 uniform),因此可以在不同层、不同时间采样中分别指定。
2.light:shaderId(token 属性)
- USD 类型:
token - Fallback(默认)值:
GeometryLight - 含义:GeometryLight 的 shader ID。USD 还会在 SdrRegistry 中注册一个标识符为
"GeometryLight"、着色系统为"USD"的 Sdr shader 节点,其输入与该光源的 inputs 一一对应。
这个属性其实继承自LightAPI(详见下文源码分析),GeometryLight 只是通过apiSchemaOverride = true把默认值覆盖为自身的类型名"GeometryLight",这与 DistantLight、DiskLight、RectLight 等内置光源的做法完全一致——每个内置 usdLux 光源的默认 shaderId 都是它自身的类型名。
在 tokens.h 中,该 token 被显式声明:
/// \brief "GeometryLight" /// /// Schema identifer and family for UsdLuxGeometryLight, Fallback value for UsdLuxGeometryLight schema attribute light:shaderId const TfToken GeometryLight;三、继承属性:来自 Xformable 与 Imageable
GeometryLight 间接继承自NonboundableLightBase,而后者又继承自Xformable(见 schema.usda),因此它同时继承了 Xformable 和 Imageable 的通用属性。官方文档将其分别归为两组:
继承自 Xformable
| 属性 | USD 类型 | 说明 |
|---|---|---|
xformOpOrder | token[] | 变换操作(xformOp)的求值顺序列表,控制光源在场景中的位置与朝向 |
作为非绑定(Nonboundable)光源,GeometryLight 没有extent等绑定体积属性,但依然可以像普通 Prim 一样被平移、旋转、缩放。
继承自 Imageable
| 属性 | USD 类型 | Fallback 值 | 说明 |
|---|---|---|---|
proxyPrim | rel | — | 用于指定替代该 Prim 显示的代理几何体 |
purpose | token | default | 绘制目的分类(如 default / render / proxy / guide) |
visibility | token | inherited | 可见性,inherited表示继承父级可见性状态 |
这些是几乎所有UsdGeomImageable派生 Prim 都具备的标准属性,可用于控制光源在 DCC 工具与渲染器中的显示与参与方式。
四、源码级实现:UsdLuxGeometryLight 类
从源码结构看,GeometryLight 对应的 C++ 类是UsdLuxGeometryLight,完整定义在 geometryLight.h:
/// \class UsdLuxGeometryLight /// /// \deprecated /// Light emitted outward from a geometric prim (UsdGeomGprim), /// which is typically a mesh. /// class UsdLuxGeometryLight : public UsdLuxNonboundableLightBase { public: /// Compile time constant representing what kind of schema this class is. static const UsdSchemaKind schemaKind = UsdSchemaKind::ConcreteTyped; ... };几个关键实现细节:
- Schema 种类:
UsdSchemaKind::ConcreteTyped,即它是一个可以独立作为 Prim 类型名(typeName)使用的具体类型; - 继承关系:
UsdLuxGeometryLight : public UsdLuxNonboundableLightBase,而NonboundableLightBase在 schema.usda 中声明为inherits = </Xformable>并prepend apiSchemas = ["LightAPI"],这意味着 GeometryLight 自动获得 LightAPI 的全部能力(intensity、exposure、color、enableColorTemperature、colorTemperature、diffuse、specular、normalize、lightLink、shadowLink 等)以及 Xformable 的变换能力; - 注册机制:geometryLight.cpp 中通过
TF_REGISTRY_FUNCTION(TfType)调用TfType::Define<UsdLuxGeometryLight, TfType::Bases<UsdLuxNonboundableLightBase>>(),并把"GeometryLight"注册为UsdSchemaBase下的派生别名,从而支持IsA查询与 schema 类型解析; - Python 绑定:wrapGeometryLight.cpp 将其导出为
UsdLux.GeometryLight,继承自UsdLux.NonboundableLightBase,Python 侧用法与 C++ 一一对应。
五、light:shaderId 与 Sdr 节点注册机制
官方文档提到:"USD 也会注册一个 Sdr shader 节点,标识符为 'GeometryLight'、source type 为 'USD',与该光源的 inputs 对应"。这一机制由 lightDefParser.cpp 中的UsdLux_LightDefParserPlugin实现,其工作流程大致是:
- 从插件的
generatedSchema.usda资源中读取 Schema 定义层; - 依次把
LightAPI、光源类型本身(如GeometryLight)、ShadowAPI、ShapingAPI的属性复制到一个匿名 prim spec 上(lightDefParser.cpp); - 打开该层,通过
UsdShadeConnectableAPI提取所有 inputs/outputs,构造一个SdrShaderNode(lightDefParser.cpp)。
因此,任何符合 usdLux 约定的内置光源都会自动获得一个可被SdrRegistry::GetShaderNodeByIdentifier("GeometryLight")查到的 shader 节点,渲染器与材质系统无需硬编码即可识别该光源及其参数。这也解释了为什么light:shaderId默认值必须与类型名一致——它是 Sdr 发现与解析的标识符。
六、为什么弃用:从 GeometryLight 到 MeshLight 的演进
官方在 overview.md 的 "Mesh Lights" 一节中,明确给出了弃用的原因与替代方案:
你可能需要把任意形状作为光源,例如模拟霓虹灯招牌,或让一个可变形的形状同时发光。请使用MeshLightAPISchema 将光照行为应用到 Mesh。使用该 Schema 优于直接把 LightAPI 应用到 Mesh,因为它应用了常用内置行为:把默认的
materialSyncMode覆盖为"materialGlowTintsLight"以使用 Mesh 绑定的材质;同时把默认shaderId设为"MeshLight",为插件挂接额外的 mesh light 属性提供挂钩。
对比两者的差异:
| 维度 | GeometryLight(已弃用) | MeshLightAPI(推荐) |
|---|---|---|
| Schema 形态 | ConcreteTyped 类型,独立 Prim | SingleApply API Schema,附加到现有 Mesh |
| 几何指定方式 | 通过geometry关系指向几何体 | 直接应用于 Mesh Prim 本身 |
| 材质同步 | 依赖 LightAPI 默认noMaterialResponse | 默认materialGlowTintsLight,发光材质可影响光色 |
| shaderId 默认值 | GeometryLight | MeshLight |
| 插件扩展性 | 无专门挂钩 | 可通过 auto-apply 的 API Schema 附加属性 |
推荐方案:MeshLightAPI
MeshLightAPI 官方文档 完整列出其两个默认属性:
light:materialSyncMode:token,Fallback 值materialGlowTintsLight——让材质发射/辉光影响光的颜色,同时保留inputs:color、inputs:intensity等 LightAPI 控制项继续调制光照;light:shaderId:token,Fallback 值MeshLight。
源码 meshLightAPI.h 中的类注释进一步说明:该 Schema 底层自动把 LightAPI 应用到 Mesh,并覆盖默认 materialSyncMode,同时作为插件挂接额外 "mesh light" 属性的钩子(通过 auto-apply 的 API Schema 实现)。在 schema.usda 中可以找到对应声明:uniform token light:shaderId = "MeshLight"、uniform token light:materialSyncMode = "materialGlowTintsLight"。
一个可运行的 MeshLight 示例
下面的完整示例来自 overview.md,将 MeshLightAPI 应用到一个复杂曲面,使其作为 4 个球体的光源:
#usda 1.0 ( upAxis = "Y" ) def Xform "MeshLight" { double xformOp:rotateX = -90 uniform token[] xformOpOrder = ["xformOp:rotateX"] def Mesh "Mesh" ( prepend apiSchemas = ["MeshLightAPI"] ) { color3f inputs:color = (1, 1, 1) float inputs:intensity = 1.0 # ...faceVertexCounts/Indices/points 此处省略... } } def Xform "TestSpheres" { def Sphere "Sphere1" { color3f[] primvars:displayColor = [(1, 1, 1)] ( interpolation = "constant" ) double3 xformOp:translate = (-2.5, 3, 0) uniform token[] xformOpOrder = ["xformOp:translate"] } def Sphere "Sphere2" { color3f[] primvars:displayColor = [(1, 1, 1)] ( interpolation = "constant" ) double3 xformOp:translate = (0, 3, -4) uniform token[] xformOpOrder = ["xformOp:translate"] } def Sphere "Sphere3" { color3f[] primvars:displayColor = [(1, 1, 1)] ( interpolation = "constant" ) double3 xformOp:translate = (2.5, 3, 0) uniform token[] xformOpOrder = ["xformOp:translate"] } def Sphere "Sphere4" { color3f[] primvars:displayColor = [(1, 1, 1)] ( interpolation = "constant" ) double3 xformOp:translate = (0, 3, 4) uniform token[] xformOpOrder = ["xformOp:translate"] } }关键点:
- 通过
prepend apiSchemas = ["MeshLightAPI"]把 Schema 附加到 Mesh 上,无需再定义独立的光源 Prim; - Mesh 上的
inputs:color与inputs:intensity来自 LightAPI(MeshLightAPI 自动应用),分别控制光色与亮度; materialSyncMode默认即为materialGlowTintsLight,绑定发光材质后,材质发射通道的颜色会与inputs:color相乘,从而让光的颜色"染"上几何体的辉光色。
渲染提示:如果你使用 Hydra 与 RenderMan 渲染,需要启用 Hydra 的 scene index(必要时在环境中设置
USDIMAGINGGL_ENGINE_ENABLE_SCENE_INDEX)才能看到 mesh light 的渲染结果(见 overview.md)。
类似的便捷 Schema:VolumeLightAPI
与 MeshLightAPI 类似的还有 VolumeLightAPI,专门用于让 USD Volume 充当光源,默认shaderId为VolumeLight、materialSyncMode同为materialGlowTintsLight(见 schema.usda)。在 lightDefParser.cpp 的ShaderIdToAPITypeNameMap中,MeshLight → MeshLightAPI、VolumeLight → VolumeLightAPI的映射关系明确写入了 Sdr 解析插件,因此这两个 shaderId 同样会被自动解析为对应的 API Schema 属性集。
七、从 GeometryLight 迁移到 MeshLight
迁移的核心思路:把"独立光源 Prim + geometry 关系"改为"Mesh 上直接应用 MeshLightAPI"。
迁移前(旧式,已弃用):
def GeometryLight "MyLight" ( prepend apiSchemas = ["LightAPI"] ) { rel geometry = </Geom/MyMesh> uniform token light:shaderId = "GeometryLight" }迁移后(推荐):
def Mesh "MyMesh" ( prepend apiSchemas = ["MeshLightAPI"] ) { uniform token light:shaderId = "MeshLight" color3f inputs:color = (1, 1, 1) float inputs:intensity = 1.0 }在 Python 侧,可以借助UsdLux.MeshLightAPI完成程序化迁移(对应 C++ 的UsdLuxMeshLightAPI::Apply,见 meshLightAPI.h):
from pxr import Usd, UsdLux stage = Usd.Stage.Open("scene.usda") mesh = stage.GetPrimAtPath("/Geom/MyMesh") # 将 MeshLightAPI 应用到 Mesh,返回的 schema 对象可用于继续读写灯光参数 meshLight = UsdLux.MeshLightAPI.Apply(mesh) meshLight.CreateShaderIdAttr() # 默认 "MeshLight" meshLight.CreateIntensityAttr().Set(1.0) meshLight.CreateColorAttr().Set((1.0, 1.0, 1.0)) # 旧式查询方式:UsdLux.GeometryLight.Get(stage, "/Lights/MyLight") # 迁移后不再需要,直接操作 Mesh 上的 LightAPI 属性即可注意:迁移后geometry关系不再需要,因为光源就是 Mesh 本身;原来通过geometry指向的几何体也无需再做任何关联操作。
八、总结
- GeometryLight是 usdLux 中让几何体向外发光的光源 Schema,自有属性仅
geometry(rel)与light:shaderId(默认GeometryLight),并继承 Xformable、Imageable 以及 LightAPI 的全部通用光照属性; - 它已被官方正式弃用(doc 中带有
\deprecated标记),其 C++ 类UsdLuxGeometryLight与 token 仍保留在仓库中以便兼容旧场景,但不应在新资产中使用; - MeshLightAPI是官方推荐的替代方案:直接应用于 Mesh,默认
materialSyncMode = "materialGlowTintsLight"、shaderId = "MeshLight",并内置插件挂钩,是模拟霓虹灯、可变形发光体等任意形状光源的标准做法; - 无论哪种方案,
light:shaderId都会通过 lightDefParser.cpp 的 Sdr 解析插件注册为 "USD" 着色系统下的 shader 节点,保证渲染器能够无硬编码地识别光源参数。
本文所依据的官方 Schema 文档位于 docs/user_guides/schemas/usdLux/GeometryLight.md,Schema 定义与实现可继续深入阅读 pxr/usd/usdLux/schema.usda、geometryLight.h、meshLightAPI.h 与 lightDefParser.cpp。
【免费下载链接】OpenUSDUniversal Scene Description项目地址: https://gitcode.com/GitHub_Trending/ope/OpenUSD
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考