## Spectral tracking question

Practical and theoretical implementation discussion.
b_old
Posts: 12
Joined: Fri Mar 16, 2018 10:30 am

### Spectral tracking question

I'm trying to implement spectral tracking as described in Spectral and Decomposition Tracking for Rendering Heterogeneous Volumes.

To make debugging easier for debugging I make the following restrictions at the moment:
• 1. The data is homogeneous, so null collisions don't play a role at the moment
2. The scattering coefficient is zero, so lighting should not factor into the result at the moment
3. Only single scattering is considered
My implementation and the results can be viewed in this gist.

Because my data is homogeneous I can compare against plain tracking, and find that the results match for cases where the absorption coefficient is not spectrally refined (apart from noise). In this case the spectral tracking weights simply are vec(1), so I guess it is the same algorithm as delta tracking.

As soon as I introduce a spectrally refined absorption coefficient, however, I no longer understand what is going on. With the data I'm using, I basically only have to care about absorption, but even for that case I cannot figure out how I have to apply the weight to the computed transmittance. For normal delta tracking the transmittance is always zero when a collision happens, but for spectral tracking a compensation is necessary. Assuming the compensation weights are calculated correctly, something is wrong with the way I apply them.

Any idea how I should apply the weights to the transmittance?

dawelter
Posts: 52
Joined: Sun Oct 29, 2017 3:15 pm
Location: Germany

### Re: Spectral tracking question

Hi,
1. The data is homogeneous, so null collisions don't play a role at the moment
I think this is incorrect w.r.t. spectral tracking. Because
mu^bar = max_lambda { mu_t(lambda) },
you get
mu_n = mu^bar - mu_t > 0 for some lambda if not all mu_t(lambda) are equal.

Moreover, the weights are multiplied "on top" of the previous weights. So there should be a variable w with
w = wa * w,
and
w = ws * w
somewhere around line 37 and 41, respectively.

I happen to have implemented exactly the scheme you are working on. Maybe this helps:
https://github.com/DaWelter/ToyTrace/bl ... racking.py
Or if you don't mind wading through my atmosphere code
https://github.com/DaWelter/ToyTrace/bl ... re.cxx#L72

b_old
Posts: 12
Joined: Fri Mar 16, 2018 10:30 am

### Re: Spectral tracking question

Hi!
I think this is incorrect w.r.t. spectral tracking. ...
I think this is a very valuable hint! I did not get this part at all.

I updated my code and it now looks very similar to your python implementation. (Apart from the scattering part.)
The gist also contains updated images.

Visual inspection seems to suggest that closed form tracking and delta tracking might converge to the same result now. But spectral tracking is incredibly noisy, at least for this absorption-only case. Do you think this looks reasonable?

I'm still unsure about the scattering part. I don't really understand what your python code does in this case, but simply multiplying the estimated in-scattered light by the accumulated weight, like I do in the gist, doesn't seem to do the trick.

dawelter
Posts: 52
Joined: Sun Oct 29, 2017 3:15 pm
Location: Germany

### Re: Spectral tracking question

Do you think this looks reasonable?
Not sure. The method is pretty noisy, indeed. I actually wonder how you get your reference image so clear with jut 16 spp.

Try the weighting scheme from "5.1.2 Incorporating Path History". It should reduce the noise somewhat.

I spot one error:
- t is updated before calling direct_light. But p still points to the previous interaction point.
And a potential error:
- You need to factor in the transmittance along the ray to the light source.

Apart from that your code looks fine to me. Very much like my "spectral_tracking" function.

b_old
Posts: 12
Joined: Fri Mar 16, 2018 10:30 am

### Re: Spectral tracking question

