@@ -443,6 +443,45 @@ _EvalAreaLight(HdEmbree_LightData const& light, _ShapeSample const& ss,
443
443
};
444
444
}
445
445
446
+ _LightSample
447
+ _SampleDomeLight (HdEmbree_LightData const & light, GfVec3f const & direction)
448
+ {
449
+ float t = acosf (direction[1 ]) / _pi<float >;
450
+ float s = atan2f (direction[0 ], direction[2 ]) / (2 .0f * _pi<float >);
451
+ s = 1 .0f - fmodf (s+0 .5f , 1 .0f );
452
+
453
+ GfVec3f Li = light.texture .pixels .empty () ?
454
+ GfVec3f (1 .0f )
455
+ : _SampleLightTexture (light.texture , s, t);
456
+
457
+ return _LightSample {
458
+ Li,
459
+ direction,
460
+ std::numeric_limits<float >::max (),
461
+ 4 .0f * _pi<float >
462
+ };
463
+ }
464
+
465
+ _LightSample
466
+ _EvalDomeLight (HdEmbree_LightData const & light, GfVec3f const & W,
467
+ float u1, float u2)
468
+ {
469
+ GfVec3f U, V;
470
+ GfBuildOrthonormalFrame (W, &U, &V);
471
+
472
+ float z = u1;
473
+ float r = sqrtf (std::max (0 .0f , 1 .0f - _Sqr (z)));
474
+ float phi = 2 .0f * _pi<float > * u2;
475
+
476
+ const GfVec3f wI =
477
+ (W * z + r * cosf (phi) * U + r * sinf (phi) * V).GetNormalized ();
478
+
479
+ _LightSample ls = _SampleDomeLight (light, wI);
480
+ ls.invPdfW = 2 .0f * _pi<float >; // We only picked from the hemisphere
481
+
482
+ return ls;
483
+ }
484
+
446
485
class _LightSampler {
447
486
public:
448
487
static _LightSample GetLightSample (HdEmbree_LightData const & lightData,
@@ -510,6 +549,10 @@ class _LightSampler {
510
549
return _EvalAreaLight (_lightData, shapeSample, _hitPosition);
511
550
}
512
551
552
+ _LightSample operator ()(HdEmbree_Dome const & dome) {
553
+ return _EvalDomeLight (_lightData, _normal, _u1, _u2);
554
+ }
555
+
513
556
private:
514
557
_LightSampler (HdEmbree_LightData const & lightData,
515
558
GfVec3f const & hitPosition,
@@ -629,13 +672,20 @@ HdEmbreeRenderer::AddLight(SdfPath const& lightPath,
629
672
{
630
673
ScopedLock lightsWriteLock (_lightsWriteMutex);
631
674
_lightMap[lightPath] = light;
675
+
676
+ if (light->IsDome ()) {
677
+ _domes.push_back (light);
678
+ }
632
679
}
633
680
634
681
void
635
682
HdEmbreeRenderer::RemoveLight (SdfPath const & lightPath, HdEmbree_Light* light)
636
683
{
637
684
ScopedLock lightsWriteLock (_lightsWriteMutex);
638
685
_lightMap.erase (lightPath);
686
+ _domes.erase (std::remove_if (_domes.begin (), _domes.end (),
687
+ [&light](auto & l){ return l == light; }),
688
+ _domes.end ());
639
689
}
640
690
641
691
bool
@@ -1425,6 +1475,29 @@ HdEmbreeRenderer::_ComputeColor(RTCRayHit const& rayHit,
1425
1475
std::default_random_engine &random,
1426
1476
GfVec4f const & clearColor)
1427
1477
{
1478
+ if (rayHit.hit .geomID == RTC_INVALID_GEOMETRY_ID) {
1479
+ if (_domes.empty ()) {
1480
+ return clearColor;
1481
+ }
1482
+
1483
+ // if we missed all geometry in the scene, evaluate the infinite lights
1484
+ // directly
1485
+ GfVec4f domeColor (0 .0f , 0 .0f , 0 .0f , 1 .0f );
1486
+
1487
+ for (auto * dome : _domes) {
1488
+ _LightSample ls = _SampleDomeLight (
1489
+ dome->LightData (),
1490
+ GfVec3f (rayHit.ray .dir_x ,
1491
+ rayHit.ray .dir_y ,
1492
+ rayHit.ray .dir_z )
1493
+ );
1494
+ domeColor[0 ] += ls.Li [0 ];
1495
+ domeColor[1 ] += ls.Li [1 ];
1496
+ domeColor[2 ] += ls.Li [2 ];
1497
+ }
1498
+ return domeColor;
1499
+ }
1500
+
1428
1501
// Get the instance and prototype context structures for the hit prim.
1429
1502
// We don't use embree's multi-level instancing; we
1430
1503
// flatten everything in hydra. So instID[0] should always be correct.
0 commit comments