OpenUSD usdLux DomeLight 全解析:环境照明(IBL)穹顶灯的原理、属性与实战示例
【免费下载链接】OpenUSDUniversal Scene Description项目地址: https://gitcode.com/GitHub_Trending/ope/OpenUSD
本文以 OpenUSD 仓库中 DomeLight 官方 Schema 文档 为主线,系统讲解 usdLux 体系中的 DomeLight(穹顶灯):它如何通过远距离环境贴图模拟天空或 HDR 图像带来的 Image Based Lighting(IBL),其经纬度朝向约定、全部可用属性与取值、以及配套的 DomeLight_1(poleAxis)变体。读完本文,你将能够直接在 USDA 场景中写出可运行的环境照明配置,并理解其底层 Schema 定义与 C++/Python API 的实现细节。
DomeLight 渲染输出示例:环境贴图照亮带基础材质球体的结果(来自 usdLux 用户指南 目录下的图片资源)。
DomeLight 是什么
DomeLight 是一种内置(intrinsic)光源,它从"极其遥远的外部环境"向内发光——这个环境可以是天空,也可以是一张用于 Image Based Lighting(IBL)的高动态范围(HDR)图像。官方 Schema 文档将其概括为:
An intrinsic light that emits light inwards from a very distant external environment, such as a sky, or a light environment captured in a High Dynamic Range (HDR) image used for Image Based Lighting (IBL).
一句话来说:使用 DomeLight 即可模拟环境照明(Use DomeLights to simulate environment lighting)。
在 OpenUSD 的 usdLux 模块中,DomeLight 继承自NonboundableLightBase(非有界光源基类),其 Schema 声明位于 pxr/usd/usdLux/schema.usda,生成的 C++ 类为UsdLuxDomeLight,定义于 pxr/usd/usdLux/domeLight.h。与 RectLight、DiskLight、SphereLight 等有界光源不同,DomeLight 不携带"发光面积/几何体"概念,而是围绕场景包裹一个远距离环境,从四面八方提供光照。
版本说明:usdLux 提供了两个 DomeLight 变体——本文主讲的
DomeLight以及提供poleAxis朝向控制的DomeLight_1。两者除朝向控制方式外属性完全一致,详见后文 DomeLight_1 与 poleAxis 朝向控制。
默认朝向与 OpenEXR 经纬度贴图约定
DomeLight 的默认朝向是顶部极点与世界 +Y 轴对齐。这一约定严格遵守 OpenEXR 规范 对 latitude-longitude(经纬度)贴图的规定。官方文档引用了 OpenEXR 文档的原文,这里完整保留以便理解纹理像素与 3D 空间的映射关系:
Latitude-Longitude Map:
环境图像使用极坐标(纬度和经度)投影。像素的 x 坐标对应经度,y 坐标对应纬度。像素
(dataWindow.min.x, dataWindow.min.y)的纬度为+pi/2、经度为+pi;像素(dataWindow.max.x, dataWindow.max.y)的纬度为-pi/2、经度为-pi。在 3D 空间中,纬度
-pi/2与+pi/2分别对应负 Y 与正 Y 方向。纬度 0、经度 0 指向正 Z 方向;纬度 0、经度pi/2指向正 X 方向。data window 的尺寸应为 2*N 乘 N 像素(宽 × 高),其中 N 为任意大于 0 的整数。
这段约定对贴图制作有直接指导意义:
- 图像宽高比必须是 2:1,否则无法与球面投影严格对应;
- 图像顶部边缘(纬度
+pi/2)对应穹顶顶端(+Y),底部边缘对应 -Y; - 图像水平中线(纬度 0)对应的方位:图像左/右边缘的经度为
±pi,图像水平中心经度为 0,指向 +Z。
在 schema.usda 的doc注释中完整保留了同样的说明,确保生成的所有语言绑定文档口径一致。
最小可运行示例:DomeLight + 球体 + 材质
官方文档给出了一个完整的 USDA 示例:用一个带环境贴图纹理的 DomeLight 照亮一个应用了基础材质(PxrSurface)的球体。原样继承如下:
#usda 1.0 ( ) def Scope "Lights" { def DomeLight "Dome" { asset inputs:texture:file = @orientationLatLong.tex@ } } def Xform "TestGeom" { def Sphere "Sphere1" ( prepend apiSchemas = ["MaterialBindingAPI"] ) { rel material:binding = </Material> } } def Material "Material" { token outputs:ri:surface.connect = </Material/Surface.outputs:out> def Shader "Surface" { uniform token info:id = "PxrSurface" float inputs:diffuseGain = 0.3 color3f inputs:specularEdgeColor = (1, 1, 1) color3f inputs:specularFaceColor = (0.4, 0.4, 0.4) float inputs:specularRoughness = 0.02 token outputs:out } }对示例的逐段拆解:
def DomeLight "Dome":在LightsScope 下定义穹顶灯 prim。其类型DomeLight即 usdLux 注册的 schema 类型名,渲染器据此识别光源类型(对应light:shaderId,见下文)。asset inputs:texture:file = @orientationLatLong.tex@:为穹顶指定环境贴图。@...@是 USD 中 asset 路径的书写语法,orientationLatLong.tex是按 OpenEXR 经纬度布局生成的纹理(建议 2:1 宽高比)。rel material:binding = </Material>:通过MaterialBindingAPI将球体的材质绑定到场景根部的Material。PxrSurface着色器:这是 RenderMan 风格的材质节点。文档特意将diffuseGain调低为 0.3、设置非纯白的镜面反射参数,是为了让环境贴图对球面的贡献清晰可见,避免材质自身漫反射过强掩盖 IBL 效果。
渲染提示:该示例按 RenderMan 管线书写(
outputs:ri:surface前缀、PxrSurfaceshader id)。若使用 Hydra 的 Storm 等其他渲染委托,需要换成对应渲染器支持的材质节点与连接语法;DomeLight 本身的属性定义是渲染器无关的。
属性详解
以下属性均定义在 schema.usda 的 DomeLight 类 中,并通过生成代码暴露为UsdLuxDomeLight的 C++ API 与 Python API(UsdLux.DomeLight)。
guideRadius
- USD 类型:
float - Fallback 值:
100000.0
用于设置可视化穹顶灯的辅助几何体(guide geometry)半径,单位为 USD 单位。默认值1.0e5在场景metersPerUnit为 USD 默认值0.01(即 1 单位 = 1 cm)时,恰好等于1 公里。该属性属于 "Guides" 显示分组,仅影响视口/编辑器中穹顶的可视化表现(如 usdview 中半透明的穹顶示意球),不参与光照计算。
inputs:texture:file
- USD 类型:
asset - Fallback 值:无(必须由用户提供才有效果)
DomeLight 使用的颜色纹理,通常是专为 IBL 准备的 HDR 图像。在生成的 C++ API 中对应GetTextureFileAttr()/CreateTextureFileAttr()(见 domeLight.h),显示分组为 "Basic",显示名 "Color Map"。属性名为inputs:前缀意味着它是一个可连接的着色器输入,可由渲染器采样。
inputs:texture:format
- USD 类型:
token - Fallback 值:
automatic - Allowed tokens(在 schema.usda 中由
allowedTokens声明):automatic、latlong、mirroredBall、angular、cubeMapVerticalCross
描述颜色纹理的参数化(投影)方式,渲染器据此正确采样贴图。五种取值的官方说明:
| 取值 | 含义 |
|---|---|
automatic | 渲染器尝试从文件本身推断布局。例如 RenderMan 纹理文件会内嵌显式的参数化信息 |
latlong | 文件按"纬度为 X、经度为 Y"参数化(即标准的经纬度等距柱状投影,2:1 宽高比) |
mirroredBall | 文件是环境在球面上的反射图像,采用隐式正交投影("镜像球"式环境贴图) |
angular | 类似mirroredBall,但径向维度按角度线性映射,在边缘处提供更好的采样质量 |
cubeMapVerticalCross | 文件是立方体贴图,面片按竖直十字形排列 |
需要说明:latlong项在文档正文写作 "latitude as X, longitude as Y",指的是纹理的 U/V 两个轴分别对应纬度/经度方向。配合上一节的 OpenEXR 约定理解:纬度对应图像纵向(V),经度对应横向(U)。
light:shaderId
- USD 类型:
token - Fallback 值:
DomeLight
DomeLight 的着色器标识。当该属性被设置(或使用默认值)时,USD 会注册一个标识符为"DomeLight"、source type 为"USD"的Sdr shader node,使该光源的输入属性(如inputs:texture:file)可以通过 UsdShade 的连接/发现机制被渲染器识别。Schema 中以uniform token声明且带apiSchemaOverride标记,说明它作为该光源类型的稳定标识,供渲染委托匹配对应的灯光实现。相关 API 为UsdLuxDomeLight::GetLightShaderIdAttr(继承自 LightAPI 体系)。
portals
- USD 类型:
rel(relationship) - Fallback 值:无
可选的采样引导门户(Optional portals to guide light sampling)。通过该关系,DomeLight 可以引用一个或多个PortalLightprim——即 schema.usda 中定义的矩形门户:位于局部 XY 平面、向 -Z 方向透光、边长 1 单位(可通过inputs:width、inputs:height调整)。在建筑可视化等"室外光通过窗户进入室内"的场景中,门户可以显著减少路径追踪采样噪声。对应 API 为GetPortalsRel()/CreatePortalsRel()(见 domeLight.h)。
DomeLight_1 与 poleAxis 朝向控制
官方文档明确指向了替代版本DomeLight_1(见 DomeLight_1 文档),它在DomeLight 基础上额外提供poleAxis属性来控制穹顶朝向,适用于 Z-up 场景或需要 Y/Z 轴切换的工作流。
poleAxis
- USD 类型:
token - Fallback 值:
scene - Allowed tokens:
scene、Y、Z(见 schema.usda)
决定穹顶顶部极点的初始对齐方向:
scene:穹顶顶部极点与stage 的上轴(up axis)对齐;Y:穹顶顶部极点与+Y 轴对齐;Z:穹顶顶部极点与+Z 轴对齐。
文档特别强调两点注意事项:
- 将穹顶对齐到
poleAxis所需的旋转只应用于穹顶本身,不会继承到该穹顶 prim 的命名空间子级(dome light prim 的 namespace children); - 当
poleAxis为"Y"或"scene"且 stage 上轴为 Y 时,默认朝向与 OpenEXR 经纬度规范一致;当poleAxis为"Z"或"scene"且 stage 上轴为 Z 时,纬度±pi/2对应 ±Z 方向,纬度 0、经度 0 在 3D 空间中指向-Y方向(见 schema.usda 的补充说明)。
继承属性(Xformable 与 Imageable)
除自有属性外,DomeLight 还继承了两个通用基类的属性(与其他 usdLux 光源一致):
继承自 Xformable(xformOpOrder)
xformOpOrder:token[]类型。声明变换操作(translate/rotate/scale 等)的求值顺序,用于摆放穹顶在场景中的位置与姿态。
继承自 Imageable(proxyPrim、purpose、visibility)
proxyPrim:rel(relationship)。指定一个代理 prim 用于视口加速显示。purpose:token,Fallback 值default。控制该 prim 参与渲染/预览/代理等用途的可见性。visibility:token,Fallback 值inherited。控制该 prim 的显隐,支持inherited/invisible。
这些属性使 DomeLight 与 OpenUSD 的变换、代理和可见性体系无缝衔接,例如可通过purpose让环境光不参与某类 passes,或用visibility在动画中关闭环境光。
源码级实现:OrientToStageUpAxis 与测试佐证
在生成代码之外,UsdLuxDomeLight提供了一个自定义方法OrientToStageUpAxis()(声明见 domeLight.h,实现见 domeLight.cpp):
- 调用
UsdGeomGetStageUpAxis()查询 stage 的上轴; - 若上轴为Z,则自动在穹顶上添加一个RotateX 90°的变换操作(op 后缀为
orientToStageUpAxis,对应 token 定义于 tokens.cpp),使穹顶顶部极点对齐到 Z 轴; - 若已存在同名 op,则视为已校正并直接返回;若上轴为 Y,则不创建任何 op(因为 +Y 对齐是默认朝向)。
这一行为有明确的单元测试覆盖:testenv/testUsdLuxLight.py 中的test_DomeLight_OrientToStageUpAxis验证了:Y-up 场景下不产生任何 xform op;将 stage 切换为 Z-up 后再调用,恰好产生一个TypeRotateX、数值为90.0的 op。这个 API 与DomeLight_1.poleAxis是互补的两种"对 Z-up 场景提供支持"的途径:前者通过代码便捷地补一个旋转 op,后者通过显式的poleAxistoken 声明意图。
对于生成 API,可参考 wrapDomeLight.cpp 中的 Python 绑定,在 Python 中可通过UsdLux.DomeLight.Define(stage, '/dome')创建、light.GetTextureFileAttr()读写纹理、light.OrientToStageUpAxis()校正朝向。
总结:选择哪个 DomeLight 版本
| 需求 | 推荐版本 |
|---|---|
| Y-up 场景、标准 OpenEXR latlong 贴图、无需特殊朝向 | DomeLight(默认 +Y 极点) |
| Z-up 场景,或需要显式声明穹顶朝向 | DomeLight_1+poleAxis(scene/Y/Z) |
| 需要代码动态校正 stage 上轴 | DomeLight+OrientToStageUpAxis() |
DomeLight 是 OpenUSD 中实现环境照明、IBL 和天空模拟的标准方案。核心要点可归纳为:贴图按 OpenEXR 2:1 经纬度约定制作;通过inputs:texture:file指定 HDR 贴图、用inputs:texture:format声明投影类型;用portals挂接 PortalLight 优化采样;必要时用DomeLight_1.poleAxis或OrientToStageUpAxis()适配 Z-up 管线。相关 Schema 源码位于 pxr/usd/usdLux/schema.usda,C++ 头文件与 Python 绑定分别位于 pxr/usd/usdLux/domeLight.h 与 pxr/usd/usdLux/wrapDomeLight.cpp,配套测试见 pxr/usd/usdLux/testenv/testUsdLuxLight.py,可供进一步深入研读。
【免费下载链接】OpenUSDUniversal Scene Description项目地址: https://gitcode.com/GitHub_Trending/ope/OpenUSD
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考