Skip to content

Commit 9088c1b

Browse files
anderslanglandspmolodo
authored andcommitted
[hdEmbree] Initial UsdLux reference implementation
This modifies the hdEmbree example plugin to do direct lighting so as to provide a reference implementation of the expected behaviour for UsdLux. If no lights are present in the stage, the old ambient occlusion path will be used.
1 parent dabdeb5 commit 9088c1b

File tree

8 files changed

+987
-65
lines changed

8 files changed

+987
-65
lines changed

pxr/imaging/plugin/hdEmbree/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pxr_plugin(hdEmbree
3131
PUBLIC_CLASSES
3232
config
3333
instancer
34+
light
3435
mesh
3536
meshSamplers
3637
renderBuffer

pxr/imaging/plugin/hdEmbree/light.cpp

+171
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
//
2+
// Copyright 2024 Pixar
3+
//
4+
// Licensed under the terms set forth in the LICENSE.txt file available at
5+
// https://openusd.org/license.
6+
//
7+
#include "pxr/imaging/plugin/hdEmbree/light.h"
8+
9+
#include "light.h"
10+
#include "pxr/imaging/plugin/hdEmbree/debugCodes.h"
11+
#include "pxr/imaging/plugin/hdEmbree/renderParam.h"
12+
#include "pxr/imaging/plugin/hdEmbree/renderer.h"
13+
14+
#include "pxr/imaging/hd/sceneDelegate.h"
15+
#include "pxr/imaging/hio/image.h"
16+
17+
#include <embree3/rtcore_buffer.h>
18+
#include <embree3/rtcore_scene.h>
19+
20+
#include <fstream>
21+
#include <sstream>
22+
#include <vector>
23+
24+
PXR_NAMESPACE_OPEN_SCOPE
25+
26+
HdEmbree_Light::HdEmbree_Light(SdfPath const& id, TfToken const& lightType)
27+
: HdLight(id) {
28+
if (id.IsEmpty()) {
29+
return;
30+
}
31+
32+
// Set the variant to the right type - Sync will fill rest of data
33+
if (lightType == HdSprimTypeTokens->cylinderLight) {
34+
_lightData.lightVariant = HdEmbree_Cylinder();
35+
} else if (lightType == HdSprimTypeTokens->diskLight) {
36+
_lightData.lightVariant = HdEmbree_Disk();
37+
} else if (lightType == HdSprimTypeTokens->rectLight) {
38+
// Get shape parameters
39+
_lightData.lightVariant = HdEmbree_Rect();
40+
} else if (lightType == HdSprimTypeTokens->sphereLight) {
41+
_lightData.lightVariant = HdEmbree_Sphere();
42+
} else {
43+
TF_WARN("HdEmbree - Unrecognized light type: %s", lightType.GetText());
44+
_lightData.lightVariant = HdEmbree_UnknownLight();
45+
}
46+
}
47+
48+
HdEmbree_Light::~HdEmbree_Light() = default;
49+
50+
void
51+
HdEmbree_Light::Sync(HdSceneDelegate *sceneDelegate,
52+
HdRenderParam *renderParam, HdDirtyBits *dirtyBits)
53+
{
54+
HD_TRACE_FUNCTION();
55+
HF_MALLOC_TAG_FUNCTION();
56+
57+
HdEmbreeRenderParam *embreeRenderParam =
58+
static_cast<HdEmbreeRenderParam*>(renderParam);
59+
60+
// calling this bumps the scene version and causes a re-render
61+
embreeRenderParam->AcquireSceneForEdit();
62+
63+
SdfPath const& id = GetId();
64+
65+
// Get _lightData's transform. We'll only consider the first time sample for now
66+
HdTimeSampleArray<GfMatrix4d, 1> xformSamples;
67+
sceneDelegate->SampleTransform(id, &xformSamples);
68+
_lightData.xformLightToWorld = GfMatrix4f(xformSamples.values[0]);
69+
_lightData.xformWorldToLight = _lightData.xformLightToWorld.GetInverse();
70+
_lightData.normalXformLightToWorld =
71+
_lightData.xformWorldToLight.ExtractRotationMatrix().GetTranspose();
72+
73+
// Store luminance parameters
74+
_lightData.intensity = sceneDelegate->GetLightParamValue(
75+
id, HdLightTokens->intensity).GetWithDefault(1.0f);
76+
_lightData.exposure = sceneDelegate->GetLightParamValue(
77+
id, HdLightTokens->exposure).GetWithDefault(0.0f);
78+
_lightData.color = sceneDelegate->GetLightParamValue(
79+
id, HdLightTokens->color).GetWithDefault(GfVec3f{1.0f, 1.0f, 1.0f});
80+
_lightData.normalize = sceneDelegate->GetLightParamValue(
81+
id, HdLightTokens->normalize).GetWithDefault(false);
82+
_lightData.colorTemperature = sceneDelegate->GetLightParamValue(
83+
id, HdLightTokens->colorTemperature).GetWithDefault(6500.0f);
84+
_lightData.enableColorTemperature = sceneDelegate->GetLightParamValue(
85+
id, HdLightTokens->enableColorTemperature).GetWithDefault(false);
86+
87+
// Get visibility
88+
_lightData.visible = sceneDelegate->GetVisible(id);
89+
90+
// Switch on the _lightData type and pull the relevant attributes from the scene
91+
// delegate
92+
std::visit([this, &id, &sceneDelegate](auto& typedLight) {
93+
using T = std::decay_t<decltype(typedLight)>;
94+
if constexpr (std::is_same_v<T, HdEmbree_UnknownLight>) {
95+
// Do nothing
96+
} else if constexpr (std::is_same_v<T, HdEmbree_Cylinder>) {
97+
typedLight = HdEmbree_Cylinder{
98+
sceneDelegate->GetLightParamValue(id, HdLightTokens->radius)
99+
.GetWithDefault(0.5f),
100+
sceneDelegate->GetLightParamValue(id, HdLightTokens->length)
101+
.GetWithDefault(1.0f),
102+
};
103+
} else if constexpr (std::is_same_v<T, HdEmbree_Disk>) {
104+
typedLight = HdEmbree_Disk{
105+
sceneDelegate->GetLightParamValue(id, HdLightTokens->radius)
106+
.GetWithDefault(0.5f),
107+
};
108+
} else if constexpr (std::is_same_v<T, HdEmbree_Rect>) {
109+
typedLight = HdEmbree_Rect{
110+
sceneDelegate->GetLightParamValue(id, HdLightTokens->width)
111+
.Get<float>(),
112+
sceneDelegate->GetLightParamValue(id, HdLightTokens->height)
113+
.Get<float>(),
114+
};
115+
} else if constexpr (std::is_same_v<T, HdEmbree_Sphere>) {
116+
typedLight = HdEmbree_Sphere{
117+
sceneDelegate->GetLightParamValue(id, HdLightTokens->radius)
118+
.GetWithDefault(0.5f),
119+
};
120+
} else {
121+
static_assert(false, "non-exhaustive _LightVariant visitor");
122+
}
123+
}, _lightData.lightVariant);
124+
125+
if (const auto value = sceneDelegate->GetLightParamValue(
126+
id, HdLightTokens->shapingFocus);
127+
value.IsHolding<float>()) {
128+
_lightData.shaping.focus = value.UncheckedGet<float>();
129+
}
130+
131+
if (const auto value = sceneDelegate->GetLightParamValue(
132+
id, HdLightTokens->shapingFocusTint);
133+
value.IsHolding<GfVec3f>()) {
134+
_lightData.shaping.focusTint = value.UncheckedGet<GfVec3f>();
135+
}
136+
137+
if (const auto value = sceneDelegate->GetLightParamValue(
138+
id, HdLightTokens->shapingConeAngle);
139+
value.IsHolding<float>()) {
140+
_lightData.shaping.coneAngle = value.UncheckedGet<float>();
141+
}
142+
143+
if (const auto value = sceneDelegate->GetLightParamValue(
144+
id, HdLightTokens->shapingConeSoftness);
145+
value.IsHolding<float>()) {
146+
_lightData.shaping.coneSoftness = value.UncheckedGet<float>();
147+
}
148+
149+
HdEmbreeRenderer *renderer = embreeRenderParam->GetRenderer();
150+
renderer->AddLight(id, this);
151+
152+
*dirtyBits &= ~HdLight::AllDirty;
153+
}
154+
155+
HdDirtyBits
156+
HdEmbree_Light::GetInitialDirtyBitsMask() const
157+
{
158+
return HdLight::AllDirty;
159+
}
160+
161+
void
162+
HdEmbree_Light::Finalize(HdRenderParam *renderParam)
163+
{
164+
auto* embreeParam = static_cast<HdEmbreeRenderParam*>(renderParam);
165+
166+
// Remove from renderer's light map
167+
HdEmbreeRenderer *renderer = embreeParam->GetRenderer();
168+
renderer->RemoveLight(GetId(), this);
169+
}
170+
171+
PXR_NAMESPACE_CLOSE_SCOPE

pxr/imaging/plugin/hdEmbree/light.h

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
//
2+
// Copyright 2024 Pixar
3+
//
4+
// Licensed under the terms set forth in the LICENSE.txt file available at
5+
// https://openusd.org/license.
6+
//
7+
#ifndef PXR_IMAGING_PLUGIN_HD_EMBREE_LIGHT_H
8+
#define PXR_IMAGING_PLUGIN_HD_EMBREE_LIGHT_H
9+
10+
#include "pxr/base/gf/vec3f.h"
11+
#include "pxr/base/gf/matrix3f.h"
12+
#include "pxr/base/gf/matrix4f.h"
13+
#include "pxr/imaging/hd/light.h"
14+
15+
#include <embree3/rtcore_common.h>
16+
#include <embree3/rtcore_geometry.h>
17+
18+
#include <limits>
19+
#include <variant>
20+
21+
PXR_NAMESPACE_OPEN_SCOPE
22+
23+
class HdEmbreeRenderer;
24+
25+
struct HdEmbree_UnknownLight
26+
{};
27+
struct HdEmbree_Cylinder
28+
{
29+
float radius;
30+
float length;
31+
};
32+
33+
struct HdEmbree_Disk
34+
{
35+
float radius;
36+
};
37+
38+
struct HdEmbree_Rect
39+
{
40+
float width;
41+
float height;
42+
};
43+
44+
struct HdEmbree_Sphere
45+
{
46+
float radius;
47+
};
48+
49+
using HdEmbree_LightVariant = std::variant<
50+
HdEmbree_UnknownLight,
51+
HdEmbree_Cylinder,
52+
HdEmbree_Disk,
53+
HdEmbree_Rect,
54+
HdEmbree_Sphere>;
55+
56+
struct HdEmbree_Shaping
57+
{
58+
GfVec3f focusTint;
59+
float focus = 0.0f;
60+
float coneAngle = 180.0f;
61+
float coneSoftness = 0.0f;
62+
};
63+
64+
struct HdEmbree_LightData
65+
{
66+
GfMatrix4f xformLightToWorld;
67+
GfMatrix3f normalXformLightToWorld;
68+
GfMatrix4f xformWorldToLight;
69+
GfVec3f color;
70+
float intensity = 1.0f;
71+
float exposure = 0.0f;
72+
float colorTemperature = 6500.0f;
73+
bool enableColorTemperature = false;
74+
HdEmbree_LightVariant lightVariant;
75+
bool normalize = false;
76+
bool visible = true;
77+
HdEmbree_Shaping shaping;
78+
};
79+
80+
class HdEmbree_Light final : public HdLight
81+
{
82+
public:
83+
HdEmbree_Light(SdfPath const& id, TfToken const& lightType);
84+
~HdEmbree_Light();
85+
86+
/// Synchronizes state from the delegate to this object.
87+
void Sync(HdSceneDelegate* sceneDelegate,
88+
HdRenderParam* renderParam,
89+
HdDirtyBits* dirtyBits) override;
90+
91+
/// Returns the minimal set of dirty bits to place in the
92+
/// change tracker for use in the first sync of this prim.
93+
/// Typically this would be all dirty bits.
94+
HdDirtyBits GetInitialDirtyBitsMask() const override;
95+
96+
void Finalize(HdRenderParam *renderParam) override;
97+
98+
HdEmbree_LightData const& LightData() const {
99+
return _lightData;
100+
}
101+
102+
private:
103+
HdEmbree_LightData _lightData;
104+
};
105+
106+
107+
PXR_NAMESPACE_CLOSE_SCOPE
108+
109+
#endif

pxr/imaging/plugin/hdEmbree/renderBuffer.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ class HdEmbreeRenderBuffer : public HdRenderBuffer
166166
// For multisampled buffers: the input write buffer.
167167
std::vector<uint8_t> _sampleBuffer;
168168
// For multisampled buffers: the sample count buffer.
169-
std::vector<uint8_t> _sampleCount;
169+
std::vector<uint32_t> _sampleCount;
170170

171171
// The number of callers mapping this buffer.
172172
std::atomic<int> _mappers;

pxr/imaging/plugin/hdEmbree/renderDelegate.cpp

+19-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "pxr/imaging/plugin/hdEmbree/config.h"
1010
#include "pxr/imaging/plugin/hdEmbree/instancer.h"
11+
#include "pxr/imaging/plugin/hdEmbree/light.h"
1112
#include "pxr/imaging/plugin/hdEmbree/renderParam.h"
1213
#include "pxr/imaging/plugin/hdEmbree/renderPass.h"
1314

@@ -35,6 +36,10 @@ const TfTokenVector HdEmbreeRenderDelegate::SUPPORTED_SPRIM_TYPES =
3536
{
3637
HdPrimTypeTokens->camera,
3738
HdPrimTypeTokens->extComputation,
39+
HdPrimTypeTokens->cylinderLight,
40+
HdPrimTypeTokens->diskLight,
41+
HdPrimTypeTokens->rectLight,
42+
HdPrimTypeTokens->sphereLight,
3843
};
3944

4045
const TfTokenVector HdEmbreeRenderDelegate::SUPPORTED_BPRIM_TYPES =
@@ -147,7 +152,7 @@ HdEmbreeRenderDelegate::_Initialize()
147152
// Store top-level embree objects inside a render param that can be
148153
// passed to prims during Sync(). Also pass a handle to the render thread.
149154
_renderParam = std::make_shared<HdEmbreeRenderParam>(
150-
_rtcDevice, _rtcScene, &_renderThread, &_sceneVersion);
155+
_rtcDevice, _rtcScene, &_renderThread, &_renderer, &_sceneVersion);
151156

