@@ -422,6 +422,20 @@ _SampleCylinder(GfMatrix4f const& xf, GfMatrix3f const& normalXform,
422422 };
423423}
424424
425+ _ShapeSample
426+ _IntersectAreaLight (HdEmbree_LightData const & light, RTCRayHit const & rayHit)
427+ {
428+ // XXX: just rect lights at the moment, need to do the others
429+ auto const & rect = std::get<HdEmbree_Rect>(light.lightVariant );
430+
431+ return _ShapeSample {
432+ _CalculateHitPosition (rayHit),
433+ GfVec3f (rayHit.hit .Ng_x , rayHit.hit .Ng_y , rayHit.hit .Ng_z ),
434+ GfVec2f (1 .0f - rayHit.hit .u , rayHit.hit .v ),
435+ _AreaRect (light.xformLightToWorld , rect.width , rect.height )
436+ };
437+ }
438+
425439GfVec3f
426440_EvalLightBasic (HdEmbree_LightData const & light)
427441{
@@ -1275,6 +1289,43 @@ _CosineWeightedDirection(GfVec2f const& uniform_float)
12751289 return dir;
12761290}
12771291
1292+ bool
1293+ HdEmbreeRenderer::_RayShouldContinue (RTCRayHit const & rayHit) const {
1294+ if (rayHit.hit .geomID == RTC_INVALID_GEOMETRY_ID) {
1295+ // missed, don't continue
1296+ return false ;
1297+ }
1298+
1299+ if (rayHit.hit .instID [0 ] == RTC_INVALID_GEOMETRY_ID) {
1300+ // not hit an instance, but a "raw" geometry. This should be a light
1301+ const HdEmbreeInstanceContext *instanceContext =
1302+ static_cast <HdEmbreeInstanceContext*>(
1303+ rtcGetGeometryUserData (rtcGetGeometry (_scene,
1304+ rayHit.hit .geomID )));
1305+
1306+ if (instanceContext->light == nullptr ) {
1307+ // if this isn't a light, don't know what this is
1308+ return false ;
1309+ }
1310+
1311+ auto const & light = instanceContext->light ->LightData ();
1312+
1313+ if ((rayHit.ray .mask & HdEmbree_RayMask::Camera)
1314+ && !light.visible_camera ) {
1315+ return true ;
1316+ } else if ((rayHit.ray .mask & HdEmbree_RayMask::Shadow)
1317+ && !light.visible_shadow ) {
1318+ return true ;
1319+ } else {
1320+ return false ;
1321+ }
1322+ }
1323+
1324+ // XXX: otherwise this is a regular geo. we should handle visibility here
1325+ // too eventually
1326+ return false ;
1327+ }
1328+
12781329void
12791330HdEmbreeRenderer::_TraceRay (unsigned int x, unsigned int y,
12801331 GfVec3f const &origin, GfVec3f const &dir,
@@ -1306,6 +1357,13 @@ HdEmbreeRenderer::_TraceRay(unsigned int x, unsigned int y,
13061357 rayHit.hit .Ng_z = -rayHit.hit .Ng_z ;
13071358 }
13081359
1360+ if (_RayShouldContinue (rayHit)) {
1361+ GfVec3f hitPos = _CalculateHitPosition (rayHit);
1362+
1363+ _TraceRay (x, y, hitPos + dir * _rayHitContinueBias, dir, random);
1364+ return ;
1365+ }
1366+
13091367 // Write AOVs to attachments that aren't converged.
13101368 for (size_t i = 0 ; i < _aovBindings.size (); ++i) {
13111369 HdEmbreeRenderBuffer *renderBuffer =
@@ -1361,6 +1419,11 @@ HdEmbreeRenderer::_ComputeId(RTCRayHit const& rayHit, TfToken const& idType,
13611419 return false ;
13621420 }
13631421
1422+ if (rayHit.hit .instID [0 ] == RTC_INVALID_GEOMETRY_ID) {
1423+ // not hit an instance, but a "raw" geometry. This should be a light
1424+ return false ;
1425+ }
1426+
13641427 // Get the instance and prototype context structures for the hit prim.
13651428 // We don't use embree's multi-level instancing; we
13661429 // flatten everything in hydra. So instID[0] should always be correct.
@@ -1401,6 +1464,11 @@ HdEmbreeRenderer::_ComputeDepth(RTCRayHit const& rayHit,
14011464 return false ;
14021465 }
14031466
1467+ if (rayHit.hit .instID [0 ] == RTC_INVALID_GEOMETRY_ID) {
1468+ // not hit an instance, but a "raw" geometry. This should be a light
1469+ return false ;
1470+ }
1471+
14041472 if (clip) {
14051473 GfVec3f hitPos = _CalculateHitPosition (rayHit);
14061474
@@ -1424,6 +1492,11 @@ HdEmbreeRenderer::_ComputeNormal(RTCRayHit const& rayHit,
14241492 return false ;
14251493 }
14261494
1495+ if (rayHit.hit .instID [0 ] == RTC_INVALID_GEOMETRY_ID) {
1496+ // not hit an instance, but a "raw" geometry. This should be a light
1497+ return false ;
1498+ }
1499+
14271500 // We don't use embree's multi-level instancing; we
14281501 // flatten everything in hydra. So instID[0] should always be correct.
14291502 const HdEmbreeInstanceContext *instanceContext =
@@ -1462,6 +1535,11 @@ HdEmbreeRenderer::_ComputePrimvar(RTCRayHit const& rayHit,
14621535 return false ;
14631536 }
14641537
1538+ if (rayHit.hit .instID [0 ] == RTC_INVALID_GEOMETRY_ID) {
1539+ // not hit an instance, but a "raw" geometry. This should be a light
1540+ return false ;
1541+ }
1542+
14651543 // We don't use embree's multi-level instancing; we
14661544 // flatten everything in hydra. So instID[0] should always be correct.
14671545 const HdEmbreeInstanceContext *instanceContext =
@@ -1548,6 +1626,30 @@ HdEmbreeRenderer::_ComputeColor(RTCRayHit const& rayHit,
15481626 return domeColor;
15491627 }
15501628
1629+ if (rayHit.hit .instID [0 ] == RTC_INVALID_GEOMETRY_ID) {
1630+ // if it's not an instance then it's almost certainly a light
1631+ const HdEmbreeInstanceContext *instanceContext =
1632+ static_cast <HdEmbreeInstanceContext*>(
1633+ rtcGetGeometryUserData (rtcGetGeometry (_scene,
1634+ rayHit.hit .geomID )));
1635+
1636+ // if we hit a light, just evaluate the light directly
1637+ if (instanceContext->light != nullptr ) {
1638+ auto const & light = instanceContext->light ->LightData ();
1639+ _ShapeSample ss = _IntersectAreaLight (light, rayHit);
1640+ _LightSample ls = _EvalAreaLight (light, ss,
1641+ GfVec3f (rayHit.ray .org_x , rayHit.ray .org_y , rayHit.ray .org_z ));
1642+
1643+ return GfVec4f (ls.Li [0 ], ls.Li [1 ], ls.Li [2 ], 1 .0f );
1644+ } else {
1645+ // should never get here. magenta warning!
1646+ TF_WARN (" Unexpected runtime state - hit an an embree instance "
1647+ " that wasn't a geo or light" );
1648+ return GfVec4f (1 .0f , 0 .0f , 1 .0f , 1 .0f );
1649+ }
1650+
1651+ }
1652+
15511653 // Get the instance and prototype context structures for the hit prim.
15521654 // We don't use embree's multi-level instancing; we
15531655 // flatten everything in hydra. So instID[0] should always be correct.
0 commit comments