<p>The problem lies mainly in <code>CIE1931XYZ::tristimulusValues()</code> function, where you normalize the resulting color to the luminance of your illuminant which causes that directly observed light source has luminance 1, but everything else is much darker. That is a nice thing to do if you just want to visualize colours of various reflectance spectra under a given illumination, but is probably not the best thing to do in a global illumination renderer.</p>

<p>To be more specific, you cannot expect a reflectance profile to be rendered always completely white just because it reflects all incident energy (constant spectral reflectance equal to 1 everywhere). Neglecting the material directional properties (BSDF, etc.), the properties of the light reflected from a point depend both on reflectance spectral profile of the material, and on the spectral and angular properties of the incident light. The incident light therefore depends not only on the SPD of the illuminant used for your light source, but also on its size and distance from the shaded point. The points closer to the light source will be brighter, while distant points will be darker.</p>

<p>I would suggest removing the luminance normalization in your Spectrum-to-XYZ conversion completely and then adjusting the overall brightness of your scene by multiplying the normalized SPD of the used illuminant (D65 in your case) with some brightness parameter. Whether you multiply it before rendering, during rendering or during the XYZ conversion step is completely up to you. The choice shouldn't affect the result.</p>

CC BY-SA 3.0
2016-03-25T17:06:21.783Z
Did this solve the problem?
ivokabel
CC BY-SA 3.0
2016-04-26T11:49:18.877Z
Hi @ivokabel, sorry for the late reply. You advice was good, and point me in the right direction, but was not enough. Indeed adding a brightness parameter to the light to manage the spectrum of the light. But i also added another parameter to manage the total luminance of a pixel: the tristimulus value obtained from the path tracer is multiply with the total radiance of the pixel (sum of each SPD wavelenght of the pixel). In this way the image brightness is good.
Fabrizio Duroni
CC BY-SA 3.0
2016-04-26T11:49:24.143Z
This is an example: https://drive.google.com/open?id=0BxeVnHLvT8-7MFNuN1pDcG1DZjg. Anyway thank you again. I hope to find a completely physically based solution before the end of my thesis time.
Fabrizio Duroni
CC BY-SA 3.0
2016-05-23T20:04:32.153Z
@FabrizioDuroni, does it mean, that adjusting the power of your light source with the brightness parameter doesn't make the resulting picture bright enough? I think I am missing something and I'm afraid you are adding to much alchemy into it ;-) Anyway, I'm glad it helped at least partially.
ivokabel
CC BY-SA 3.0
2016-05-24T20:06:11.123Z
I was missing something too, and in fact i remove that strange "alchemy" that i though was the right thing to do (web is not always a good source :D) Just a brightness multipler is good. This parameter could be substituted with more physically correct values, like the light power (using a Rienmann sum to calculate the integrate the light SPD ) and its area. But for my thesis has been decided that the brightness parameter is enough.
Fabrizio Duroni
CC BY-SA 3.0
2016-05-24T20:06:16.093Z
This is an example of a final rendered image that will be included in the thesis https://drive.google.com/open?id=0BxeVnHLvT8-7TVBZZE44VTRuT1k Keep watching my github repo for the final result ;)
Fabrizio Duroni
CC BY-SA 3.0
2016-05-24T20:39:39.613Z
@fabrizio, but that is almost exactly what I suggested you to do. ;-) And yes, having a more physically meaningful parameter (e.g. power) in a physically-based renderer would be definitely a nicer thing than some unitless brightness parameter. Especially when you have a spectral renderer (it is not clear how to do it in a colour-space renderer). The image looks pretty good to me. Good luck with the thesis!
ivokabel
CC BY-SA 3.0
2016-03-21T14:18:13.233Z
2016-03-21T14:18:13.233Z
ivokabel
<p>I implemented a spectral path tracing using physically base BRDF models such as Oren-Nayar,Specular Reflection and Transmission, Lambertian. All calculation in the path tracer uses standard illuminant and macbeth color checker SPD, spectral power distribution. The result of the path tracer for each pixel is the SPD obtained as a sum of SPD obtained from each sample calculated by the pat tracer. This SPD is then converted to CIE XYZ color and to RGB. The result scene obtained is the following one (in this example taking 500 samples per pixel):</p>

<p><a href="https://i.sstatic.net/8CdNZ.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/8CdNZ.png" alt="enter image description here"></a></p>

