-
Hello everyone, I'm currently implementing an integrator on Mitsuba 3 (stable branch) where I need to store each of the individual bounces of each sampled path and then access that information afterwards. I'm having a bit of trouble understanding how to store this information and use it, specially in the context of recorded loops, and I've thought of some possible solutions but I thought I needed some external help as well. Basically, the integrator's
I implemented the following custom structure in C++ for storing each individual bounce, keeping in mind that the underlying data is vectorized, so not all of the components may be active, therefore I included a /**
* \brief Structure that stores one bounce of some path traversing the scene.
*
* A bounce data object contains all the necessary information to compute both forwards and backwards light transport.
*/
template <typename Float_, typename Spectrum_>
struct BounceData {
using Float = Float_;
using Spectrum = Spectrum_;
MI_IMPORT_TYPES()
MI_IMPORT_OBJECT_TYPES()
/// \brief The id of the vertex in the path (mainly for debug purposes)
UInt32 id;
/// \brief Information about the interaction at this vertex
SurfaceInteraction3f interaction;
//...
/// \brief Whether this vertex of the path belongs to an active path.
Mask active;
BounceData(
const UInt32 id_,
const SurfaceInteraction3f& it_, ... , const Mask& active_)
: id(id_), interaction(it_), ..., active(active_) {}
DRJIT_STRUCT(BounceData, id, interaction, ..., active);
}; I've also exposed the data structure to the Python API with Pybind11. The integrator's sampling function and the two phases can be summarized in the following schema: def plt_sample_phase(self, ...):
# define internal state
# Here's where the bounces are stored.
bounce_buffer = ?
...
# Note: I'm not sure if the bounce_buffer should be part of the loop state...
loop = mi.Loop("PLT Path tracer (sample phase)",
state = lambda : (...))
loop.set_max_iterations(self.max_depth)
while loop(active):
# Sampling logic is identical to the path tracer integrator, omitting NEE and MIS.
# It also updates the active mask as the path tracer does.
# ...
# store bounce data
bounce = mi.BounceData(id=i, interaction=si, active=active, ...)
# The buffer could have this signature for adding bounces
bounce_buffer.add_bounce(depth, bounce)
return bounce_buffer, ...
def plt_solve_phase(self, ..., bounce_buffer):
# Solve data
L = mi.Spectrum(0.0)
i = mi.UInt(0)
loop = mi.Loop(name="PLT Path tracer (solve phase)", state=lambda:(?))
loop.set_max_iterations(self.max_depth)
while loop(i < self.max_depth):
# read a bounce here
bounce = bounce_buffer.read_bounce(i)
# do something with the recovered bounce
# ...
# next bounce
i += 1
return (L, ...)
def sample(...):
bounce_buffer, ... = self.plt_sample_phase(...)
L = self.plt_solve_phase(..., bounce_buffer)
return (L, ...) I'm having trouble implementing a structure that stores these bounces. I've tried to use conventional Python lists, or DynamicArray in the C++ side, but I haven't found a solution that works. Sorry for the big snippets of code, if you have any ideas, let me know, i will highly appreciate it! |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 2 replies
-
Hi @ZenithGD , Usually for creating these types of buffers, you need to reserve an amount of memory beforehand. In your case, that could be the maximum number of bounces. After deciding, I would recommend you take a look into a new feature of Dr.JIT named "Local Memory" which allows to have a buffer of fixed size per thread. You can imagine that it is like local storage per thread (in the CPU context). |
Beta Was this translation helpful? Give feedback.
Hi @ZenithGD ,
Usually for creating these types of buffers, you need to reserve an amount of memory beforehand. In your case, that could be the maximum number of bounces.
After deciding, I would recommend you take a look into a new feature of Dr.JIT named "Local Memory" which allows to have a buffer of fixed size per thread. You can imagine that it is like local storage per thread (in the CPU context).
With that, you could use the
depth
of the integrator to index in that buffer to retrieve the information saved on it and it will be more performant than previous solutions that had to reserve memory for the entire wavefront.Just a final note: I am assuming that both the first and second ph…