OpenUSD 灯光入门:深入解析 usdLux DiskLight 圆盘灯 Schema 与实战
2026/9/17 3:17:43 网站建设 项目流程

OpenUSD 灯光入门:深入解析 usdLux DiskLight 圆盘灯 Schema 与实战

【免费下载链接】OpenUSDUniversal Scene Description项目地址: https://gitcode.com/GitHub_Trending/ope/OpenUSD

导读

DiskLight(圆盘灯)是 OpenUSD 中 usdLux 核心库提供的一种内建(intrinsic)光源类型,它从位于 XY 平面中心的一个圆形盘片沿 -Z 轴单向发光,用于模拟摄影软箱(soft box)、线性灯、荧光灯与灯板等现实照明设备。本文以 OpenUSD 仓库中 DiskLight.md 文档为骨架,结合 schema.usda 的 Schema 定义、diskLight.h 的 C++ API 以及 testUsdLuxLight.py 的测试用例,完整讲解 DiskLight 的属性体系、USD 场景编写方法、继承自 LightAPI 的灯光参数,以及 extent 包围盒计算的底层实现,读完即可在 USD 场景中正确配置并使用 DiskLight。

一、DiskLight 是什么:核心定义与适用场景

根据 Schema 文档的定义,DiskLight 是一种内建光源(intrinsic light):

Light emitted from one side of a circular disk. The disk is centered in the XY plane and emits light along the -Z axis.

即:发光面是一个位于XY 平面中心的圆盘,光线只从圆盘的一侧沿-Z 轴方向向外发射。这与 RectLight(矩形灯)类似,但发光区域为圆形,因此非常适合模拟:

  • 摄影用的柔光箱(soft boxes)——圆形柔光箱在真实摄影中非常常见;
  • 线性灯 / 荧光灯管(linear lights, fluorescent lights)——通过长条状的圆盘排列或组合实现;
  • 灯板(light panels)——大面积均匀发光的影视/摄影灯板。

由于它是「有边界、可求范围」的光源,DiskLight 在 usdLux 的类型体系中归属于可包围盒光源(BoundableLightBase),这一点会在后文源码部分详细展开。

二、快速上手:完整的 USD 场景示例

原文档给出了一个可直接使用的完整 USD 场景:场景中放置了一个radius = 0.8intensity = 20的 DiskLight,并配有 Sphere 与 Cube 作为被照明物体。完整代码如下:

#usda 1.0 ( upAxis = "Y" ) def Scope "Lights" { def DiskLight "Light1" { float inputs:radius = 0.8 color3f inputs:color = (1, 1, 1) float inputs:intensity = 20.0 double3 xformOp:translate = (4, 0, 1) uniform token[] xformOpOrder = ["xformOp:translate"] } } def Xform "TestGeom" { def Sphere "Sphere1" { token purpose = "render" color3f[] primvars:displayColor = [(1, 1, 1)] ( interpolation = "constant" ) double3 xformOp:translate = (0, 0, -2) uniform token[] xformOpOrder = ["xformOp:translate"] } def Cube "Cube" { token purpose = "render" color3f[] primvars:displayColor = [(1, 1, 1)] ( interpolation = "constant" ) double size = 8 double3 xformOp:translate = (0, 0, -8) uniform token[] xformOpOrder = ["xformOp:translate"] } }

逐行拆解这个示例的关键点:

元素说明
def DiskLight "Light1"LightsScope 下定义一个 DiskLight 类型的 prim,prim 类型名与 Schema 类型名完全一致
float inputs:radius = 0.8设置圆盘发光面半径。注意原文档特意省略了该属性的默认值行注释,因为 0.8 是显式覆盖了 Schema 默认值 0.5(见下文属性详解)
color3f inputs:color = (1, 1, 1)发光颜色,此处为纯白,继承自 LightAPI
float inputs:intensity = 20.0光强缩放系数,继承自 LightAPI,此处覆盖默认值 1.0 以增强照明效果
double3 xformOp:translate = (4, 0, 1)将灯放置在 (4, 0, 1),灯默认发光方向为自身局部坐标的 -Z 轴
uniform token[] xformOpOrder声明变换操作顺序,USD 的标准变换约定
def Sphere/def Cube被照明几何体,均设置purpose = "render",Sphere 置于 (0,0,-2) 正对灯光 -Z 发射方向,Cube 置于 (0,0,-8)

整个场景的upAxis = "Y"表示 Y 轴向上。灯光位于 X=4 处斜向照射几何体,Sphere 与 Cube 依次排列在灯光的 -Z 发射方向上,从而在渲染中形成由近及远的受光层次。

三、DiskLight 专属属性详解

DiskLight 自身(在 Schema 层面)只声明了一个专属属性,另一个是继承自 LightAPI 的light:shaderId重写。

