<p>Consider the following scheme that mimicks the generation of a sample for phong shading. where V is the viewer direction, N is the normal, R is the specular reflection direction and $S_i$ is some sample. This space (commonly called tangent space) uses the normal as one of its basis vectors. you can think of it as the 'Z axis'</p>

<p><a href="https://i.sstatic.net/xYz3F.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/xYz3F.png" alt="tangent space"></a></p>

<p>Now, when we generate samples for Phong shading wo do not generate them in this space.</p>

<p>Rather, we use a different reference system where the Specular reflection direction is the 'z axis', thus, our angle $\theta$ is the angle between the reflected direction and the sample direction, and the angle $\phi$ is the angle between some $S_{ix}$ that is the projection of our sample direction onto the plane perpendicular to $R$ and some arbitrary but constant vector perpendicular to our reflected direction</p>

<p><a href="https://i.sstatic.net/MxqAm.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/MxqAm.png" alt="ray space"></a></p>

<p>$\phi$ is a number that is sampled uniformly in the range $(0,2\pi)$ this means that rays will be generated around the reflected direction with no bias towards any particular direction.</p>

<p>Generated rays will, however, be biased to have a direction close to $R$ due to the way that $\theta$ is sampled.</p>

<p>When we generate rays in a backwards pathtracer we use the view direction to get the directions where the light is likely to come from, instead of throwing light around and seeing where it falls. The later technique is closer to photon mapping.</p>

CC BY-SA 3.0
2018-01-26T22:56:02.827Z
Can't thank you enough, as a side question: after computing a sample according to this model, the resulting radiance should be divided by the pdf specified in the first formula I've posted?
Row Rebel
CC BY-SA 3.0
2018-01-26T23:11:15.717Z
it should be multiplied by the brdf and divided by the pdf. those usually cancel each other out so it is often not necesary
Sebastián Mestre
CC BY-SA 3.0
2018-01-26T22:25:05.040Z
2018-01-26T22:25:05.040Z
Sebastián Mestre
<p>According to: <a href="https://www.cs.virginia.edu/~jdl/importance.doc" rel="nofollow noreferrer">https://www.cs.virginia.edu/~jdl/importance.doc</a></p>

<p>For a specular sample: (page 4 of the document) $$pdf(\theta_{i}) = \frac{n+1}{2\pi} \cos^n(a)$$  </p>

<p>And this is how you choose an incoming direction according to a specular sample of the BRDF (page 4 of the document):
$$ \vec{w_{i}} = (\alpha, \phi) = (\arccos(\varepsilon_{1}^{  \frac{1}{n+1}  }), \ \  2\pi\varepsilon_{2})$$</p>

<p>But according to the figure on page 4, a specular sample has a BRDF favoring a direction which is highly dependent on the incoming ray, but the $ \phi $ angle is decided by uniformly sampling a circle, disregarding completely the incoming direction, which to me makes no sense</p>

<p>Shouldn't the $ \phi $ angle favor the specular direction, which is dependent on the incoming ray? Why we're not using at all the incoming ray to calculate the sampled direction which is supposedly sampling the brdf?</p>

<p>No matter where I look for it, I haven't seen an implementation using a BRDF which takes into account the incoming direction, which makes me think I've misunderstood the theory behind it</p>

<p>Lastly, assuming a standard backward path tracer, is this pseudocode the right way of computing the results?</p>

<pre><code>color =  float3(1,1,1)
ray   =  getRayFromCamera()

for NUM_BOUNCES:
    primitive = world.intersect(ray)    

    // assuming primitive is non null, I'm omitting the code where we sample a background
    albedo           = primitive.albedo

    // computeOutGoingRay will return a Ray and a PDF
    outgoingRay, pdf = primitive.material.computeOutGoingRay(ray, normal, etc..)

    // of the incoming radiance, how much is scattered along the new direction?
    brdf             = primitive.brdf(outgoingRay, ray)

    color = (color * albedo * brdf) / pdf

    // assigning the new ray to keep our backward recursion
    ray   = outGoingRay
</code></pre>