152157
// Pass the scene handle to the renderer.
153158
_renderer.SetScene(_rtcScene);
@@ -230,7 +235,7 @@ HdAovDescriptor
230235
HdEmbreeRenderDelegate::GetDefaultAovDescriptor(TfToken const& name) const
231236
{
232237
if (name == HdAovTokens->color) {
233-
return HdAovDescriptor(HdFormatUNorm8Vec4, true,
238+
return HdAovDescriptor(HdFormatFloat32Vec4, true,
234239
VtValue(GfVec4f(0.0f)));
235240
} else if (name == HdAovTokens->normal || name == HdAovTokens->Neye) {
236241
return HdAovDescriptor(HdFormatFloat32Vec3, false,
@@ -331,6 +336,12 @@ HdEmbreeRenderDelegate::CreateSprim(TfToken const& typeId,
331336
return new HdCamera(sprimId);
332337
} else if (typeId == HdPrimTypeTokens->extComputation) {
333338
return new HdExtComputation(sprimId);
339+
} else if (typeId == HdPrimTypeTokens->light ||
340+
typeId == HdPrimTypeTokens->diskLight ||
341+
typeId == HdPrimTypeTokens->rectLight ||
342+
typeId == HdPrimTypeTokens->sphereLight ||
343+
typeId == HdPrimTypeTokens->cylinderLight) {
344+
return new HdEmbree_Light(sprimId, typeId);
334345
} else {
335346
TF_CODING_ERROR("Unknown Sprim Type %s", typeId.GetText());
336347
}
@@ -347,6 +358,12 @@ HdEmbreeRenderDelegate::CreateFallbackSprim(TfToken const& typeId)
347358
return new HdCamera(SdfPath::EmptyPath());
348359
} else if (typeId == HdPrimTypeTokens->extComputation) {
349360
return new HdExtComputation(SdfPath::EmptyPath());
361+
} else if (typeId == HdPrimTypeTokens->light ||
362+
typeId == HdPrimTypeTokens->diskLight ||
363+
typeId == HdPrimTypeTokens->rectLight ||
364+
typeId == HdPrimTypeTokens->sphereLight ||
365+
typeId == HdPrimTypeTokens->cylinderLight) {
366+
return new HdEmbree_Light(SdfPath::EmptyPath(), typeId);
350367
} else {
351368
TF_CODING_ERROR("Unknown Sprim Type %s", typeId.GetText());
352369
}

0 commit comments

Comments
 (0)