diff --git a/pxr/imaging/plugin/hdEmbree/CMakeLists.txt b/pxr/imaging/plugin/hdEmbree/CMakeLists.txt index c3c92aa552..98f745631e 100644 --- a/pxr/imaging/plugin/hdEmbree/CMakeLists.txt +++ b/pxr/imaging/plugin/hdEmbree/CMakeLists.txt @@ -49,6 +49,9 @@ pxr_plugin(hdEmbree debugCodes implicitSurfaceSceneIndexPlugin + PRIVATE_HEADERS + pxrPbrt/pbrtUtils.h + RESOURCE_FILES plugInfo.json diff --git a/pxr/imaging/plugin/hdEmbree/light.cpp b/pxr/imaging/plugin/hdEmbree/light.cpp index d83d07b59f..2388d346fe 100644 --- a/pxr/imaging/plugin/hdEmbree/light.cpp +++ b/pxr/imaging/plugin/hdEmbree/light.cpp @@ -97,6 +97,8 @@ HdEmbree_Light::HdEmbree_Light(SdfPath const& id, TfToken const& lightType) _lightData.lightVariant = HdEmbree_Cylinder(); } else if (lightType == HdSprimTypeTokens->diskLight) { _lightData.lightVariant = HdEmbree_Disk(); + } else if (lightType == HdSprimTypeTokens->distantLight) { + _lightData.lightVariant = HdEmbree_Distant(); } else if (lightType == HdSprimTypeTokens->domeLight) { _lightData.lightVariant = HdEmbree_Dome(); } else if (lightType == HdSprimTypeTokens->rectLight) { @@ -180,6 +182,12 @@ HdEmbree_Light::Sync(HdSceneDelegate *sceneDelegate, sceneDelegate->GetLightParamValue(id, HdLightTokens->radius) .GetWithDefault(0.5f), }; + } else if constexpr (std::is_same_v) { + typedLight = HdEmbree_Distant{ + float(GfDegreesToRadians( + sceneDelegate->GetLightParamValue(id, HdLightTokens->angle) + .GetWithDefault(0.53f) / 2.0f)), + }; } else if constexpr (std::is_same_v) { typedLight = HdEmbree_Dome{}; _SyncLightTexture(id, _lightData, sceneDelegate); diff --git a/pxr/imaging/plugin/hdEmbree/light.h b/pxr/imaging/plugin/hdEmbree/light.h index 99d29837d6..3f756ebedf 100644 --- a/pxr/imaging/plugin/hdEmbree/light.h +++ b/pxr/imaging/plugin/hdEmbree/light.h @@ -35,6 +35,11 @@ struct HdEmbree_Disk float radius; }; +struct HdEmbree_Distant +{ + float halfAngleRadians; +}; + // Needed for HdEmbree_LightVariant struct HdEmbree_Dome {}; @@ -54,6 +59,7 @@ using HdEmbree_LightVariant = std::variant< HdEmbree_UnknownLight, HdEmbree_Cylinder, HdEmbree_Disk, + HdEmbree_Distant, HdEmbree_Dome, HdEmbree_Rect, HdEmbree_Sphere>; diff --git a/pxr/imaging/plugin/hdEmbree/renderDelegate.cpp b/pxr/imaging/plugin/hdEmbree/renderDelegate.cpp index 27cad002da..3050fc6d03 100644 --- a/pxr/imaging/plugin/hdEmbree/renderDelegate.cpp +++ b/pxr/imaging/plugin/hdEmbree/renderDelegate.cpp @@ -38,6 +38,7 @@ const TfTokenVector HdEmbreeRenderDelegate::SUPPORTED_SPRIM_TYPES = HdPrimTypeTokens->extComputation, HdPrimTypeTokens->cylinderLight, HdPrimTypeTokens->diskLight, + HdPrimTypeTokens->distantLight, HdPrimTypeTokens->domeLight, HdPrimTypeTokens->rectLight, HdPrimTypeTokens->sphereLight, @@ -338,6 +339,7 @@ HdEmbreeRenderDelegate::CreateSprim(TfToken const& typeId, } else if (typeId == HdPrimTypeTokens->extComputation) { return new HdExtComputation(sprimId); } else if (typeId == HdPrimTypeTokens->light || + typeId == HdPrimTypeTokens->distantLight || typeId == HdPrimTypeTokens->diskLight || typeId == HdPrimTypeTokens->domeLight || typeId == HdPrimTypeTokens->rectLight || @@ -361,6 +363,7 @@ HdEmbreeRenderDelegate::CreateFallbackSprim(TfToken const& typeId) } else if (typeId == HdPrimTypeTokens->extComputation) { return new HdExtComputation(SdfPath::EmptyPath()); } else if (typeId == HdPrimTypeTokens->light || + typeId == HdPrimTypeTokens->distantLight || typeId == HdPrimTypeTokens->diskLight || typeId == HdPrimTypeTokens->domeLight || typeId == HdPrimTypeTokens->rectLight || diff --git a/pxr/imaging/plugin/hdEmbree/renderer.cpp b/pxr/imaging/plugin/hdEmbree/renderer.cpp index 356ff2450b..226549c41c 100644 --- a/pxr/imaging/plugin/hdEmbree/renderer.cpp +++ b/pxr/imaging/plugin/hdEmbree/renderer.cpp @@ -9,6 +9,7 @@ #include "pxr/imaging/plugin/hdEmbree/config.h" #include "pxr/imaging/plugin/hdEmbree/light.h" #include "pxr/imaging/plugin/hdEmbree/mesh.h" +#include "pxr/imaging/plugin/hdEmbree/pxrPbrt/pbrtUtils.h" #include "pxr/imaging/plugin/hdEmbree/renderBuffer.h" #include "pxr/imaging/hd/perfLog.h" @@ -449,6 +450,51 @@ _EvalLightBasic(HdEmbree_LightData const& light) return Le; } +_LightSample +_EvalDistantLight(HdEmbree_LightData const& light, GfVec3f const& position, + float u1, float u2) +{ + auto const& distant = std::get(light.lightVariant); + + GfVec3f Le = _EvalLightBasic(light); + + if (distant.halfAngleRadians > 0.0f) + { + if (light.normalize) + { + float sinTheta = sinf(distant.halfAngleRadians); + Le /= _Sqr(sinTheta) * _pi; + } + + // There's an implicit double-negation of the wI direction here + GfVec3f localDir = pxr_pbrt::SampleUniformCone(GfVec2f(u1, u2), + distant.halfAngleRadians); + GfVec3f wI = light.xformLightToWorld.TransformDir(localDir); + wI.Normalize(); + + return _LightSample { + Le, + wI, + std::numeric_limits::max(), + pxr_pbrt::InvUniformConePDF(distant.halfAngleRadians) + }; + } + else + { + // delta case, infinite pdf + GfVec3f wI = light.xformLightToWorld.TransformDir( + GfVec3f(0.0f, 0.0f, 1.0f)); + wI.Normalize(); + + return _LightSample { + Le, + wI, + std::numeric_limits::max(), + 1.0f, + }; + } +} + _LightSample _EvalAreaLight(HdEmbree_LightData const& light, _ShapeSample const& ss, GfVec3f const& position) @@ -615,6 +661,10 @@ class _LightSampler { return _EvalDomeLight(_lightData, _normal, _u1, _u2); } + _LightSample operator()(HdEmbree_Distant const& distant) { + return _EvalDistantLight(_lightData, _hitPosition, _u1, _u2); + } + private: _LightSampler(HdEmbree_LightData const& lightData, GfVec3f const& hitPosition,