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.8、intensity = 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 中的intensity、color等被标记为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 } )两个关键细节:
- 该属性带
uniform修饰符,表示在整个场景中它是一个均匀(uniform)值,不会被时间采样或分块求值。 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 → Boundable并prepend apiSchemas = ["LightAPI"](见 schema.usda)获得了完整的灯光通用属性。从源码结构看,所有内建光源(RectLight、SphereLight、DistantLight、PortalLight 等)共享这套 LightAPI 参数体系,掌握它们即可通用于所有 usdLux 灯光。
以下参数均定义于 LightAPI(schema.usda),DiskLight 可直接使用:
| 属性 | USD 类型 | 默认值 | 含义 |
|---|---|---|---|
inputs:intensity | float | 1 | 线性缩放灯光亮度。规范上,intensity=1、exposure=0的白光在 RGB 渲染器中于传感器平面正入射时产生 [1,1,1] 像素值,即亮度 1 nit(cd/m²);intensity=2则为 2 nit |
inputs:exposure | float | 0 | 以 2 的幂次指数缩放亮度(类似 F-stop 曝光控制),L = L · 2^exposure,与 intensity 相乘生效 |
inputs:color | color3f | (1, 1, 1) | 发光颜色(在渲染色彩空间中定义),L_color = L_scalar · color |
inputs:diffuse | float | 1.0 | 灯光对材质漫反射响应的倍率(非物理控制),用于精细调光 |
inputs:specular | float | 1.0 | 灯光对材质高光响应的倍率(非物理控制) |
inputs:normalize | bool | 0 | 是否将光强按发光面积归一化,使不同尺寸盘片的单位亮度一致(displayGroup = "Refine") |
inputs:enableColorTemperature | bool | false | 是否启用色温控制 |
inputs:colorTemperature | float | 6500 | 色温(开尔文),有效范围 1000~10000,默认 6500 对应 D65 白点,值越低越暖、越高越冷;仅当enableColorTemperature为 true 时生效 |
light:shaderId | token | "" | 灯光的着色器 ID(DiskLight 覆盖为"DiskLight") |
inputs:materialSyncMode | token | 见源码 | 材质同步模式,允许值包括materialGlowTintsLight、independent、noMaterialResponse |
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 = 1与collection: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 类型 | 默认值 | 含义 |
|---|---|---|---|
proxyPrim | rel(关系) | — | 代理 prim 关系,用于在交互视口中以轻量几何替代渲染几何 |
purpose | token | default | prim 的用途(default/render/proxy/guide),决定其在各阶段的可见性。在 usdview 中,purpose = "render"的物体只参与渲染而不参与视口选择等交互 |
visibility | token | inherited | 可见性,可取inherited/invisible,invisible时该灯不参与照明计算 |
六、源码级原理: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 直接相关的验证包括:
- 类型可定义性(第 352 行):
UsdLux.DiskLight.Define(stage, "/DiskLight")返回有效的 Schema 对象,验证 DiskLight 是注册在 usdLux 插件中的可实例化灯光类型; - 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 一致;
- 默认半径 0.5 → extent
- 尺寸属性注册表(第 441 行):
'DiskLight' : ['radius']表明 radius 是 DiskLight 唯一影响包围盒的尺寸属性; - 灯光类型枚举(第 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 的解析机制。
九、实践要点小结
- 默认发光方向:DiskLight 在自身局部坐标中沿-Z 轴单向发光,布置场景时需通过
xformOp旋转/平移将盘面对准被照物体; - 半径即覆盖范围:
inputs:radius默认 0.5,增大半径扩大照明范围并柔化阴影,同时 extent 随之线性增大; - 亮度控制:优先使用
intensity(线性)与exposure(2 的幂次)组合调光;示例中intensity = 20属于较强的补光设置,实际取值需结合渲染器与场景尺度调整; - 颜色与色温:
color直接与亮度相乘;需要物理色温时可启用enableColorTemperature并设置colorTemperature(1000~10000K); - 薄盘包围盒:DiskLight 的 extent 在 Z 轴为 0,交互拾取与剔除行为与 RectLight 一致,与 SphereLight 等有厚度的光源不同;
- 继承体系:DiskLight 的全部通用属性来自
LightAPI,掌握 LightAPI 参数即可一通百通地使用 usdLux 内建灯光。
通过本文的文档解读与源码对照,读者可以在 OpenUSD 项目中准确地以手写 USD 或程序化 API(C++/Python)方式创建、配置 DiskLight,并理解其渲染集成与包围盒计算的底层机制。
【免费下载链接】OpenUSDUniversal Scene Description项目地址: https://gitcode.com/GitHub_Trending/ope/OpenUSD
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考