<p>For your first question, the basic process should be (simplified version):</p>
<pre class="lang-cpp prettyprint-override"><code>// Step1: Ray intersection: calculate the maximum extent for the ray before hitting the surface
bool hit = ray_intersection(scene, ray);
if (!hit) {
    // check if the world itself contains scatter medium, if not then we return
}
/** Step2: distance sampling (free-path sampling).
 * For homogeneous scattering medium, it's easy to do with transmittance sampling
 * We sample a distance traveled before an scattering event
 * and evaluate transmittance
*/
MediumInteraction mi;
Spectrum tr;
bool medium_event = ray.medium.distance_sample(scene, mi, tr);
if (medium_event) {
    // we are here, if the sampled distance is less than the distance to the closest surface
    // Step 3: phase function sampling to upate the ray direction,
    // since distance sampling already updates the origin of the ray
    ray = ray.medium.phase_sampling(mi);
    path_throughput *= tr;
} else {
    // Nothing to be said here, it's just basic surface rendering process
    // One thing to note is that, transmittance value should be evaluated
    // via ray marching (or some other algorithms)
}
// Okay, then we update our ray for the next intersection and scattering event. Loop continues.
</code></pre>
<p>There are some details hidden in this pseudo code:</p>
<ul>
<li>How do we sample the free path in step 2?
In <a href="https://cs.dartmouth.edu/wjarosz/publications/novak18monte-slides-3-distance-sampling.pdf" rel="nofollow noreferrer">Dartmouth distance-sampling, page 7</a>, the sampling process is well explained: first find the bin we are in (since we are using fixed steps, it lefts us several bins in the space), and find the exact position in that bin (so, from discrete bins to continuous distance).</li>
<li>How to evaluate the transmittance?
For homogeneous medium, it's simple and can be done analytically (if, the medium is exponential). For heterogeneous medium, when ray marching is used, we just subdivide the space and evaluate each part then multiply them together.</li>
<li>Absorption &amp; scattering coefficient
You will find them in most renders as <code>sigma_a</code> and <code>sigma_s</code>, they compose a extinction coefficient <code>sigma_t</code>. The transmittance of a certain distance is usually:
<span class="math-container">$$
\exp(-\sigma_t d), \text{ where } d \text{ is the distance} 
$$</span></li>
</ul>
<hr />
<p>For the second question, I believe it has been answered: we <strong>sample</strong> the distance sample (distance traveled before a scattering event) according to the aggregated local transmittance, and we should be able to <strong>evaluate</strong> the transmittance (approximately) for any given path. So for non-uniform transmittance we can use ray marching here.</p>
<hr />
<p>For the third question:
No. Actually, for heterogeneous medium (not yet for SSS), some better ways are developed already: delta-tracking (woodcock tracking), residual tracking, etc. They are <strong>unbiased</strong> and efficient in multiple ways.
For SSS, path tracing can have extremely poor converge in highly scattering medium (high <code>sigma_s</code>, low <code>sigma_a</code>) since the energy of the ray won't change much even we have hundreds of scattering events. This is decided by the sampling process, let's take a look at a homogeneous example:</p>
<p><span class="math-container">$$
\text{estimator} = \sigma_s\frac{f(x)}{p(x)} = \sigma_s\frac{\exp(-\sigma_t d)}{\sigma_t\exp(-\sigma_t d)} = \frac{\sigma_s}{\sigma_s + \sigma_a} \approx 1
$$</span></p>
<p>So, a huge amount of scattering events need to be sampled (hence great <code>max_depth</code>) and the variance is pretty high. There are some interesting works on accelerating Monte Carlo SSS rendering, if you are interested:</p>
<ul>
<li>Meng, Johannes, Johannes Hanika, and Carsten Dachsbacher. &quot;Improving the Dwivedi sampling scheme.&quot; Computer Graphics Forum. Vol. 35. No. 4. 2016.</li>
<li>Křivánek, Jaroslav, and Eugene d'Eon. &quot;A zero-variance-based sampling scheme for Monte Carlo subsurface scattering.&quot; ACM SIGGRAPH 2014 Talks. 2014. 1-1.</li>
</ul>
<p>The ideas behind these works are basically: the ray will get lost in the highly scattering medium, so we should guide the ray out or to the emitter as quickly as possible.</p>
<p>I think for SSS, BSSRDF can already be very efficient.</p>

