Blender V4.3
usd_writer_light.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2019 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4#include "usd_writer_light.hh"
6
7#include <pxr/usd/usdLux/diskLight.h>
8#include <pxr/usd/usdLux/distantLight.h>
9#include <pxr/usd/usdLux/rectLight.h>
10#include <pxr/usd/usdLux/shapingAPI.h>
11#include <pxr/usd/usdLux/sphereLight.h>
12
13#include "BLI_assert.h"
14#include "BLI_math_rotation.h"
15
16#include "DNA_light_types.h"
17
18namespace blender::io::usd {
19
21
22bool USDLightWriter::is_supported(const HierarchyContext * /*context*/) const
23{
24 return true;
25}
26
27static void set_light_extents(const pxr::UsdPrim &prim, const pxr::UsdTimeCode time)
28{
29 if (auto boundable = pxr::UsdGeomBoundable(prim)) {
30 pxr::VtArray<pxr::GfVec3f> extent;
31 pxr::UsdGeomBoundable::ComputeExtentFromPlugins(boundable, time, &extent);
32 boundable.CreateExtentAttr().Set(extent, time);
33 }
34
35 /* We're intentionally not setting an error on non-boundable lights,
36 * because overly noisy errors are annoying. */
37}
38
40{
41 pxr::UsdStageRefPtr stage = usd_export_context_.stage;
42 const pxr::SdfPath &usd_path = usd_export_context_.usd_path;
43 pxr::UsdTimeCode timecode = get_export_time_code();
44
45 const Light *light = static_cast<const Light *>(context.object->data);
46 pxr::UsdLuxLightAPI usd_light_api;
47
48 switch (light->type) {
49 case LA_AREA: {
50 switch (light->area_shape) {
51 case LA_AREA_RECT: {
52 pxr::UsdLuxRectLight rect_light = pxr::UsdLuxRectLight::Define(stage, usd_path);
53 rect_light.CreateWidthAttr().Set(light->area_size, timecode);
54 rect_light.CreateHeightAttr().Set(light->area_sizey, timecode);
55 usd_light_api = rect_light.LightAPI();
56 break;
57 }
58 case LA_AREA_SQUARE: {
59 pxr::UsdLuxRectLight rect_light = pxr::UsdLuxRectLight::Define(stage, usd_path);
60 rect_light.CreateWidthAttr().Set(light->area_size, timecode);
61 rect_light.CreateHeightAttr().Set(light->area_size, timecode);
62 usd_light_api = rect_light.LightAPI();
63 break;
64 }
65 case LA_AREA_DISK: {
66 pxr::UsdLuxDiskLight disk_light = pxr::UsdLuxDiskLight::Define(stage, usd_path);
67 disk_light.CreateRadiusAttr().Set(light->area_size / 2.0f, timecode);
68 usd_light_api = disk_light.LightAPI();
69 break;
70 }
71 case LA_AREA_ELLIPSE: {
72 /* An ellipse light deteriorates into a disk light. */
73 pxr::UsdLuxDiskLight disk_light = pxr::UsdLuxDiskLight::Define(stage, usd_path);
74 disk_light.CreateRadiusAttr().Set((light->area_size + light->area_sizey) / 4.0f,
75 timecode);
76 usd_light_api = disk_light.LightAPI();
77 break;
78 }
79 }
80 break;
81 }
82 case LA_LOCAL:
83 case LA_SPOT: {
84 pxr::UsdLuxSphereLight sphere_light = pxr::UsdLuxSphereLight::Define(stage, usd_path);
85 sphere_light.CreateRadiusAttr().Set(light->radius, timecode);
86 if (light->radius == 0.0f) {
87 sphere_light.CreateTreatAsPointAttr().Set(true, timecode);
88 }
89
90 if (light->type == LA_SPOT) {
91 pxr::UsdLuxShapingAPI shaping_api = pxr::UsdLuxShapingAPI::Apply(sphere_light.GetPrim());
92 if (shaping_api) {
93 shaping_api.CreateShapingConeAngleAttr().Set(RAD2DEGF(light->spotsize) / 2.0f, timecode);
94 shaping_api.CreateShapingConeSoftnessAttr().Set(light->spotblend, timecode);
95 }
96 }
97
98 usd_light_api = sphere_light.LightAPI();
99 break;
100 }
101 case LA_SUN: {
102 pxr::UsdLuxDistantLight distant_light = pxr::UsdLuxDistantLight::Define(stage, usd_path);
103 distant_light.CreateAngleAttr().Set(RAD2DEGF(light->sun_angle / 2.0f), timecode);
104 usd_light_api = distant_light.LightAPI();
105 break;
106 }
107 default:
109 break;
110 }
111
112 float intensity;
113 if (light->type == LA_SUN) {
114 /* Unclear why, but approximately matches Karma. */
115 intensity = light->energy / 4.0f;
116 }
117 else {
118 /* Convert from radiant flux to intensity. */
119 intensity = light->energy / M_PI;
120 }
121
122 usd_light_api.CreateIntensityAttr().Set(intensity, timecode);
123 usd_light_api.CreateExposureAttr().Set(0.0f, timecode);
124 usd_light_api.CreateColorAttr().Set(pxr::GfVec3f(light->r, light->g, light->b), timecode);
125 usd_light_api.CreateDiffuseAttr().Set(light->diff_fac, timecode);
126 usd_light_api.CreateSpecularAttr().Set(light->spec_fac, timecode);
127 usd_light_api.CreateNormalizeAttr().Set(true, timecode);
128
129 auto prim = usd_light_api.GetPrim();
130 write_id_properties(prim, light->id, timecode);
131
132 set_light_extents(usd_light_api.GetPrim(), timecode);
133}
134
135} // namespace blender::io::usd
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define M_PI
#define RAD2DEGF(_rad)
@ LA_AREA
@ LA_LOCAL
@ LA_SPOT
@ LA_SUN
@ LA_AREA_ELLIPSE
@ LA_AREA_SQUARE
@ LA_AREA_RECT
@ LA_AREA_DISK
const pxr::SdfPath & usd_path() const
pxr::UsdTimeCode get_export_time_code() const
void write_id_properties(const pxr::UsdPrim &prim, const ID &id, pxr::UsdTimeCode=pxr::UsdTimeCode::Default()) const
const USDExporterContext usd_export_context_
virtual bool is_supported(const HierarchyContext *context) const override
USDLightWriter(const USDExporterContext &ctx)
virtual void do_write(HierarchyContext &context) override
EvaluationStage stage
Definition deg_eval.cc:83
static void set_light_extents(const pxr::UsdPrim &prim, const pxr::UsdTimeCode time)