Modified Files:
include/nori/medium.h
src/homogeneous.cpp
src/path_mis_vol.cpp
src/path_mis_all.cpp
Small Changes: include/object.h, include/common.h, include/shape.h
Implementation
The implementation follows the lecture and also references the Meida of PBRT.
A Medium
class which is a subclass of NoriObject
, a Homogeneous
class which is a subclass of Medium
and a PhaseFunction
class
are created for the purpose. The homogeneous is implemented with the path tracing integrator.
Medium Object
In my implementation, the medium is bounded to a Shape which is its boundary. In the case of making the scene full of a medium, a large cube can be used.
And I also make an assumption here that no two mediums will intersect each other, as the intersection can be realized by introducing another medium bounded by the shape of the intersection.
The Medium
class has a Tr
method to compute the transmittance of given path length,
, a sample_free_path
method to sample a free path length with importance sampling of the transmittance,
and a get_phase
method to get the PhaseFunction
object.
The PhaseFunction
has a pdf
method to compute the value or the pdf of sampling some given angle theta,
and a sample
method to sample a wi direction given a wo direction, from the distribution of Henyey–Greenstein phase function.
All the evaluations and sampling have been introduced in detail in the lecture. And there is one thing worth noticing: When doing the free path sampling,
sigma_t
has three channels but only one float value should be used to sample the path length, here I choose to randomly sample one channel and sample the path length
and compute the pdf with the value of sigma_t
and transmittance of this channel. And in this case, the transmittance cannot be canceled anymore.
Integrator Behvior
Adding support of Medium in Integrator is the really hard part.
The main path-tracing logic remains the same. Three part needs to change:
(1) Medium Detect. The integrator needs to know when the ray is in the medium and when is not. In the beginning, I achieve this by maintaining a pointer
to Medium
, set it to the medium when the ray is entering the medium, and set it to nullptr when the ray is leaving the medium. But this approach often
results in issues due to numerical problems. Now, I use another approach to detect whether the ray is or not in a medium by intersecting the ray with the scene, if the ray intersects with
a normal Shape, then make the ray keeps going until there is no intersection ,or it intersects a Shape with Medium. The ray is inside the Medium, if and only if the ray intersects
with the Shape and the angle between the direction of the ray and the normal of the intersection is smaller than 90 degrees.
(2) Medium interaction. If the ray is in the medium, a maximum free path can be got by intersecting the scene, and a free path needs to be sampled. Three are three cases:
(a) if the sampled free path is smaller than the maximum free path, then it's a valid medium interaction. The throughput needs to be multiple with the transmittance and the scattering factor.
And an emitter sampling needs to be conducted as usual. But the visibility check will be different and will be introduced in (3). And the bsdf is replaced by the phase function, when an MIS emitter sampling
can be conducted and the contribution of the sampling can be added to the final result.
(b) if the sampled free path is smaller than the maximum free path, and the ray is intersecting the boundary of the medium, then set the mint
of the ray to overlook this intersection and directly continue to the next iteration.
(c) if the sampled free path is smaller than the maximum free path, and the intersection point is not on the boundary, it means the ray is intersecting a shape in the medium. In this case, it's not a valid medium interaction and it will be handled by the normal ray tracing part.
And it is worth noticing that, it's no need to multiply the transmittance in this case, as it will be canceled out by the probability of sampling.
(3) Emitter visibility. The check the visibility of the sampled emitter in emitter sampling, one needs to rule out the intersection with the medium boundary and compute the transmittance of the ray going through the medium.
And it also needs to take into consideration that, the ref point and the sampled point on the emitter might both be in, both not in, or only one in the medium. And between the two points, there could be other mediums too.
(4) MIS. The MIS weights of emitter sampling of normal surface interaction remain the same. And in the case of medium interaction, the bsdf pdf is replaced with the phase function value.
And for the MIS weights of "mats" part, the original "bsdf_pdf" value is the original BSDF pdf if the current ray is sampled by a BSDF, and is the phase function value if the current ray is sampled in a valid medium interaction.
Validation
The validation is done in a modified cbox scene, and all the result is compared with Mitsuba except one due to a bug in Mitsuba. All the result is rendered with 256spp.
(1) There are three balls in the cbox, and they have different kinds of medium. In this scene, we can see the medium is well interacting with the surfaces, the emitter, and each other. The result is compared against Mitsuba.
The scene file is scenes/medium/cbox/cbox_ball.xml
.
Three medium ball in cbox.
(2) This scene is fully in the medium, and there are both dielectric and diffused surfaces interacting with the medium. The result is compared against Mitsuba.
The scene file is scenes/medium/cbox/cbox_full.xml
.
Cbox full of medium with both dielectric and diffused balls.(g=0)
(3) This scene is same as (2) except for different g
for the HG phase function.
Cbox with g=0.8
(4) The last comparison is among my results with different g from -0.8 to 0 to 0.8. Here I cannot show a comparison with Mitsuba with g=-0.8, because I found that Mitsuba has a bug in the HG PhaseFunction sampling with a negative g value. I have sent an Issue to the Mitsuba GitHub repo.
Cbox with g=-0.8, g=0 and g=-0.8