CC BY-SA 4.0
2023-08-18T03:55:16.203Z
2023-08-18T06:24:08.447Z
2023-08-18T06:24:08.447Z
Enigmatisms
<p>If this is still of interest to some readers in the future), I would recommend that you look at the lesson on ray-marching / volume rendering for developers on scratchapixel.</p>
<p><a href="https://www.scratchapixel.com/lessons/advanced-rendering/volume-rendering-for-developers/intro-volume-rendering" rel="nofollow noreferrer">https://www.scratchapixel.com/lessons/advanced-rendering/volume-rendering-for-developers/intro-volume-rendering</a></p>
<p>It explains how ray-marching works and also gives info on how to render volumetric objects with varying volume density (including voxel grids). Hope it helps.</p>

CC BY-SA 4.0
2022-03-25T23:49:21.707Z
2022-03-25T23:49:21.707Z
user18490
<p>Can somebody explain how to implement volume rendering and scattering? I've been told that this is the easiest and most effective method to render things like smoke, milk and fog. </p>

<p>Scratchapixel has a great article about it <a href="https://www.scratchapixel.com/lessons/advanced-rendering/volume-rendering-for-artists" rel="nofollow noreferrer">here</a> but the lesson on implementation is unavailable. </p>

<p>I understand what Ray Marching is because of this <a href="https://computergraphics.stackexchange.com/questions/4412/volume-rendering-path-tracing-real-time">answer</a> from a while back but similiar to my previous problem I have no idea how to implement it. </p>

<p>To make it clear and narrow this question down so it is easier to answer here are my main problems:</p>

<ol>
<li>Can someone provide some pseudo code or code of a basic Volume
Rendering and Ray Marching loop with Absorption &amp; Scattering
coefficients, Phase Function and a Density function?</li>
<li>How is Ray Marching used alongside Path Tracing?</li>
<li>Is this the best way to render sub surface scattering?</li>
</ol>

CC BY-SA 3.0
2017-06-11T00:25:44.353Z
Subsurface scattering won't necessarily require ray marching if it is in a homogeneous medium. Are you specifically looking to model inhomogeneous media (fire and smoke) rather than homogeneous media (milk or glass)?
trichoplax is on Codidact now
CC BY-SA 3.0
2017-06-16T23:47:03.353Z
Are you trying to do real time or offline rendering? SSS is a surface based algorithm that uses what's called a BSSRDF. Usually the implementation only accepts the data of a few layers past the surface. Usually just a few extra texture maps. Volume rendering can do the job of SSS but it models the entire inside of a volume. Often it does this with a 3d texture (uniform grid). But sometimes it's done with other datasets like tetrahedral grids. TLDR: Volume rendering isn't used for SSS although the concepts of emission, absorption, in/out scattering are the same.
Andrew Wilson
<pathtracing><subsurface-scattering><raymarching><volumetric-scattering>
Volume Rendering: Implementation
Arjan Singh
# Volume Rendering: Implementation

(Asked by: username_0 on 2017-06-09)

Can somebody explain how to implement volume rendering and scattering? I've been told that this is the easiest and most effective method to render things like smoke, milk and fog.