3.1 inputs:radius

  • USD 类型float
  • 默认值(Fallback value)0.5
  • 含义:圆盘发光面的半径。半径越大,灯光整体的覆盖范围(reach)越大,但单位面积上的发光强度分布也随之变化。

从 schema.usda 可以看到该属性的完整声明:

float inputs:radius = 0.5 ( displayGroup = "Geometry" displayName = "Radius" doc = "Radius of the disk." customData = { token apiName = "radius" } )

值得注意的是displayGroup = "Geometry"displayName = "Radius",这两个元数据用于在 DCC 工具(如 Maya、Katana、Houdini 的 USD 插件)的 UI 中归类与显示该属性——它属于「几何/形状」分组而非「基础」分组。这与 LightAPI 中的intensitycolor等被标记为displayGroup = "Basic"的属性形成对比。

半径与渲染效果的关系:半径不仅决定发光面的物理大小,还直接影响阴影的软硬程度——在其他条件不变时,更大的发光面意味着更柔和的阴影边缘(类似摄影中更大的柔光箱),因为从盘面上不同点发出的光线以不同的角度到达被照物体表面。该属性在 C++ 层的访问 API 为GetRadiusAttr()/CreateRadiusAttr(),详见 diskLight.h。

3.2 light:shaderId

  • USD 类型token
  • 默认值DiskLight
  • 含义:DiskLight 对应的着色器标识符(shader ID)。

在 schema.usda 中其声明为:

uniform token light:shaderId = "DiskLight" ( customData = { bool apiSchemaOverride = true } )

两个关键细节:

  1. 该属性带uniform修饰符,表示在整个场景中它是一个均匀(uniform)值,不会被时间采样或分块求值。
  2. apiSchemaOverride = true表明这是对 LightAPI 中同名属性(LightAPI 中light:shaderId默认值为空字符串"")的子类覆盖——DiskLight 将自己的默认 shaderId 固定为类型名"DiskLight"

原文档特别指出:USD 会同时注册一个标识符为"DiskLight"、源类型(source type)为"USD"的 Sdr shader 节点,用来对应灯光的各 inputs。这意味着 DiskLight 的inputs:*属性会被 Sdr(Shader Definition Registry,着色器定义注册表)识别为着色器输入,渲染器可以通过 Sdr 机制查询到该光源的定义,从而在渲染器侧完成材质/光源的映射。

四、继承自 LightAPI 的灯光参数(Intensity / Color / Exposure 等)

DiskLight 通过继承链DiskLight → BoundableLightBase → Boundableprepend apiSchemas = ["LightAPI"](见 schema.usda)获得了完整的灯光通用属性。从源码结构看,所有内建光源(RectLight、SphereLight、DistantLight、PortalLight 等)共享这套 LightAPI 参数体系,掌握它们即可通用于所有 usdLux 灯光。

以下参数均定义于 LightAPI(schema.usda),DiskLight 可直接使用:

属性USD 类型默认值含义
inputs:intensityfloat1线性缩放灯光亮度。规范上,intensity=1exposure=0的白光在 RGB 渲染器中于传感器平面正入射时产生 [1,1,1] 像素值,即亮度 1 nit(cd/m²);intensity=2则为 2 nit
inputs:exposurefloat0以 2 的幂次指数缩放亮度(类似 F-stop 曝光控制),L = L · 2^exposure,与 intensity 相乘生效
inputs:colorcolor3f(1, 1, 1)发光颜色(在渲染色彩空间中定义),L_color = L_scalar · color
inputs:diffusefloat1.0灯光对材质漫反射响应的倍率(非物理控制),用于精细调光
inputs:specularfloat1.0灯光对材质高光响应的倍率(非物理控制)
inputs:normalizebool0是否将光强按发光面积归一化,使不同尺寸盘片的单位亮度一致(displayGroup = "Refine"
inputs:enableColorTemperatureboolfalse是否启用色温控制
inputs:colorTemperaturefloat6500色温(开尔文),有效范围 1000~10000,默认 6500 对应 D65 白点,值越低越暖、越高越冷;仅当enableColorTemperature为 true 时生效
light:shaderIdtoken""灯光的着色器 ID(DiskLight 覆盖为"DiskLight"
inputs:materialSyncModetoken见源码材质同步模式,允许值包括materialGlowTintsLightindependentnoMaterialResponse

4.1 亮度单位的规范性说明

在 schema.usda 的 LightAPI 文档中,对亮度单位有明确的规范性定义:当前绝大多数消费 OpenUSD 的渲染器是 RGB 渲染器而非光谱渲染器,RGB 渲染器中传输的每个通道(R/G/B)代表「光谱曝光分布 × 传感器响应函数」的卷积(如 CIE Illuminant D65 × CIE 1931)。因此,默认灯光的发射(intensity=1, color=[1,1,1])被定义为:发光色度与渲染色彩空间白点一致的 Illuminant D 光谱分布,其亮度恰为1 nit (cd/m²)。这也是为什么示例中 DiskLight 需要intensity = 20才能获得明显照明——默认 1 nit 是「直接被看到」的基准亮度。

4.2 灯光链接(Linking)

LightAPI 还预置了collection:lightLink:includeRoot = 1collection:shadowLink:includeRoot = 1两个属性(schema.usda),对应GetLightLinkCollection()GetShadowLinkCollection()两个集合接口。Linking 用于控制一盏灯照亮哪些几何体、以及哪些几何体对该灯投射阴影。默认includeRoot为 true,即灯光默认照亮全部物体;若只想照亮特定集合,可显式排除其余物体,或将 includeRoot 设为 false 后显式包含目标物体。

五、继承属性:Boundable / Xformable / Imageable

原文档在「Inherited Properties」小节列出了 DiskLight 从三个基类继承的属性,完整清单如下:

5.1 继承自 Boundable

extent

  • USD 类型float3[]
  • 含义:包围盒范围(extent),用于空间加速与剔除。DiskLight 的 Schema 声明了implementsComputeExtent = 1(见 schema.usda),表示其拥有可计算 extent 的实现

关于 extent 的数值:测试用例 testUsdLuxLight.py 验证了它的计算规则——当使用默认半径 0.5 时,extent 为[(-0.5, -0.5, 0.0), (0.5, 0.5, 0.0)];当通过diskLight.CreateRadiusAttr(5.0)将半径改为 5.0 后,extent 变为[(-5.0, -5.0, 0.0), (5.0, 5.0, 0.0)]。可见DiskLight 的 extent 与半径严格成正比,且在 Z 轴上厚度为零(发光面为 XY 平面内的薄盘)。这一点与 RectLight 完全一致(同测试中 RectLight 的 extent 由宽高决定,Z 轴同样为 0),而与 SphereLight、CylinderLight 的 Z 轴有厚度的 extent 不同。

5.2 继承自 Xformable

xformOpOrder

  • USD 类型token[]
  • 含义:Xform 变换操作顺序。与所有可变换 prim 相同,DiskLight 的朝向与位置由xformOp:*系列操作及其顺序决定。特别注意发光方向是局部坐标 -Z,因此要通过旋转(如xformOp:rotateXYZ)调整灯光照射方向。

5.3 继承自 Imageable

属性USD 类型默认值含义
proxyPrimrel(关系)代理 prim 关系,用于在交互视口中以轻量几何替代渲染几何
purposetokendefaultprim 的用途(default/render/proxy/guide),决定其在各阶段的可见性。在 usdview 中,purpose = "render"的物体只参与渲染而不参与视口选择等交互
visibilitytokeninherited可见性,可取inherited/invisibleinvisible时该灯不参与照明计算

六、源码级原理:Schema 定义与 C++ API

6.1 Schema 声明(schema.usda)

DiskLight 的完整 Schema 声明位于 schema.usda:

class DiskLight "DiskLight" ( customData = { dictionary extraPlugInfo = { bool implementsComputeExtent = 1 } } inherits = </BoundableLightBase> doc = """Light emitted from one side of a circular disk. The disk is centered in the XY plane and emits light along the -Z axis.""" ) { uniform token light:shaderId = "DiskLight" ( customData = { bool apiSchemaOverride = true } ) float inputs:radius = 0.5 ( displayGroup = "Geometry" displayName = "Radius" doc = "Radius of the disk." customData = { token apiName = "radius" } ) }

要点:

  • inherits = </BoundableLightBase>:直接继承可包围盒灯光基类,因此具备 extent 计算能力;
  • implementsComputeExtent = 1:提示系统该类型有自定义的 extent 计算实现,而非使用通用遍历;
  • 全篇唯一的新增属性只有inputs:radius,其余能力全部来自继承链。

6.2 C++ 类型体系(diskLight.h)

在 C++ 侧,DiskLight 对应UsdLuxDiskLight类,定义于 diskLight.h:

class UsdLuxDiskLight : public UsdLuxBoundableLightBase

关键信息:

  • schemaKind = UsdSchemaKind::ConcreteTyped(diskLight.h):这是一个具体类型化(concrete typed)Schema,可以直接用def DiskLight在 USD 文件中实例化;
  • 提供工厂方法UsdLuxDiskLight::Get(stage, path)UsdLuxDiskLight::Define(stage, path)(diskLight.h):Get用于获取已存在的符合该 Schema 的 prim,Define用于在指定路径上创建/确保存在符合该 Schema 的 prim;
  • 属性访问 API:GetRadiusAttr()获取 radius 属性句柄,CreateRadiusAttr(defaultValue, writeSparsely)创建并可选地稀疏写入默认值(diskLight.h)。

6.3 Python 绑定

Python 侧通过 wrapDiskLight.cpp 导出UsdLux.DiskLight模块,典型用法即测试用例所示:

import UsdLux diskLight = UsdLux.DiskLight.Define(stage, "/DiskLight") diskLight.CreateRadiusAttr(5.0)

七、测试验证:extent 与包围盒计算

testUsdLuxLight.py 是 usdLux 灯光体系的综合测试,其中与 DiskLight 直接相关的验证包括:

  1. 类型可定义性(第 352 行):UsdLux.DiskLight.Define(stage, "/DiskLight")返回有效的 Schema 对象,验证 DiskLight 是注册在 usdLux 插件中的可实例化灯光类型;
  2. extent 与包围盒计算(第 364、375-376 行):
    • 默认半径 0.5 → extent[(-0.5, -0.5, 0.0), (0.5, 0.5, 0.0)]
    • CreateRadiusAttr(5.0)→ extent[(-5.0, -5.0, 0.0), (5.0, 5.0, 0.0)]
    • 验证函数_VerifyExtentAndBBox同时检查ComputeLocalBound(time, "default")返回的Gf.BBox3d是否与 extent 一致;
  3. 尺寸属性注册表(第 441 行):'DiskLight' : ['radius']表明 radius 是 DiskLight 唯一影响包围盒的尺寸属性;
  4. 灯光类型枚举(第 452-464 行):DiskLight出现在所有 BoundableLightBase/NonboundableLightBase 派生类型列表中,由插件注册表Plug.Registry().GetPluginWithName("usdLux").DeclaresType验证。

这些测试从侧面印证了第 5.1 节的结论:DiskLight 的 extent 完全由 radius 决定,且为 XY 平面内的薄盘(Z 轴厚度为 0),这对渲染器的包围盒剔除与交互选择具有重要意义。

八、渲染集成与扩展:从 Sdr 到各渲染器

DiskLight 作为内建光源,其渲染路径的核心是light:shaderId

  • Sdr 注册:USD 会为 DiskLight 注册源类型(source type)为"USD"、标识符为"DiskLight"的 Sdr shader 节点,其输入对应灯光的inputs:*属性(含继承自 LightAPI 的全部参数)。渲染器可通过 Sdr 查询该节点定义,从而在渲染时实例化对应的光源 shader;
  • RenderMan 输出:原文档展示的lux_disk_light.png即为该 USD layer 在 RenderMan 中的渲染结果(Sphere 与 Cube 被 DiskLight 照亮的效果);
  • usdview 验证:可直接用usdview打开包含 DiskLight 的 USD 文件,通过交互视口调整 radius、intensity 等参数并实时观察照明变化;
  • 插件扩展:DiskLight 与 RectLight、SphereLight、CylinderLight、DistantLight、DomeLight、PortalLight 等共同构成 usdLux 的内建灯光家族(见 testUsdLuxLight.py 的完整类型清单),各渲染器插件(如 third_party/renderman)会针对这些 shaderId 提供对应的转换与实现。如需自定义灯光行为,可参考PluginLight与 LightDefParser 的解析机制。

九、实践要点小结

  1. 默认发光方向:DiskLight 在自身局部坐标中沿-Z 轴单向发光,布置场景时需通过xformOp旋转/平移将盘面对准被照物体;
  2. 半径即覆盖范围inputs:radius默认 0.5,增大半径扩大照明范围并柔化阴影,同时 extent 随之线性增大;
  3. 亮度控制:优先使用intensity(线性)与exposure(2 的幂次)组合调光;示例中intensity = 20属于较强的补光设置,实际取值需结合渲染器与场景尺度调整;
  4. 颜色与色温color直接与亮度相乘;需要物理色温时可启用enableColorTemperature并设置colorTemperature(1000~10000K);
  5. 薄盘包围盒:DiskLight 的 extent 在 Z 轴为 0,交互拾取与剔除行为与 RectLight 一致,与 SphereLight 等有厚度的光源不同;
  6. 继承体系:DiskLight 的全部通用属性来自LightAPI,掌握 LightAPI 参数即可一通百通地使用 usdLux 内建灯光。

通过本文的文档解读与源码对照,读者可以在 OpenUSD 项目中准确地以手写 USD 或程序化 API(C++/Python)方式创建、配置 DiskLight,并理解其渲染集成与包围盒计算的底层机制。

【免费下载链接】OpenUSDUniversal Scene Description项目地址: https://gitcode.com/GitHub_Trending/ope/OpenUSD

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询