<p>As you can see, everything seems fine, except for the brightness/luminance of the scene. Every object in the scene is darker than it have to be. The floor and the front wall of the cornell box in the scene must be white and neutral8 (from macbeth color checker), but they are dark gray.
The following method is the one that trace the samples for a pixel of the path tracer:</p>

<pre><code>Vector3D PathTracer::getPixelColor(const Ray&amp; ray, int bounce) {

    Spectrum&lt;constant::spectrumSamples&gt; L(0.0f);
    int numberOfSamples = 500;
    float sampleWeight = 1.0f/(float)numberOfSamples;

    for (int i = 0; i &lt; numberOfSamples; i++) {

        Spectrum&lt;constant::spectrumSamples&gt; spectrumSample = trace(ray, bounce);
        L = L + spectrumSample * sampleWeight;
    }

    Spectrum&lt;constant::spectrumSamples&gt; Li = scene-&gt;light-&gt;spectrum;

    ColorMatchingFunction* colorMatchingFunction = new Standard2ObserverColorMatchingFunction();

    //Get tristimulus values.
    Vector3D tristimulus = CIE1931XYZ::tristimulusValues(L, Li, colorMatchingFunction);

    //Convert tristimulus to sRGB.
    Vector3D color = CIE1931XYZ::tristimulusTosRGB(tristimulus);

    //Apply sRGB gamma correction.
    sRGB::sRGBGammaCorrection(color, GammaCompanding);

    //Convert to standard 0 - 255 RGB value.
    sRGB::sRGBStandardRange(color);

    delete colorMatchingFunction;

    return color;
}
</code></pre>

<p>As you can seen, I already apply a gamma correction to the color obtained. 
Do you have any idea why my image rendered is so dark? My concerns are in the part where I convert the SPD sum, obtained from the samples, into RGB color. Do you see any error? Am I missing something? Do I need other operation to execute a correct conversion from the SPD obtained from the sampling to an RGB color?</p>

<hr>

<p>To avoid to write a too long question, I will link the main classes used by the path tracer for the calculation:</p>

<ul>
<li>Lighting/shading class used to recursive calculate the rendering equation <a href="https://github.com/chicio/Spectrum-Clara-Lux-Tracer/blob/luminance/SCLT/Shading/PathBRDF.cpp" rel="nofollow noreferrer">https://github.com/chicio/Spectrum-Clara-Lux-Tracer/blob/luminance/SCLT/Shading/PathBRDF.cpp</a> </li>
<li>CIE XYZ conversion <a href="https://github.com/chicio/Spectrum-Clara-Lux-Tracer/blob/luminance/SCLT/Color/CIEColorSpaces/CIEXYZ.cpp" rel="nofollow noreferrer">https://github.com/chicio/Spectrum-Clara-Lux-Tracer/blob/luminance/SCLT/Color/CIEColorSpaces/CIEXYZ.cpp</a></li>
<li>sRGB utils <a href="https://github.com/chicio/Spectrum-Clara-Lux-Tracer/blob/luminance/SCLT/Color/sRGB.hpp" rel="nofollow noreferrer">https://github.com/chicio/Spectrum-Clara-Lux-Tracer/blob/luminance/SCLT/Color/sRGB.hpp</a></li>
</ul>

<p>The other files/classes used are all on this repository (branch luminance)</p>

<p><a href="https://github.com/chicio/Spectrum-Clara-Lux-Tracer/tree/luminance" rel="nofollow noreferrer">https://github.com/chicio/Spectrum-Clara-Lux-Tracer/tree/luminance</a></p>

<hr>

<p>Thanks you all guys, I hope someone could help me.</p>