Scratchapixel has a great article about it [here](https://www.scratchapixel.com/lessons/advanced-rendering/volume-rendering-for-artists) but the lesson on implementation is unavailable.

I understand what Ray Marching is because of this [answer](https://computergraphics.stackexchange.com/questions/4412/volume-rendering-path-tracing-real-time) from a while back but similiar to my previous problem I have no idea how to implement it.

To make it clear and narrow this question down so it is easier to answer here are my main problems:

1. Can someone provide some pseudo code or code of a basic Volume
   Rendering and Ray Marching loop with Absorption & Scattering
   coefficients, Phase Function and a Density function?
2. How is Ray Marching used alongside Path Tracing?
3. Is this the best way to render sub surface scattering?

**Tags:** pathtracing, subsurface-scattering, raymarching, volumetric-scattering

> **Comments:**
> **username_1**: Subsurface scattering won't necessarily require ray marching if it is in a homogeneous medium. Are you specifically looking to model inhomogeneous media (fire and smoke) rather than homogeneous media (milk or glass)?  
> **username_2**: Are you trying to do real time or offline rendering? SSS is a surface based algorithm that uses what's called a BSSRDF. Usually the implementation only accepts the data of a few layers past the surface. Usually just a few extra texture maps. Volume rendering can do the job of SSS but it models the entire inside of a volume. Often it does this with a 3d texture (uniform grid). But sometimes it's done with other datasets like tetrahedral grids. TLDR: Volume rendering isn't used for SSS although the concepts of emission, absorption, in/out scattering are the same.  

---

## 2 answers

### Answer by username_3 on 2023-08-18. Score: 1

For your first question, the basic process should be (simplified version):

```cpp
// Step1: Ray intersection: calculate the maximum extent for the ray before hitting the surface
bool hit = ray_intersection(scene, ray);
if (!hit) {
    // check if the world itself contains scatter medium, if not then we return
}
/** Step2: distance sampling (free-path sampling).
 * For homogeneous scattering medium, it's easy to do with transmittance sampling
 * We sample a distance traveled before an scattering event
 * and evaluate transmittance
*/
MediumInteraction mi;
Spectrum tr;
bool medium_event = ray.medium.distance_sample(scene, mi, tr);
if (medium_event) {
    // we are here, if the sampled distance is less than the distance to the closest surface
    // Step 3: phase function sampling to upate the ray direction,
    // since distance sampling already updates the origin of the ray
    ray = ray.medium.phase_sampling(mi);
    path_throughput *= tr;
} else {
    // Nothing to be said here, it's just basic surface rendering process
    // One thing to note is that, transmittance value should be evaluated
    // via ray marching (or some other algorithms)
}
// Okay, then we update our ray for the next intersection and scattering event. Loop continues.

```

There are some details hidden in this pseudo code:

* How do we sample the free path in step 2?
  In [Dartmouth distance-sampling, page 7](https://cs.dartmouth.edu/wjarosz/publications/novak18monte-slides-3-distance-sampling.pdf), the sampling process is well explained: first find the bin we are in (since we are using fixed steps, it lefts us several bins in the space), and find the exact position in that bin (so, from discrete bins to continuous distance).
* How to evaluate the transmittance?
  For homogeneous medium, it's simple and can be done analytically (if, the medium is exponential). For heterogeneous medium, when ray marching is used, we just subdivide the space and evaluate each part then multiply them together.
* Absorption & scattering coefficient
  You will find them in most renders as `sigma_a` and `sigma_s`, they compose a extinction coefficient `sigma_t`. The transmittance of a certain distance is usually:
  $$
  \exp(-\sigma\_t d), \text{ where } d \text{ is the distance}
  $$

---

For the second question, I believe it has been answered: we **sample** the distance sample (distance traveled before a scattering event) according to the aggregated local transmittance, and we should be able to **evaluate** the transmittance (approximately) for any given path. So for non-uniform transmittance we can use ray marching here.

---

For the third question:
No. Actually, for heterogeneous medium (not yet for SSS), some better ways are developed already: delta-tracking (woodcock tracking), residual tracking, etc. They are **unbiased** and efficient in multiple ways.
For SSS, path tracing can have extremely poor converge in highly scattering medium (high `sigma_s`, low `sigma_a`) since the energy of the ray won't change much even we have hundreds of scattering events. This is decided by the sampling process, let's take a look at a homogeneous example:

$$
\text{estimator} = \sigma\_s\frac{f(x)}{p(x)} = \sigma\_s\frac{\exp(-\sigma\_t d)}{\sigma\_t\exp(-\sigma\_t d)} = \frac{\sigma\_s}{\sigma\_s + \sigma\_a} \approx 1
$$

So, a huge amount of scattering events need to be sampled (hence great `max_depth`) and the variance is pretty high. There are some interesting works on accelerating Monte Carlo SSS rendering, if you are interested:

* Meng, Johannes, Johannes Hanika, and Carsten Dachsbacher. "Improving the Dwivedi sampling scheme." Computer Graphics Forum. Vol. 35. No. 4. 2016.
* Křivánek, Jaroslav, and Eugene d'Eon. "A zero-variance-based sampling scheme for Monte Carlo subsurface scattering." ACM SIGGRAPH 2014 Talks. 2014. 1-1.

The ideas behind these works are basically: the ray will get lost in the highly scattering medium, so we should guide the ray out or to the emitter as quickly as possible.

I think for SSS, BSSRDF can already be very efficient.


---

### Answer by username_4 on 2022-03-25. Score: 0

If this is still of interest to some readers in the future), I would recommend that you look at the lesson on ray-marching / volume rendering for developers on scratchapixel.

<https://www.scratchapixel.com/lessons/advanced-rendering/volume-rendering-for-developers/intro-volume-rendering>

It explains how ray-marching works and also gives info on how to render volumetric objects with varying volume density (including voxel grids). Hope it helps.


---

