diff --git a/pxr/imaging/plugin/hdEmbree/light.cpp b/pxr/imaging/plugin/hdEmbree/light.cpp index 2388d346fe..6885d20965 100644 --- a/pxr/imaging/plugin/hdEmbree/light.cpp +++ b/pxr/imaging/plugin/hdEmbree/light.cpp @@ -233,6 +233,42 @@ HdEmbree_Light::Sync(HdSceneDelegate *sceneDelegate, _lightData.shaping.coneSoftness = value.UncheckedGet(); } + if (const auto value = sceneDelegate->GetLightParamValue( + id, HdLightTokens->shapingIesFile); + value.IsHolding()) { + SdfAssetPath iesAssetPath = value.UncheckedGet(); + std::string iesPath = iesAssetPath.GetResolvedPath(); + if (iesPath.empty()) { + iesPath = iesAssetPath.GetAssetPath(); + } + + if (!iesPath.empty()) { + std::ifstream in(iesPath); + if (!in.is_open()) { + TF_WARN("could not open ies file %s", iesPath.c_str()); + } else { + std::stringstream buffer; + buffer << in.rdbuf(); + + if (!_lightData.shaping.ies.iesFile.load(buffer.str())) { + TF_WARN("could not load ies file %s", iesPath.c_str()); + } + } + } + } + + if (const auto value = sceneDelegate->GetLightParamValue( + id, HdLightTokens->shapingIesNormalize); + value.IsHolding()) { + _lightData.shaping.ies.normalize = value.UncheckedGet(); + } + + if (const auto value = sceneDelegate->GetLightParamValue( + id, HdLightTokens->shapingIesAngleScale); + value.IsHolding()) { + _lightData.shaping.ies.angleScale = value.UncheckedGet(); + } + _PopulateRtcLight(device, scene); HdEmbreeRenderer *renderer = embreeRenderParam->GetRenderer(); diff --git a/pxr/imaging/plugin/hdEmbree/light.h b/pxr/imaging/plugin/hdEmbree/light.h index 3f756ebedf..1020de3cea 100644 --- a/pxr/imaging/plugin/hdEmbree/light.h +++ b/pxr/imaging/plugin/hdEmbree/light.h @@ -7,6 +7,8 @@ #ifndef PXR_IMAGING_PLUGIN_HD_EMBREE_LIGHT_H #define PXR_IMAGING_PLUGIN_HD_EMBREE_LIGHT_H +#include "pxr/imaging/plugin/hdEmbree/pxrIES/pxrIES.h" + #include "pxr/base/gf/vec3f.h" #include "pxr/base/gf/matrix3f.h" #include "pxr/base/gf/matrix4f.h" @@ -71,12 +73,20 @@ struct HdEmbree_LightTexture int height = 0; }; +struct HdEmbree_IES +{ + PxrIESFile iesFile; + bool normalize = false; + float angleScale = 0.0f; +}; + struct HdEmbree_Shaping { GfVec3f focusTint; float focus = 0.0f; float coneAngle = 180.0f; float coneSoftness = 0.0f; + HdEmbree_IES ies; }; struct HdEmbree_LightData diff --git a/pxr/imaging/plugin/hdEmbree/renderer.cpp b/pxr/imaging/plugin/hdEmbree/renderer.cpp index 28587f0d4c..72b29656d3 100644 --- a/pxr/imaging/plugin/hdEmbree/renderer.cpp +++ b/pxr/imaging/plugin/hdEmbree/renderer.cpp @@ -389,6 +389,27 @@ _IntersectAreaLight(HdEmbree_LightData const& light, RTCRayHit const& rayHit) }; } +float +_EvalIES(HdEmbree_LightData const& light, GfVec3f const& wI) +{ + HdEmbree_IES const& ies = light.shaping.ies; + + if (!ies.iesFile.valid()) { + // Either none specified or there was an error loading. In either case, + // just ignore + return 1.0f; + } + + // emission direction in light space + GfVec3f wE = light.xformWorldToLight.TransformDir(wI).GetNormalized(); + + float theta = _Theta(wE); + float phi = _Phi(wE); + float norm = ies.normalize ? ies.iesFile.power() : 1.0f; + + return ies.iesFile.eval(theta, phi, ies.angleScale) / norm; +} + GfVec3f _EvalLightBasic(HdEmbree_LightData const& light) { @@ -495,6 +516,9 @@ _EvalAreaLight(HdEmbree_LightData const& light, _ShapeSample const& ss, const float thetaOffZ = acosf(cosThetaOffZ); Le *= 1.0f - _Smoothstep(thetaOffZ, GfRange1f(thetaSoft, thetaCone)); + // Apply IES + Le *= _EvalIES(light, wI); + return _LightSample { Le, wI,