I'm writing my implementation of ray tracer and I've got result which you can see at this image.

img So you can see that some dark parts are overlapping. And I have them even in the part where it should be bright in my opinion. There are two lights one from above and the second one from right-bottom corner.

And I have two questions. Is it right? I really tried to google some references but failed. I'm not still sure that results in my imagination are correct ones.

And the second one where does it come from?

I use usual lambertian shading model and have something like this in my code:

pixel = (0, 0, 0)
normal = get normal of sphere in point of intersection;
normal = unit vector of normal;
for each light from light_set {
    light = unit vector of light;
    pixel = pixel + diffuseColor * max(0, scalar multiplication of light and normal);

I'm really struggling to find out the reason where this strange thing is coming from. But couldn't find it.

UPD0: added some of my real code. The part which is described here is next:

Material mat = surfaces[closestSurfase]->getMaterial();
Color pixel = Color(0, 0, 0);
Vector3f normal = surfaces[closestSurfase]->getNormal(point).getUnitVector();
Vector3f view = -ray.getDirection().getUnitVector();
for (size_t i = 0; i < lights.size(); ++i) {
    Vector3f normal_light = lights[i]->getDirection().getUnitVector();
    Vector3f specVect = (normal_light + view).getUnitVector();
    float intenst = lights[i]->getIntensity();
    pixel = pixel + mat.getDiffuse() * std::max(0.0f, normal_light.dotMultiply(normal)) * intenst;
result->setPixel(x, y, pixel);

Or you can find more here: https://github.com/minebv/ray_tracer/tree/lambertian_shading_fix/src

Described above is from Camera's method getRender.

UPD1: It looks like the problem in the mixing colors in gamma space instead linear one, as answered @PaulHK .

But I've still some kind of problem. Here you can see 2 renders. img1 At the left one I make all work after transformation all colors into linear space, I mean it's like this in my code:

pixel = pixel + mat.getDiffuse().toLinear() * std::max(0.0f, normal_light.dotMultiply(normal)) * intenst;

At the right one I make transformation after multiplying:

pixel = pixel + (mat.getDiffuse() * std::max(0.0f, normal_light.dotMultiply(normal)) * intenst).toLinear();

And I didn't forget to make pixel into gamma space again after all job.

As for me, the right one is more correct. But then there is a question: why should I make multiplication on angle into gamma space? Or is it my incorrect way to think about what is right?

UPD3:it looks like the whole thing really was about mixing colors in gamma space instead of linear one. Here is result with ambient light. img3

Also about overlapping lights, it was my incorrect way of thinking. I finally found reference material where they have the same thing. Found it at blender docs.

Thank everyone for answers.

  • $\begingroup$ It does look weird. Could you put some of your actual code for us to see? Pseudo code shows your intent, which looks decent, but the problem might be in some subtle issue of the math or a typo (: $\endgroup$
    – Alan Wolfe
    Aug 22, 2016 at 1:59
  • $\begingroup$ @AlanWolfe updated my question, added some real code. $\endgroup$ Aug 22, 2016 at 4:25

1 Answer 1


I think what you're describing is what happens when you mix colours in gamma space. You should be using linear colour space when mixing.

When reading colours of lights and materials, convert them from gamma->linear using the inverse gamma function.

colourLin = pow(colourLight, 2.2);
... do lambert calculation here and accumulate in 'colour' variable ..

// On output (linear->gamma conversion)
gl_FragColor = pow(colour, 1.0/2.2);

There is an in depth chapter in GPU Gems on this topic: The Importance of Being Linear.

  • $\begingroup$ Done it. It looks like the problem is really with hamma. But I still has a question. There are to results of my ray tracing. In the first one I $\endgroup$ Aug 22, 2016 at 4:27
  • $\begingroup$ Sorry for kind of spamming. Didn't use to sending commentary with Enter button. There is continuation. In the left one I make at first gamma to linear conversion and then multiplying it on the max(0, scalar multiplication of light and normal) and after that summing results in pixel. And convert results into gamma space again. At the right one I convert colour into linear space only after multiplying it on on the max(0, scalar multiplication of light and normal). I don't quite get the reason why should I multiply in the gamma space. !img $\endgroup$ Aug 22, 2016 at 4:40
  • $\begingroup$ The most important thing is the output is converted to gamma (meaning your light accumulation is linear). Because your inputs are constant colours it doesn't affect shading as much as the output conversion. $\endgroup$
    – PaulHK
    Aug 22, 2016 at 4:50
  • $\begingroup$ I'd be interested to see your new image output if you can post an update $\endgroup$
    – PaulHK
    Aug 22, 2016 at 4:51
  • $\begingroup$ Don't forget, you picked the orange/green colours by eye (presumably) using a gamma-space monitor, so likely these are the correct/intended colours. $\endgroup$
    – PaulHK
    Aug 22, 2016 at 4:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.