Open Mine-525 opened 4 years ago
Hi, I also noticed strange behavior of scene.ray_intersect
in Python with packet_rgb
. Generally speaking, I am getting nonsense intersection data, and they are not even deterministic even though the code I wrote was deterministic. I suspect there is uninitialized memory or overflows happening somewhere, which causes the intersections to give nonsense non-deterministic results.
This week, I will try to write the simplest possible Python script for reproducing what I saw, unless someone else is already working on fixing the issue.
Hi,
This week, I will try to write the simplest possible Python script for reproducing what I saw, unless someone else is already working on fixing the issue.
Please do, it would be really helpful to debug this issue!
Thanks!
I think I managed to find out what exactly causes the bug. :)
I am actually not sure if the bug I am seeing is the same that @Mine-525 reported, but looking at their code sample, I think it could be exactly the same issue.
Below I attached a simple Python script that I used in a Jupyter notebook. It is using a custom hard-coded integrator in Python, which does the following:
sensor.sample_ray_differential
) to the scene (which contains a cube).
scene.ray_intersect
.interaction.spawn_ray
.
scene.ray_intersect
.Now, ideally, because a cube is a closed mesh, all pixels should be either cyan (no cube) or red (hit cube twice):
However, if you run the script a couple of times, again and again, you notice that sometimes you get very weird results:
While debugging, I noticed that the first scene.ray_intersect
called with rays from sensor.sample_ray_differential
works fine. The cube is never cyan, and the sky is never red or yellow, which means the first intersections are detected fine.
So the bug only happens when scene.ray_intersect
is called with rays generated by interaction.spawn_ray
. So I started investigating the rays and noticed that the maxt
of these rays is just a 1-element array [inf]
, but everything else like o
, d
, mint
, and time
are arrays that has 300*300=90000
elements (number of pixels):
So I tried rewriting a part of the script:
# Advance the rays to the first surface interaction:
rays = interaction.spawn_ray(rays.d)
rays.maxt = ek.zero(Float, 300*300)
rays.maxt += float("inf")
so that maxt
is a proper Enoki array of the correct dimension:
and that solved the bug! So I believe that the scene intersection code was touching invalid memory, which resulted in the weird patterns. Similarly, in the script of @Mine-525, they generate their custom rays without any mint
or maxt
explicitly defined, which I believe could cause the crashes.
The code for Interaction::spawn_ray
in Mitsuba 2 looks like this:
/// Spawn a semi-infinite ray towards the given direction
Ray3f spawn_ray(const Vector3f &d) const {
return Ray3f(p, d, (1.f + hmax(abs(p))) * math::RayEpsilon<Float>,
math::Infinity<Float>, time, wavelengths);
}
I think the problem is the math::Infinity<Float>
not being a properly sized Enoki array.
Hi, @tomasiser. Thank you for your great additional investigation!
I can solve this problem by your detailed report, and I'm glad that the great report comes from my little one!
Great, glad it helped! :)
I also want to point out that similar problems can easily occur with other structs, e.g., Interaction
. For example, if you initialize a custom interaction like this:
i = mitsuba.render.Interaction3f()
i.t = some_distances
i.p = some_positions
this will give you invalid interactions, because of missing i.time
, which, again, needs to be a properly sized Enoki array. Same probably goes for i.wavelengths
, although that is not used for trivial scene intersections.
Small mistakes like these do not throw any exceptions and can often silently crash the Python kernel.
Anyway, I believe the Interaction::spawn_ray
implementation is bugged in Mitsuba 2 itself.
Hi @tomasiser,
Thanks a lot for this very detailed investigation!
I think the implematation of Interaction::spawn_ray
is fine as enoki
knows how to deal with operation involving dynamic arrays and a dynamic array of size one.
Although the problem arises when working with those arrays outside of the enoki context, for instance accessing data directly via the array data pointer. This happens in few places accross the codebase, and apparently we don't handle this case properly everywhere.
See for instance this where the ray struct is "resized" before we pass it's data pointer to Optix.
Are you using embree
here? Or the mitsuba kd-tree?
Are you using
embree
here? Or the mitsuba kd-tree?
I am not using embree
. I also tried ray_intersect_naive
with the same result.
If it works with OptiX, then perhaps the bug is in the kd-tree itself?
When using ray_intersect_naive()
, the kd-tree isn't even used. This sounds more like an enoki bug at this point.
The current refactoring involves a complete redesign of the packet_*
modes and this bug will most likely go away. If you are fine with the workaround you mentioned above, I would wait for the refactored code to be merged.
How does that sound to you?
How does that sound to you?
Sounds fine! :-) We should remember to check the bug again after the refactoring. Looking forward!
Hi, I tested custom integrator in python and encountered a strange behavior of
ray_intersect()
.System configuration
scalar_rgb
,packet_rbg
andgpu_rgb
problem description
I tested a function
ray_intersect()
in a simple scene including one box and floor. In a attached scripts, rays should intersect at top of the box. test_si.zipWith
scalar_rgb
, while the vertical ray intersects at top of the box properly, the slanted ray doesn't intersect with the box and does with floor.gpu_rgb
works well about both rays. Withpacket_rgb
, executingray_intersect()
causes python crashing in attached script even thoughdepth_integrator
from sample codes works well withpacket_rgb
.In the page "Custom plugins in Python" from the documentation of Mitsuba2, it is said that Only gpu_ variants will produce reasonable performance when using such Python implementations of core system component. Is this means that not only overriding plugins, but also existing Mitsuba's methods, e.g. rayintersect(), works well only with `gpu` variants in python?