<p>I finally figured out where everything came from. More details at my blog post --&gt; <a href="https://viclw17.github.io/2024/07/20/glsl-cornellbox-breakdown-p2#ray-generation-raygenfrag" rel="nofollow noreferrer">https://viclw17.github.io/2024/07/20/glsl-cornellbox-breakdown-p2#ray-generation-raygenfrag</a></p>
<p>So the generated camera ray has a pdf of <code>1/cosine_theta^3</code> that the computed radiance have to divide; then the same cosine term have to multiply the radiance to get the real unbiased result, which in total is equivalent to multiply <code>cosine_theta^4</code>.</p>

CC BY-SA 4.0
2024-08-19T21:18:30.187Z
2024-08-19T21:18:30.187Z
Victor Li
<p>A cosine between the cam-view-direction and the ray computes something like a specular area. A highlight. You can compare that with a kind of <a href="https://en.wikipedia.org/wiki/Phong_shading" rel="nofollow noreferrer">Phong shading</a>. The more the ray is pointing &quot;away&quot; from the camera center, the lower this cosine gets. In the context of path tracing this would more be like a reflection of the surrounding objects being stronger visible in that area.</p>
<p>(pdf = path distribution factor, if I am not mistaken)
In the second snippet as I understand it, might be a bug? Because you probably want to store the average radiance and not something scaled=multiplied by pdf. But the pdf was computed as 1/... in the first snippet, so the division would turn out to be a multiplication. Seems odd.</p>
<p>/* Second thought: Normally you would have a factor &quot;alpha&quot; with the cosine, which controls the size of that highlight area. With just the cosine, that factor would be always 1.... maybe the radiance (second snippet) is meant to be that factor, but it does not quite make sense, because radiance is a vector. */</p>

CC BY-SA 4.0
2024-08-19T21:14:48.657Z
Thank you for the answer but unfortunately I believe it is not relevant to my question. _pdf_ here stands for _probability distribution function_ which is used during evaluating rendering equation in path tracing with monte carlo. Please refer to my answer for more details. Thanks!
Victor Li
CC BY-SA 4.0
2024-08-14T03:03:30.017Z
2024-08-14T03:38:44.353Z
2024-08-14T03:38:44.353Z
Antares
<p>When I was studying <a href="https://github.com/yumcyaWiz/glsl330-cornellbox/blob/master/src/shaders/pt.frag" rel="nofollow noreferrer">a code base</a> of path tracing implementation (done in GLSL), I notice the author returned a pdf of generated camera ray:</p>
<pre><code>Ray rayGen(in vec2 uv, out float pdf) {
    // ...
    Ray ray;
    ray.origin = camPos;
    ray.direction = normalize(pinholePos - sensorPos);

    pdf = 1.0 / pow(dot(ray.direction, camForward), 3.0);

    return ray;
}
</code></pre>
<p>I understand the <code>1/cosine^3</code> of the pdf is from <strong>the conversion from differential area to differential solid angle</strong> by reading these parts of pbrt - <a href="https://pbr-book.org/4ed/Radiometry,_Spectra,_and_Color/Working_with_Radiometric_Integrals#IntegralsoverArea" rel="nofollow noreferrer">4.2.3 Integrals over Area</a> and <a href="https://pbr-book.org/3ed-2018/Light_Transport_III_Bidirectional_Methods/The_Path-Space_Measurement_Equation#SamplingCameras" rel="nofollow noreferrer">16.1.1 Sampling Cameras</a>.</p>
<p>But I am confused why the end computed radiance has to divide this pdf for this rather simple path tracing implementation (never seen this in many other implementations):</p>
<pre><code>void main() {
    // ...
    float pdf;
    Ray ray = rayGen(uv, pdf);
    float cos_term = dot(camForward, ray.direction);

    // accumulate sampled color on accumTexture
    vec3 radiance = computeRadiance(ray) / pdf;

    color = texture(accumTexture, texCoord).xyz + radiance * cos_term;
    
    // ...
}
</code></pre>
<p>*Lastly I also do not understand above why the radiance that keeps adding into the final color (for progressive rendering, and later will divide sample count) has to <strong>multiply a cosine term</strong>.</p>
<p>Any insights on these will be appreciated!</p>

