<p>I think this question lacks some additional information. I used your code to implement a simple diffusive color visualizer, and found nothing strange:</p>
<div class="s-table-container">
<table class="s-table">
<thead>
<tr>
<th style="text-align: center;">'Guassian' surface</th>
<th style="text-align: center;">Lambertian surface</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center;"><a href="https://i.sstatic.net/lBKkH.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/lBKkH.png" alt="enter image description here" /></a></td>
<td style="text-align: center;"><a href="https://i.sstatic.net/820N7.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/820N7.png" alt="enter image description here" /></a></td>
</tr>
</tbody>
</table>
</div>
<p>(Note that, Guassian surface means that the outgoing ray samples is subject to a normal distribution around the normal vector, Lambertian surface just means the cosine-weighted sampling used by you).</p>
<p>These images are the surface reflected color (cosine-weighted) visualized as a 2D image (mapped to theta and phi). The code can be found here: <a href="https://gist.github.com/Enigmatisms/8aa4f626a128174f61852ef27bcb4fab" rel="nofollow noreferrer">Gist: env_map.py</a>, simply run this code with:</p>
<pre class="lang-shell prettyprint-override"><code>python3 ./env_map.py
</code></pre>
<p>and you can get these results. So I have no idea why these white spots are there, it seems to me that the code given works, even when I modify how the <code>theta</code> and <code>phi</code> are computed (in case there is something wrong with your coordinate frame).</p>
<p>My suggestion is: input other environment maps to see what will happen to the diffuse component. For example, use an environment map with only one white circle and the other parts are black. More inputs get you more information.</p>
<hr />
<p>Update: I implemented the Hammersley sequence based 'sampling' you mentioned in the comment in my code and the result is like the following. I'm not sure if I get this correctly, and the code is here: <a href="https://gist.github.com/Enigmatisms/6b361126b3c6a3cbe28220ca72fa0434" rel="nofollow noreferrer">hammersley.cc</a>, to use it, you can follow the comment in that gist. The original code is also updated.</p>
<p><a href="https://i.sstatic.net/chlYs.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/chlYs.png" alt="enter image description here" /></a></p>
<p>There are indeed some artifacts, but not the kind you are looking for (if I get it right).</p>

