For this feature, I created a new Header file at
medium.h.
homogeneous_medium.cpp implements these functions. I then created
a new Integrator volpath.cpp.
To controll the medium, the user can set two variables: A
Color3f sigmaA for the absorbtion and a Color3f sigmaS for the
scattering.
For the Path-Tracer, we make the assumption, that the camera is not within the medium and that
media don't intersect. Solid elements within the media are allowed. The implementation is based
on path_mis.cpp.
If we are within the medium, we sample the free flight time:
if (medium) {
float t = medium->sampleFreePath(sampler->next1D());
if (t < its.t) {
// ...
}
}
For bounces in the medium, we then sample the phase function and sample a random emitter.
Vector3f phase = medium->samplePhaseFunction(sampler->next2D());
const Emitter * e = scene->getRandomEmitter(sampler->next1D());
EmitterQueryRecord eqr = EmitterQueryRecord(_ray.o);
Color3f color_emitter = e->sample(eqr, sampler->next2D()) * float(scene->getLights().size());
We then also need to consider the transmittance for these illuminations.
Color3f t_shadow(1.f);
Intersection its_sh;
bool in_medium = true;
while (true) {
if (scene->rayIntersect(eqr.shadowRay, its_sh)) {
if (its_sh.mesh->isMedium()) {
if (in_medium) {
t_shadow * its_sh.mesh->getMedium()->getTransmittance(its_sh.t);
}
in_medium = !in_medium;
eqr.shadowRay.o = eqr.shadowRay.o + eqr.shadowRay.d*its_sh.t;
}
color_emitter = 0.0f;
break;
}
break;
}
Finally, we can create the next ray, set the throughput depending in the albedo of the medium and add everything to the complete illumination.
_ray = Ray3f(_ray.o + _ray.d*t, phase, 0, INFINITY);
throughput *= medium->getAlbedo();
sampledColor += throughput * 1/4.f*INV_PI* color_emitter * t_shadow;
To validate the implementation, I created equal scenes for Mitsuba and compared the results.