diff --git a/docs/src/plugin_reference.rst b/docs/src/plugin_reference.rst index f1be77e42..d0679cf35 100644 --- a/docs/src/plugin_reference.rst +++ b/docs/src/plugin_reference.rst @@ -106,4 +106,42 @@ Each parameter optionally has flags that are listed in the last column. These flags indicate whether the parameter is differentiable or not, or whether it introduces discontinuities and thus needs special treatment. -See :py:class:`mitsuba.ParamFlags` for their documentation. \ No newline at end of file +See :py:class:`mitsuba.ParamFlags` for their documentation. + + +Scene-wide attributes +--------------------- + +The Scene object exposes scene-wide attributes. Currently, this functionality is +only used to configure Embree's BVH. In the future, additional settings for the +BVH behavior might be exposed. + +**Embree BVH mode:** We expose a scene-level flag to enable Embree's "robust" +mode. Enabling this flag makes Embree use slightly slower but more robust ray +intersection computations. Embree's default "fast" mode can miss ray +intersections when a ray perfectly hits the edge between two adjacent triangles. +Enabling the robust intersection mode fixes that in most cases. Note that Embree +cannot guarantee that all intersections are reported for rays that exactly hit a +vertex, which is a known limitation. + +.. pluginparameters:: + + * - embree_use_robust_intersection + - :paramtype:`bool` + - Whether Embree uses the robust mode flag `RTC_SCENE_FLAG_ROBUST` (Default: |false|). + +When creating a scene, the scene-wide attributes can be specified as follows: + +.. tabs:: + .. code-tab:: xml + + + + + + .. code-tab:: python + + { + 'type': 'scene', + 'embree_use_robust_intersection': True, + } diff --git a/src/render/scene_embree.inl b/src/render/scene_embree.inl index 9f5fac5a4..fab523628 100644 --- a/src/render/scene_embree.inl +++ b/src/render/scene_embree.inl @@ -112,7 +112,8 @@ Scene::accel_init_cpu(const Properties &props) { s.accel = rtcNewScene(embree_device); rtcSetSceneBuildQuality(s.accel, RTC_BUILD_QUALITY_HIGH); - rtcSetSceneFlags(s.accel, RTC_SCENE_FLAG_NONE); + bool use_robust = props.get("embree_use_robust_intersections", false); + rtcSetSceneFlags(s.accel, use_robust ? RTC_SCENE_FLAG_ROBUST : RTC_SCENE_FLAG_NONE); ScopedPhase phase(ProfilerPhase::InitAccel); accel_parameters_changed_cpu(); diff --git a/src/render/tests/test_scene.py b/src/render/tests/test_scene.py index 64fc9cb79..1273dcc58 100644 --- a/src/render/tests/test_scene.py +++ b/src/render/tests/test_scene.py @@ -315,3 +315,30 @@ def test11_sample_silhouette_bijective(variants_vec_rgb): out = scene.invert_silhouette_sample(ss) assert dr.all(ss.discontinuity_type != mi.DiscontinuityFlags.Empty.value) assert dr.allclose(valid_samples, valid_out, atol=1e-6) + + +def test_enable_embree_robust_flag(variants_any_llvm): + + # We intersect a ray against two adjacent triangles. The ray hits exactly + # the edge between two triangles, which Embree will not count as an + # intersection if the "robust" flag is not set. + R = mi.Transform4f() \ + .rotate(dr.normalize(mi.Vector3f(1, 1, 1)), 10) \ + .rotate([0, 1, 0], 40) + vertices = mi.Vector3f( + [0.0, 1.0, 0.0, 1.0], [0.0, 0.0, 1.0, 1.0], [0.0, 0.0, 0.0, 0.0]) + vertices = R @ vertices + + mesh = mi.Mesh("MyMesh", 4, 2) + params = mi.traverse(mesh) + params['vertex_positions'] = dr.ravel(vertices) + params['faces'] = [0, 1, 2, 1, 3, 2] + params.update() + ray = R @ mi.Ray3f(mi.Point3f(0.5, 0.5, 1), mi.Vector3f(0, 0, -1)) + + scene = mi.load_dict({'type': 'scene', 'mesh': mesh}) + assert not scene.ray_intersect(ray).is_valid() + + scene = mi.load_dict({'type': 'scene', 'mesh': mesh, + 'embree_use_robust_intersections': True}) + assert scene.ray_intersect(ray).is_valid()