4
$\begingroup$

In my naïve raytracer experiment I work internally with RGB values, and after all the tracing has been done, I end up with raw RGB triplets that I need to write down to some image format with a limited gamut, typically sRGB.

Since bright spots in my image can have values far beyond (1,1,1), I need to clip them. Right now I just limit each channel individually, but that will obviously introduce a shift in hue when one channel clips before another. Here is a typical (enlarged) example from my code where the yellow-green object turns into yellow around the highlight:

Example of hue shift

I'm now looking for a way to solve this problem, but all the solutions I come up with seems to have the same drawback: eventually you have to discard information. For example, I've thought about working with another colorspace like Lab internally, but even then I would first have to transform it to sRGB for rendering the final image file.

Before I dig myself into this any further, I would like to see if there is either:

  • An objectively "best" way to solve this problem, or..
  • An industry standard way that is used in practice
$\endgroup$
2
  • $\begingroup$ Would I be right in thinking your "raw RGB triplets" are floating-point values, and the problem comes when you clamp them to [0,1]? $\endgroup$
    – Dan Hulme
    Dec 31, 2017 at 10:53
  • $\begingroup$ @DanHulme That's right! The same problem could also occur if I work with another colorspace internally and then want to convert to something the display or file format can handle. But in this particular case it is because I use floats with light sources brighter than "one". $\endgroup$
    – pipe
    Dec 31, 2017 at 23:23

1 Answer 1

6
$\begingroup$

Effectively, before you start to think about clipping/clamping, you'll need a general approach to map the much wider color range you are working in onto the [0,1] triplets you want to output. There are various way to do this, look up HDR tone mapping to get a good first impression of what is possible. Simply clipping things to [0,1] will leave you with a very cramped color space to work in, throwing away much of the advantages of raytracying in "high dynamic range" (floats).

On to the actual problem at hand, to prevent clamped colours from shifting hue, a naive but functional approach is:

  1. Take the max component m from (R, G, B)
  2. If m > 1, scale all three components by 1 / m.

This does not take the relative luminance of the color components into account, but if you eventually end up doing something like tone-mapping anyway that would be a better time to tackle that problem.

$\endgroup$

Your Answer

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

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