-
Notifications
You must be signed in to change notification settings - Fork 264
Description
Ray intersection is sometimes behind surface with inaccuracy larger than shadow epsilon. This may result in wrong occlusion.
System configuration
Platform: macOS 10.15.4
Compiler: Apple clang version 11.0.0 (clang-1100.0.33.17)
Python version: Python 3.7.6 :: Anaconda, Inc.
Mitsuba 2 version: leroyvn/mitsuba2@ed00d49 [branched off abf6938]
Compiled variants:
scalar_monoscalar_mono_double
Problem
I sometimes get intersections located at the wrong side of the associated surface. While it's usually not an issue, the error in positioning can become larger that ShadowEpsilon if scene dimensions become too large. At this point, this become problematic, as the surface will occlude while is actually should not. I tried with the rectangle and sphere shape plugins.
Note that I encountered this issue only with the distant sensor plugin (see #143). I suspect that this is due to the fact that the ray origin moves further away from the scene as its size increases, which increases the tolerance on positioning.
Any idea about what can be done to ensure that the intersection point will end up at the correct side of the surface? (Or at least closer than ShadowEpsilon?)
Steps to reproduce
- Compile Mitsuba with the aforementioned variants.
- Run the following script (problematic configurations will be reported with a '
⚠️ '):
from itertools import product
import numpy as np
import mitsuba
def scene_dict(scene_size=1., shape="rectangle"):
from mitsuba.core import ScalarTransform4f, ScalarVector3f
if shape == "rectangle":
to_world = ScalarTransform4f.scale(
ScalarVector3f(scene_size, scene_size, 1.)
)
elif shape == "sphere":
to_world = ScalarTransform4f(
[[scene_size, 0, 0, 0],
[0, scene_size, 0, 0],
[0, 0, scene_size, -scene_size],
[0, 0, 0, 1]]
)
else:
raise ValueError(f"unsupported shape {shape}")
return {
"type": "scene",
"surface": {
"type": shape,
"to_world": to_world,
"bsdf": {
"type": "diffuse",
"reflectance": {"type": "uniform", "value": 0.5}
}
},
"illumination": {
"type": "directional",
"direction": [0, 0, -1],
"irradiance": {"type": "uniform", "value": 1.0}
},
"integrator": {"type": "volpath"},
"measure": {
"type": "distant",
"direction": [-1, 0, -1],
"target": [0, 0, 0],
"sampler": {"type": "independent", "sample_count": 1},
"film": {
"type": "hdrfilm",
"width": 1,
"height": 1,
"pixel_format": "luminance",
"component_format": "float32",
"rfilter": {"type": "box"}
}
}
}
for shape, variant in product(["rectangle", "sphere"],
["scalar_mono", "scalar_mono_double"]):
mitsuba.set_variant(variant)
from mitsuba.core.xml import load_dict
from mitsuba.core.math import ShadowEpsilon
from mitsuba.core import Thread
Thread.thread().logger().clear_appenders()
print(f"{shape}, {variant} (ShadowEpsilon = {ShadowEpsilon:.4g})")
for scene_size in [10**i for i in range(8)]:
print(f" scene_size = {scene_size:.4g}")
scene = load_dict(scene_dict(scene_size))
sensor = scene.sensors()[0]
sampler = sensor.sampler()
# Cast a ray from the sensor
ray, _ = sensor.sample_ray_differential(
sampler.next_1d(),
sampler.next_1d(),
sampler.next_2d(),
sampler.next_2d()
)
si = scene.ray_intersect(ray)
print(f" si.p.z = {si.p.z:.4g}")
print(f" relative = {si.p.z / ShadowEpsilon:.4g}")
# Sample illumination from surface interaction point
ds, emitter_val = scene.sample_emitter_direction(si, sampler.next_2d())
emitter_val = np.squeeze(emitter_val)
icon = "⚠️" if emitter_val == 0. else " "
print(f" {icon} emitter_val = {emitter_val}")
print()