Offline path tracer produces a darker image than expected I've been going though Peter Shirley's beginner raytracing books. Upon building the Cornell box and rendering an image, I get a much darker / dimmer image than expected.



The color values are normalized (in the range [0.0f, 1.0f]). The author of the books has stated that for a brighter result, I need to gamma correct the values (calculating the nth root of the color values)The  above image has a gamma correction of 2 (square root). This is the same value that the author uses, but his result is much brighter 



I tried making the gamma correction larger (increasing n) and after setting n=4 (each color gets set to the (1/4)th exponent), I get this image.



There are obvious artifacts, like a lack of highlights near the light, and the over-saturated small number of pixels where a wall is close to the sphere.

The way a pixel's color is calculated is like this:

for(int j = height - 1; j &gt;= 0; j--)
{
    for(int i = 0; i &lt; width; i++)
    {
        vec3 color(0.0f, 0.0f, 0.0f);
        for(int s = 0; s &lt; samplesPerPixel; s++)
        {
            float u = ((float)i + RandomNumber(0.0f, 1.0f)) / width;
            float v = ((float)j + RandomNumber(0.0f, 1.0f)) / height;

            ray r = cam.CastRay(u, v);
            color += Color(r, list, depth);
        }

        color /= (float)samplesPerPixel;
        color = vec3(pow(color.x, gammaCorrection), pow(color.y, gammaCorrection), pow(color.z, gammaCorrection));

        int ir = Map(0.0f, 1.0f, 0.0f, 255.0f, color.x);
        int ig = Map(0.0f, 1.0f, 0.0f, 255.0f, color.y);
        int ib = Map(0.0f, 1.0f, 0.0f, 255.0f, color.z);

        output &lt;&lt; ir &lt;&lt; " " &lt;&lt; ig &lt;&lt; " " &lt;&lt; ib &lt;&lt; "\n";
    }
}


And the resulting color values for each channel (red, green and blue) is in the range of [0, 255].

Is there a problem with how I calculate a pixel's color based on all samples? My color function is pretty much the same as it is in the book 

vec3 Color(const ray&amp; r, HitableList&amp; hitables, int depth)
{
    float tmin = 0.001f;
    float tmax = 10000.0f; 

    HitData data;

    // If the ray hit something
    if(hitables.Hit(r, tmin, tmax, data))
    {
        ray scattered;
        vec3 attenuation;

        // If the material is a light, store its emitted color
        vec3 emitted = data.mat-&gt;Emitted(data.u, data.v, data.point);

        // If the number of bounces is below 50 and the ray gets scattered into a random direction
        if(depth &lt; 50 &amp;&amp; data.mat-&gt;Scatter(r, data, attenuation, scattered))
            return emitted + attenuation * Color(scattered, hitables, depth + 1);
        else
            return emitted;
    } else
        return vec3(0.0, 0.0f, 0.0f);
} 


Has anyone come across a similar issue before?
I have found the issue. The gamma correction was the correct value, the same as in the book (1/2), but the light source had the brightness of 1.0f. The book had set the light's brightness to 18.0f for all color channels. 

This would introduce color overflow if left at that, and the very light areas (above 1.0f, and subsequently when converted, outside the range [0, 255]) would have wrong colors. 

To fix this clamp the the pixel's color values.


Go through all samples and calculate pixel color.
Divide the color by number of samples
Apply gamma correction
Clamp colors in range [0, 1]
Finally, convert values to range [0, 255]




(I will accept this answer as a solution in 2 days because StackExchange doesn't let me to do it now.)