<shader><glsl><pathtracing><sampling>
Confusion about camera ray pdf
Victor Li
# Confusion about camera ray pdf

(Asked by: username_0 on 2024-08-13)

When I was studying [a code base](https://github.com/yumcyaWiz/glsl330-cornellbox/blob/master/src/shaders/pt.frag) of path tracing implementation (done in GLSL), I notice the author returned a pdf of generated camera ray:

```
Ray rayGen(in vec2 uv, out float pdf) {
    // ...
    Ray ray;
    ray.origin = camPos;
    ray.direction = normalize(pinholePos - sensorPos);

    pdf = 1.0 / pow(dot(ray.direction, camForward), 3.0);

    return ray;
}

```

I understand the `1/cosine^3` of the pdf is from **the conversion from differential area to differential solid angle** by reading these parts of pbrt - [4.2.3 Integrals over Area](https://pbr-book.org/4ed/Radiometry,_Spectra,_and_Color/Working_with_Radiometric_Integrals#IntegralsoverArea) and [16.1.1 Sampling Cameras](https://pbr-book.org/3ed-2018/Light_Transport_III_Bidirectional_Methods/The_Path-Space_Measurement_Equation#SamplingCameras).

But I am confused why the end computed radiance has to divide this pdf for this rather simple path tracing implementation (never seen this in many other implementations):

```
void main() {
    // ...
    float pdf;
    Ray ray = rayGen(uv, pdf);
    float cos_term = dot(camForward, ray.direction);

    // accumulate sampled color on accumTexture
    vec3 radiance = computeRadiance(ray) / pdf;

    color = texture(accumTexture, texCoord).xyz + radiance * cos_term;
    
    // ...
}

```

\*Lastly I also do not understand above why the radiance that keeps adding into the final color (for progressive rendering, and later will divide sample count) has to **multiply a cosine term**.

Any insights on these will be appreciated!

**Tags:** shader, glsl, pathtracing, sampling


---

## 2 answers

### Answer by username_0 on 2024-08-19. Score: 1 | Accepted answer

I finally figured out where everything came from. More details at my blog post --> <https://viclw17.github.io/2024/07/20/glsl-cornellbox-breakdown-p2#ray-generation-raygenfrag>

So the generated camera ray has a pdf of `1/cosine_theta^3` that the computed radiance have to divide; then the same cosine term have to multiply the radiance to get the real unbiased result, which in total is equivalent to multiply `cosine_theta^4`.


---

### Answer by username_1 on 2024-08-14. Score: 0

A cosine between the cam-view-direction and the ray computes something like a specular area. A highlight. You can compare that with a kind of [Phong shading](https://en.wikipedia.org/wiki/Phong_shading). The more the ray is pointing "away" from the camera center, the lower this cosine gets. In the context of path tracing this would more be like a reflection of the surrounding objects being stronger visible in that area.

(pdf = path distribution factor, if I am not mistaken)
In the second snippet as I understand it, might be a bug? Because you probably want to store the average radiance and not something scaled=multiplied by pdf. But the pdf was computed as 1/... in the first snippet, so the division would turn out to be a multiplication. Seems odd.

/\* Second thought: Normally you would have a factor "alpha" with the cosine, which controls the size of that highlight area. With just the cosine, that factor would be always 1.... maybe the radiance (second snippet) is meant to be that factor, but it does not quite make sense, because radiance is a vector. \*/

> **Comments:**
> **username_0**: Thank you for the answer but unfortunately I believe it is not relevant to my question. _pdf_ here stands for _probability distribution function_ which is used during evaluating rendering equation in path tracing with monte carlo. Please refer to my answer for more details. Thanks!  

---