I actually wonder how you get your reference image so clear with jut 16 spp.
In this case I used closed-form tracking as described in the volume rendering course. (I think this is valid even for spectrally refined media, as long as there is no scattering. More on that below.)
Try the weighting scheme from "5.1.2 Incorporating Path History". It should reduce the noise somewhat.
Indeed. Massive difference!
"5.1.3 Reduced Termination Rates" also works well for me, but it is only suitable for non-emissive media.(This is not yet included in the images further down)
I spot one error:
- t is updated before calling direct_light. But p still points to the previous interaction point.
Excellent find! I introduced this error recently by shuffling around some things and did not even consider it anymore.

After fixing this problem the results actually already look very promising. Isn't the transmittance along the ray handled by probabilities already? The delta tracking as described in the volume rendering course also doesn't need this. There you multiply the incoming light by the scattering albedo. But this doesn't seem to be necessary in spectral tracking because of the weights?!

Anyway, here are some new images (16 samples per pixel across all schemes) and thoughts:

Spectrally refined absorption and scattering. The spectral tracking seems to converge to the same result as the ray marched reference. Closed-form tracking is slightly off.

Spectrally refined absorption with zero scattering. All three schemes seem to converge to the same result. Closed-form tracking converges much faster than spectral tracking. (Judging from my experiments, spectrally refined absorption with gray scattering will also be handled incorrectly by closed-form tracking)

Do you think it is possible to modify closed-form tracking in such a way that it handles spectrally refined absorption/scattering for homogeneous media correctly? Or would you end up at spectral scattering anyway, because of the null collision thing we talked about earlier?

dawelter
Posts: 52
Joined: Sun Oct 29, 2017 3:15 pm
Location: Germany

### Re: Spectral tracking question

Cool! And thanks for the link to the paper. Very interesting.
Do you think it is possible to modify closed-form tracking in such a way that it handles spectrally refined absorption/scattering for homogeneous media correctly?
For homogeneous media you have the analytic expression for the transmittance. So you have a lot of freedom with sampling strategies where you also have the pdf in closed form. I.e. you could make standard Monte-carlo estimators like transmission(x)*otherstuff(x)/pdf(x), x~pdf.

Using a "mixture" pdf would be a possibility perhaps: pdf(x) = pr_1*sigma_1*exp(-sigma_1*x) + pr_2*sigma_2*exp(-sigma_2*x) + ..., where pr_i are the probabilities to select the i-th wavelength for sampling. IIRC this is a special case of MIS weighting. Not quite the usual delta tracking. But still.
Isn't this implemented in PBRT? ... Yeah ... https://github.com/mmp/pbrt-v3/blob/mas ... eneous.cpp

Instead of this pdf you could probably mix the modified pdfs that "force" samples to lie within a given distance. Good for very thin media.

b_old
Posts: 12
Joined: Fri Mar 16, 2018 10:30 am

### Re: Spectral tracking question

Isn't this implemented in PBRT?
Hm, I quickly started implementing this for absorption only material and the results where even more noisy than spectral tracking (with history and no emission), which discourages me from going further in that direction.
Instead of this pdf you could probably mix the modified pdfs that "force" samples to lie within a given distance.
I think that is basically what closed-form tracking does.

Code: Select all

float3 closed_form_tracking(const Ray& ray, float3& transmittance) {
const float d = ray.max_t - ray.min_t;

const float3 sigma_a = material.absorption();
const float3 sigma_s = material.scattering();
const float3 sigma_t = sigma_a + sigma_s;

const float3 tr = math::exp(-d * sigma_t);

const float r = rng_.random_float();
const float scatter_distance = -std::log(1.f - r * (1.f - math::average(tr))) / math::average(sigma_t);
const float3 p = ray.point(ray.min_t + scatter_distance);
const float3 l = direct_light(ray, p);

const float3 scattering_albedo = sigma_s / sigma_t;

transmittance = tr;
return l * (1.f - tr) * scattering_albedo;
}

I guess it is possible to come up with a weight to fix the amount of inscattered light. But I suspect that the way in which scatter_distance is calculated has to be adjusted as well.