CC BY-SA 3.0
2018-01-26T05:41:23.580Z
on a phong brdf, samples are generated in a space where the reflected direction is the z axis. thats where the dependence comes from
Sebastián Mestre
CC BY-SA 3.0
2018-01-26T11:41:14.783Z
Still, the phi angle is sampled over a circle uniformly instead of favoring the specular direction! This is the part I didn't get
Row Rebel
<pathtracing><brdf><physically-based><monte-carlo>
Phong Modified BRDF Implementation
Row Rebel
# Phong Modified BRDF Implementation

(Asked by: username_0 on 2018-01-25)

According to: <https://www.cs.virginia.edu/~jdl/importance.doc>

For a specular sample: (page 4 of the document) $$pdf(\theta\_{i}) = \frac{n+1}{2\pi} \cos^n(a)$$

And this is how you choose an incoming direction according to a specular sample of the BRDF (page 4 of the document):
$$ \vec{w\_{i}} = (\alpha, \phi) = (\arccos(\varepsilon\_{1}^{ \frac{1}{n+1} }), \ \ 2\pi\varepsilon\_{2})$$

But according to the figure on page 4, a specular sample has a BRDF favoring a direction which is highly dependent on the incoming ray, but the $ \phi $ angle is decided by uniformly sampling a circle, disregarding completely the incoming direction, which to me makes no sense

Shouldn't the $ \phi $ angle favor the specular direction, which is dependent on the incoming ray? Why we're not using at all the incoming ray to calculate the sampled direction which is supposedly sampling the brdf?

No matter where I look for it, I haven't seen an implementation using a BRDF which takes into account the incoming direction, which makes me think I've misunderstood the theory behind it

Lastly, assuming a standard backward path tracer, is this pseudocode the right way of computing the results?

```
color =  float3(1,1,1)
ray   =  getRayFromCamera()

for NUM_BOUNCES:
    primitive = world.intersect(ray)    

    // assuming primitive is non null, I'm omitting the code where we sample a background
    albedo           = primitive.albedo

    // computeOutGoingRay will return a Ray and a PDF
    outgoingRay, pdf = primitive.material.computeOutGoingRay(ray, normal, etc..)

    // of the incoming radiance, how much is scattered along the new direction?
    brdf             = primitive.brdf(outgoingRay, ray)

    color = (color * albedo * brdf) / pdf

    // assigning the new ray to keep our backward recursion
    ray   = outGoingRay

```

**Tags:** pathtracing, brdf, physically-based, monte-carlo

> **Comments:**
> **username_1**: on a phong brdf, samples are generated in a space where the reflected direction is the z axis. thats where the dependence comes from  
> **username_0**: Still, the phi angle is sampled over a circle uniformly instead of favoring the specular direction! This is the part I didn't get  

---

## 1 answers

### Answer by username_1 on 2018-01-26. Score: 1 | Accepted answer

Consider the following scheme that mimicks the generation of a sample for phong shading. where V is the viewer direction, N is the normal, R is the specular reflection direction and $S\_i$ is some sample. This space (commonly called tangent space) uses the normal as one of its basis vectors. you can think of it as the 'Z axis'

[![tangent space](https://i.sstatic.net/xYz3F.png)](https://i.sstatic.net/xYz3F.png)

Now, when we generate samples for Phong shading wo do not generate them in this space.

Rather, we use a different reference system where the Specular reflection direction is the 'z axis', thus, our angle $\theta$ is the angle between the reflected direction and the sample direction, and the angle $\phi$ is the angle between some $S\_{ix}$ that is the projection of our sample direction onto the plane perpendicular to $R$ and some arbitrary but constant vector perpendicular to our reflected direction

[![ray space](https://i.sstatic.net/MxqAm.png)](https://i.sstatic.net/MxqAm.png)

$\phi$ is a number that is sampled uniformly in the range $(0,2\pi)$ this means that rays will be generated around the reflected direction with no bias towards any particular direction.

Generated rays will, however, be biased to have a direction close to $R$ due to the way that $\theta$ is sampled.

When we generate rays in a backwards pathtracer we use the view direction to get the directions where the light is likely to come from, instead of throwing light around and seeing where it falls. The later technique is closer to photon mapping.

> **Comments:**
> **username_0**: Can't thank you enough, as a side question: after computing a sample according to this model, the resulting radiance should be divided by the pdf specified in the first formula I've posted?  
> **username_1**: it should be multiplied by the brdf and divided by the pdf. those usually cancel each other out so it is often not necesary  

---