CC BY-SA 4.0
2023-08-19T12:16:18.350Z
Hi and thank you for your answer. I have looked at your code and could not find any specific element that was different from my code. I think the difference is that I am using a hdr env map while the one that I provided in the question is already clamped, which means the problem doesn't appear.
Ivan
CC BY-SA 4.0
2023-08-19T12:16:34.660Z
[Another thread](https://computergraphics.stackexchange.com/questions/10390/problem-sampling-uniformly-envmap-with-ggx) caught my attention: the spots come from the light sampling which is deterministic and yields identical sequences of rays for each fragment (locally speaking)... In turn, close-by-points that have a similar normal will return the same color since the light integral is very close. I have tried again with resampling per fragment, and this gives me [this](https://i.sstatic.net/CygcU.png).
Ivan
CC BY-SA 4.0
2023-08-19T12:19:45.973Z
Let me know if that makes sense. I have found in some references that they sample from a fixed Hammersley sequence instead of sampling with a probabilistic distribution, *eg.* [here](http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html#sec-SourceCode). Hence my confusion when I was setting the initial "random" sequence identical to all fragments. Do you know why that is, can this be actually considered valid MC sampling?
Ivan
CC BY-SA 4.0
2023-08-19T15:24:11.053Z
This would make a pretty good point so I tried this out. It seems that I can't put any image in a comment so I would open the answer (edit).
Enigmatisms
CC BY-SA 4.0
2023-08-19T21:17:30.077Z
It looks like you only changed the shader to gaussian in your gist, correct? I found from [here](https://developer.nvidia.com/gpugems/gpugems3/part-iii-rendering/chapter-20-gpu-based-importance-sampling) that "sampling" from Hammersley ensures a better distribution of sampling directions than when using a uniform generator. What I don't understand is that this sequence doesn't have a random seed so it remains identical accross fragments. For instance [here](http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html#sec-SourceCode)
Ivan
CC BY-SA 4.0
2023-08-20T01:27:02.130Z
Ehh, I am sorry I forgot to update the original code, now it is updated. Yes, the sequence is not random, and it will remains identical across fragments. Since it does not ensure the coverage (in a probabilistic way) of the full domain to be integrated, I can't say it is unbiased and as you know, the method using these deterministic sequences are called *quasi-*MC. However, for diffuse component, it still can be a very excellent approximation to the unbiased estimation. I think you can deterministically rotate the vector using an extra phi angle to better populate the domain.
Enigmatisms
CC BY-SA 4.0
2023-08-19T10:06:07.043Z
2023-08-19T15:31:16.117Z
2023-08-19T15:31:16.117Z
Enigmatisms
<p>I am trying to implement a simple shader. A round ball object is rendered with uniform albedo and I noticed some strange white spots on the outputs.
I perform importance sampling with 512 light directions on the cosine-weighted hemisphere to render the scene. For debugging purposes, I dropped the specular component from the visualization and only show the <code>albedo*light</code> component:</p>
<p><a href="https://i.sstatic.net/Lrzn5m.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/Lrzn5m.png" alt="enter image description here" /></a></p>
<p><a href="https://i.sstatic.net/Lrzn5.png" rel="nofollow noreferrer">[higher resolution]</a></p>
<p>The spots roughly align with the position of the sun in the env map. From what I have understood the issue is that some values in the hdr are very high (up to <code>~8384</code>, 12% of the environment map pixels have a value over <code>1</code>). So if one of the very high values is sampled, then the resulting average light intensity will be very high. However, I don't see why the resulting diffuse color is sparse like this.</p>
<p>From this render, I expect to see a uniform color with a bright side on the left of the sphere. Could this issue be fixed with a more advanced sampling method based on the env map
intensity, or am I missing something with the current approach?</p>
<hr />
<p>For additional reference, I use the following python code to query the env map:</p>
<pre class="lang-python prettyprint-override"><code>def get_light(self, incident_dir, envir_map):
    &quot;&quot;&quot;
        envir_map: shape (1, 3, H, W)
        incident_dir: (3, point_num*samples_num)
    &quot;&quot;&quot;
    
    # convert from cartesian to spherical
    x,y,z = incident_dir
    phi = torch.arccos(z).flatten() - 1e-6
    theta = torch.atan2(y, x).flatten()

    # normalize to [-1, 1]
    query_y = (phi / np.pi) * 2 - 1
    query_x = - theta / np.pi

    # sampling grid is shaped (1, 1, pn*sn, 2)
    grid = torch.stack((query_x, query_y)).permute(1, 0).unsqueeze(0).unsqueeze(0)
    
    # interpolate to query env map, 
    sampled = F.grid_sample(envir_map, grid, align_corners=True) # [1, 3, 1, pn*sn]
    light_rgbs = sampled.squeeze().permute(1, 0).reshape(pn, -1, 3) # [pn, sn, 3]
    return light_rgbs
</code></pre>
<p>The environment map looks like so:</p>
<p><a href="https://i.sstatic.net/iphaom.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/iphaom.png" alt="enter image description here" /></a></p>

<rendering><sampling><ibl>
White spots when rendering diffuse material with environment light
Ivan
# White spots when rendering diffuse material with environment light

(Asked by: username_0 on 2023-08-18)

I am trying to implement a simple shader. A round ball object is rendered with uniform albedo and I noticed some strange white spots on the outputs.
I perform importance sampling with 512 light directions on the cosine-weighted hemisphere to render the scene. For debugging purposes, I dropped the specular component from the visualization and only show the `albedo*light` component:

[![enter image description here](https://i.sstatic.net/Lrzn5m.png)](https://i.sstatic.net/Lrzn5m.png)

[[higher resolution]](https://i.sstatic.net/Lrzn5.png)

The spots roughly align with the position of the sun in the env map. From what I have understood the issue is that some values in the hdr are very high (up to `~8384`, 12% of the environment map pixels have a value over `1`). So if one of the very high values is sampled, then the resulting average light intensity will be very high. However, I don't see why the resulting diffuse color is sparse like this.

From this render, I expect to see a uniform color with a bright side on the left of the sphere. Could this issue be fixed with a more advanced sampling method based on the env map
intensity, or am I missing something with the current approach?

---

For additional reference, I use the following python code to query the env map:

```python
def get_light(self, incident_dir, envir_map):
    """
        envir_map: shape (1, 3, H, W)
        incident_dir: (3, point_num*samples_num)
    """
    
    # convert from cartesian to spherical
    x,y,z = incident_dir
    phi = torch.arccos(z).flatten() - 1e-6
    theta = torch.atan2(y, x).flatten()

    # normalize to [-1, 1]
    query_y = (phi / np.pi) * 2 - 1
    query_x = - theta / np.pi

    # sampling grid is shaped (1, 1, pn*sn, 2)
    grid = torch.stack((query_x, query_y)).permute(1, 0).unsqueeze(0).unsqueeze(0)
    
    # interpolate to query env map, 
    sampled = F.grid_sample(envir_map, grid, align_corners=True) # [1, 3, 1, pn*sn]
    light_rgbs = sampled.squeeze().permute(1, 0).reshape(pn, -1, 3) # [pn, sn, 3]
    return light_rgbs

```

The environment map looks like so:

[![enter image description here](https://i.sstatic.net/iphaom.png)](https://i.sstatic.net/iphaom.png)

**Tags:** rendering, sampling, ibl


---

## 1 answers

### Answer by username_1 on 2023-08-19. Score: 1

I think this question lacks some additional information. I used your code to implement a simple diffusive color visualizer, and found nothing strange:

| 'Guassian' surface | Lambertian surface |
| --- | --- |
| [enter image description here](https://i.sstatic.net/lBKkH.png) | [enter image description here](https://i.sstatic.net/820N7.png) |

(Note that, Guassian surface means that the outgoing ray samples is subject to a normal distribution around the normal vector, Lambertian surface just means the cosine-weighted sampling used by you).

These images are the surface reflected color (cosine-weighted) visualized as a 2D image (mapped to theta and phi). The code can be found here: [Gist: env\_map.py](https://gist.github.com/username_1/8aa4f626a128174f61852ef27bcb4fab), simply run this code with:

```shell
python3 ./env_map.py

```

and you can get these results. So I have no idea why these white spots are there, it seems to me that the code given works, even when I modify how the `theta` and `phi` are computed (in case there is something wrong with your coordinate frame).

My suggestion is: input other environment maps to see what will happen to the diffuse component. For example, use an environment map with only one white circle and the other parts are black. More inputs get you more information.

---

Update: I implemented the Hammersley sequence based 'sampling' you mentioned in the comment in my code and the result is like the following. I'm not sure if I get this correctly, and the code is here: [hammersley.cc](https://gist.github.com/username_1/6b361126b3c6a3cbe28220ca72fa0434), to use it, you can follow the comment in that gist. The original code is also updated.

[![enter image description here](https://i.sstatic.net/chlYs.png)](https://i.sstatic.net/chlYs.png)

There are indeed some artifacts, but not the kind you are looking for (if I get it right).

> **Comments:**
> **username_0**: Hi and thank you for your answer. I have looked at your code and could not find any specific element that was different from my code. I think the difference is that I am using a hdr env map while the one that I provided in the question is already clamped, which means the problem doesn't appear.  
> **username_0**: [Another thread](https://computergraphics.stackexchange.com/questions/10390/problem-sampling-uniformly-envmap-with-ggx) caught my attention: the spots come from the light sampling which is deterministic and yields identical sequences of rays for each fragment (locally speaking)... In turn, close-by-points that have a similar normal will return the same color since the light integral is very close. I have tried again with resampling per fragment, and this gives me [this](https://i.sstatic.net/CygcU.png).  
> **username_0**: Let me know if that makes sense. I have found in some references that they sample from a fixed Hammersley sequence instead of sampling with a probabilistic distribution, *eg.* [here](http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html#sec-SourceCode). Hence my confusion when I was setting the initial "random" sequence identical to all fragments. Do you know why that is, can this be actually considered valid MC sampling?  
> **username_1**: This would make a pretty good point so I tried this out. It seems that I can't put any image in a comment so I would open the answer (edit).  
> **username_0**: It looks like you only changed the shader to gaussian in your gist, correct? I found from [here](https://developer.nvidia.com/gpugems/gpugems3/part-iii-rendering/chapter-20-gpu-based-importance-sampling) that "sampling" from Hammersley ensures a better distribution of sampling directions than when using a uniform generator. What I don't understand is that this sequence doesn't have a random seed so it remains identical accross fragments. For instance [here](http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html#sec-SourceCode)  
> **username_1**: Ehh, I am sorry I forgot to update the original code, now it is updated. Yes, the sequence is not random, and it will remains identical across fragments. Since it does not ensure the coverage (in a probabilistic way) of the full domain to be integrated, I can't say it is unbiased and as you know, the method using these deterministic sequences are called *quasi-*MC. However, for diffuse component, it still can be a very excellent approximation to the unbiased estimation. I think you can deterministically rotate the vector using an extra phi angle to better populate the domain.  

---