CC BY-SA 3.0
2016-03-20T23:14:39.753Z
It is perfectly OK if your material looks dark gray if you illuminate it with weak light source. What is the brightness of the light source?
ivokabel
CC BY-SA 3.0
2016-03-20T23:17:02.907Z
@ivokabel but my materials should look white and light gray. The SPD of the illuminant used is the D65. Do i need to tweak the spd of the light in some way?
Fabrizio Duroni
CC BY-SA 3.0
2016-03-20T23:17:50.843Z
@ivokabel Do i need to define a brightness paramter and use it somewhere?
Fabrizio Duroni
CC BY-SA 3.0
2016-03-20T23:37:29.820Z
If I am not mistaken, D65 only defines the shape of the spectrum, not the intensity. Therefore, you will really have to add a parameter telling the amount of emitting radiance, or something similar. Related topic is the renderer exposure value, but I saw that you take 1 as the limit value, so you don't have to bother with this one.
ivokabel
CC BY-SA 3.0
2016-03-20T23:45:26.890Z
Thank you @ivokabel for the suggestion about the parameter radiance. Could it be just a constant that will be multiplied with the spd of the illuminant during the tracing of rays? Or do i need to multiply the spd of the illuminant during the conversion from spd to cie xyz? Also I don't understand what you mean with renderer exposure value. Where do I take 1 as its value?
Fabrizio Duroni
CC BY-SA 3.0
2016-03-20T23:55:55.353Z
Yes, multiplying the SPD of your illuminant with a value (whether constant or variable) during or before the ray tracing is the way to go.
ivokabel
CC BY-SA 3.0
2016-03-20T23:58:54.817Z
@ivokabel what about the render exposure value? Where do i take 1?
Fabrizio Duroni
CC BY-SA 3.0
2016-03-20T23:58:58.063Z
...and sorry for the confusion about exposure. What I meant is the image value which maps onto maximum value in the resulting picture, 255 in your case. Don't worry about that at this point.
ivokabel
CC BY-SA 3.0
2016-03-21T00:05:41.957Z
@ivokabel can you just write a response to my question? In this way your answer an the other (if someone else would response) will remain as reference, and the user will not have to search in the  :) thank you.
Fabrizio Duroni
CC BY-SA 3.0
2016-03-21T00:11:36.470Z
I might get to it tomorrow...
ivokabel
CC BY-SA 3.0
2016-03-21T10:01:09.643Z
After re-reading your code, it is unclear to me what is the relation between scene->light->spectrum and material->le in `PathBRDF::shade`. Is it the same value? If yes, do you allow just one light source in your scene? Moreover, why do you normalize your XYZ values with illuminant luminance in `CIE1931XYZ::tristimulusValues()`?
ivokabel
CC BY-SA 3.0
2016-03-21T10:09:52.457Z
@ivokabel scene->light->spectrum and material->le contain the same value, the D65 SPD. In the scene init I give to the material of light object the SPD of the scene light. My scenes supports only one light. The normalization in CIE1931XYZ::tristimulusValues() follows the standard conversion from spd to CIE XYZ that you can found here http://www.scratchapixel.com/old/lessons/3d-basic-lessons/lesson-5-colors-and-digital-images/color-spaces/ or on the wiki CIE XYZ page. Is this passage not correct? I don't think so because my engine supports also the whitted ray tracing model that seems to be ok.
Fabrizio Duroni
CC BY-SA 3.0
2016-03-21T10:10:25.363Z
This is an example scene generated with a different illuminant SPD and the Whitted model https://raw.githubusercontent.com/chicio/Spectrum-Clara-Lux-Tracer/master/Screenshots/03_scene4_whittedSpectrum_fl9.png
Fabrizio Duroni
CC BY-SA 3.0
2016-03-21T10:13:59.067Z
In fact if I multiply the material->le with a multiplier the scene become more bright. Here are some rendered images https://drive.google.com/drive/u/1/folders/0BxeVnHLvT8-7Ty1jTVM5U1JJdms. They are not totally correct (as I expect the floor to be white), but maybe i just need a higher multiplier. Do you see any error in code that could avoid this multiplier (some error in the pdf/BRDF calculation)? Thank you very much again @ivokabel.
Fabrizio Duroni
CC BY-SA 3.0
2016-03-21T12:29:26.397Z
Let us [continue this discussion in chat](http://chat.stackexchange.com/rooms/37281/discussion-between-ivokabel-and-fabrizio-duroni).
ivokabel
<color><color-science><brightness><pathtracing><global-illumination>
Spectral path tracing - image color/brightness incorrect
Fabrizio Duroni
# Spectral path tracing - image color/brightness incorrect

(Asked by: username_0 on 2016-03-20)

I implemented a spectral path tracing using physically base BRDF models such as Oren-Nayar,Specular Reflection and Transmission, Lambertian. All calculation in the path tracer uses standard illuminant and macbeth color checker SPD, spectral power distribution. The result of the path tracer for each pixel is the SPD obtained as a sum of SPD obtained from each sample calculated by the pat tracer. This SPD is then converted to CIE XYZ color and to RGB. The result scene obtained is the following one (in this example taking 500 samples per pixel):

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

As you can see, everything seems fine, except for the brightness/luminance of the scene. Every object in the scene is darker than it have to be. The floor and the front wall of the cornell box in the scene must be white and neutral8 (from macbeth color checker), but they are dark gray.
The following method is the one that trace the samples for a pixel of the path tracer:

```
Vector3D PathTracer::getPixelColor(const Ray& ray, int bounce) {

    Spectrum<constant::spectrumSamples> L(0.0f);
    int numberOfSamples = 500;
    float sampleWeight = 1.0f/(float)numberOfSamples;

    for (int i = 0; i < numberOfSamples; i++) {

        Spectrum<constant::spectrumSamples> spectrumSample = trace(ray, bounce);
        L = L + spectrumSample * sampleWeight;
    }

    Spectrum<constant::spectrumSamples> Li = scene->light->spectrum;

    ColorMatchingFunction* colorMatchingFunction = new Standard2ObserverColorMatchingFunction();

    //Get tristimulus values.
    Vector3D tristimulus = CIE1931XYZ::tristimulusValues(L, Li, colorMatchingFunction);

    //Convert tristimulus to sRGB.
    Vector3D color = CIE1931XYZ::tristimulusTosRGB(tristimulus);

    //Apply sRGB gamma correction.
    sRGB::sRGBGammaCorrection(color, GammaCompanding);

    //Convert to standard 0 - 255 RGB value.
    sRGB::sRGBStandardRange(color);

    delete colorMatchingFunction;

    return color;
}

```

As you can seen, I already apply a gamma correction to the color obtained.
Do you have any idea why my image rendered is so dark? My concerns are in the part where I convert the SPD sum, obtained from the samples, into RGB color. Do you see any error? Am I missing something? Do I need other operation to execute a correct conversion from the SPD obtained from the sampling to an RGB color?

---

To avoid to write a too long question, I will link the main classes used by the path tracer for the calculation:

* Lighting/shading class used to recursive calculate the rendering equation <https://github.com/chicio/Spectrum-Clara-Lux-Tracer/blob/luminance/SCLT/Shading/PathBRDF.cpp>
* CIE XYZ conversion <https://github.com/chicio/Spectrum-Clara-Lux-Tracer/blob/luminance/SCLT/Color/CIEColorSpaces/CIEXYZ.cpp>
* sRGB utils <https://github.com/chicio/Spectrum-Clara-Lux-Tracer/blob/luminance/SCLT/Color/sRGB.hpp>

The other files/classes used are all on this repository (branch luminance)

<https://github.com/chicio/Spectrum-Clara-Lux-Tracer/tree/luminance>

---

Thanks you all guys, I hope someone could help me.

**Tags:** color, color-science, brightness, pathtracing, global-illumination

> **Comments:**
> **username_1**: It is perfectly OK if your material looks dark gray if you illuminate it with weak light source. What is the brightness of the light source?  
> **username_0**: @username_1 but my materials should look white and light gray. The SPD of the illuminant used is the D65. Do i need to tweak the spd of the light in some way?  
> **username_0**: @username_1 Do i need to define a brightness paramter and use it somewhere?  
> **username_1**: If I am not mistaken, D65 only defines the shape of the spectrum, not the intensity. Therefore, you will really have to add a parameter telling the amount of emitting radiance, or something similar. Related topic is the renderer exposure value, but I saw that you take 1 as the limit value, so you don't have to bother with this one.  
> **username_0**: Thank you @username_1 for the suggestion about the parameter radiance. Could it be just a constant that will be multiplied with the spd of the illuminant during the tracing of rays? Or do i need to multiply the spd of the illuminant during the conversion from spd to cie xyz? Also I don't understand what you mean with renderer exposure value. Where do I take 1 as its value?  
> **username_1**: Yes, multiplying the SPD of your illuminant with a value (whether constant or variable) during or before the ray tracing is the way to go.  
> **username_0**: @username_1 what about the render exposure value? Where do i take 1?  
> **username_1**: ...and sorry for the confusion about exposure. What I meant is the image value which maps onto maximum value in the resulting picture, 255 in your case. Don't worry about that at this point.  
> **username_0**: @username_1 can you just write a response to my question? In this way your answer an the other (if someone else would response) will remain as reference, and the user will not have to search in the  :) thank you.  
> **username_1**: I might get to it tomorrow...  
> **username_1**: After re-reading your code, it is unclear to me what is the relation between scene->light->spectrum and material->le in `PathBRDF::shade`. Is it the same value? If yes, do you allow just one light source in your scene? Moreover, why do you normalize your XYZ values with illuminant luminance in `CIE1931XYZ::tristimulusValues()`?  
> **username_0**: @username_1 scene->light->spectrum and material->le contain the same value, the D65 SPD. In the scene init I give to the material of light object the SPD of the scene light. My scenes supports only one light. The normalization in CIE1931XYZ::tristimulusValues() follows the standard conversion from spd to CIE XYZ that you can found here http://www.scratchapixel.com/old/lessons/3d-basic-lessons/lesson-5-colors-and-digital-images/color-spaces/ or on the wiki CIE XYZ page. Is this passage not correct? I don't think so because my engine supports also the whitted ray tracing model that seems to be ok.  
> **username_0**: This is an example scene generated with a different illuminant SPD and the Whitted model https://raw.githubusercontent.com/chicio/Spectrum-Clara-Lux-Tracer/master/Screenshots/03_scene4_whittedSpectrum_fl9.png  
> **username_0**: In fact if I multiply the material->le with a multiplier the scene become more bright. Here are some rendered images https://drive.google.com/drive/u/1/folders/0BxeVnHLvT8-7Ty1jTVM5U1JJdms. They are not totally correct (as I expect the floor to be white), but maybe i just need a higher multiplier. Do you see any error in code that could avoid this multiplier (some error in the pdf/BRDF calculation)? Thank you very much again @username_1.  
> **username_1**: Let us [continue this discussion in chat](http://chat.stackexchange.com/rooms/37281/discussion-between-username_1-and-username_0-username_0).  

---

## 1 answers

### Answer by username_1 on 2016-03-21. Score: 7

The problem lies mainly in `CIE1931XYZ::tristimulusValues()` function, where you normalize the resulting color to the luminance of your illuminant which causes that directly observed light source has luminance 1, but everything else is much darker. That is a nice thing to do if you just want to visualize colours of various reflectance spectra under a given illumination, but is probably not the best thing to do in a global illumination renderer.

To be more specific, you cannot expect a reflectance profile to be rendered always completely white just because it reflects all incident energy (constant spectral reflectance equal to 1 everywhere). Neglecting the material directional properties (BSDF, etc.), the properties of the light reflected from a point depend both on reflectance spectral profile of the material, and on the spectral and angular properties of the incident light. The incident light therefore depends not only on the SPD of the illuminant used for your light source, but also on its size and distance from the shaded point. The points closer to the light source will be brighter, while distant points will be darker.

I would suggest removing the luminance normalization in your Spectrum-to-XYZ conversion completely and then adjusting the overall brightness of your scene by multiplying the normalized SPD of the used illuminant (D65 in your case) with some brightness parameter. Whether you multiply it before rendering, during rendering or during the XYZ conversion step is completely up to you. The choice shouldn't affect the result.

> **Comments:**
> **username_1**: Did this solve the problem?  
> **username_0**: Hi @username_1, sorry for the late reply. You advice was good, and point me in the right direction, but was not enough. Indeed adding a brightness parameter to the light to manage the spectrum of the light. But i also added another parameter to manage the total luminance of a pixel: the tristimulus value obtained from the path tracer is multiply with the total radiance of the pixel (sum of each SPD wavelenght of the pixel). In this way the image brightness is good.  
> **username_0**: This is an example: https://drive.google.com/open?id=0BxeVnHLvT8-7MFNuN1pDcG1DZjg. Anyway thank you again. I hope to find a completely physically based solution before the end of my thesis time.  
> **username_1**: @username_0, does it mean, that adjusting the power of your light source with the brightness parameter doesn't make the resulting picture bright enough? I think I am missing something and I'm afraid you are adding to much alchemy into it ;-) Anyway, I'm glad it helped at least partially.  
> **username_0**: I was missing something too, and in fact i remove that strange "alchemy" that i though was the right thing to do (web is not always a good source :D) Just a brightness multipler is good. This parameter could be substituted with more physically correct values, like the light power (using a Rienmann sum to calculate the integrate the light SPD ) and its area. But for my thesis has been decided that the brightness parameter is enough.  
> **username_0**: This is an example of a final rendered image that will be included in the thesis https://drive.google.com/open?id=0BxeVnHLvT8-7TVBZZE44VTRuT1k Keep watching my github repo for the final result ;)  
> **username_1**: @username_0, but that is almost exactly what I suggested you to do. ;-) And yes, having a more physically meaningful parameter (e.g. power) in a physically-based renderer would be definitely a nicer thing than some unitless brightness parameter. Especially when you have a spectral renderer (it is not clear how to do it in a colour-space renderer). The image looks pretty good to me. Good luck with the thesis!  

---

