# Generating and Combining Spectral Colors

I have two somewhat related questions to ask:

1. What is the most accurate way to get the colors of a spectrum, without having to go deep into physics and simulating the universe? ;) Right now, I'm using these color matching functions, and simply reading off the XYZ color of a particular wavelength and converting it to sRGB. I know sRGB can't represent most spectral colors, but let's ignore that.
2. If I'm trying to make a color, say white, out of the spectral colors, how should I combine them? Should I add the color in XYZ space, or in RGB space, or is neither sufficient?

My plan is to experiment with spectral rendering, so it should be accurate enough to avoid biased renders. It'll most likely be on the GPU, and I need accuracy over speed.

• What's best depends a lot on your application and what operations you want to do on these spectra. Could you edit your question to add some more about that? – Dan Hulme Jan 15 '18 at 22:17
• Just edited my question to add a bit of clarification. – Daniel Kareh Jan 15 '18 at 22:40

Your way of calculating XYZ functions is probably the most efficient way to go about calculating accurate colors from a spectrum. It is standard practice afaik, for examples the books Physically Based Rendering (3rd) and Real-Time Rendering (3rd) both use this method.

You can add the colors in RGB space, but only if you convert from sRGB to linear RGB first. Otherwise you need to take into account, that sRGB sums will not lead to correct colors. The blogpost Adventures with Gamma-Correct Rendering by Naty Hoffman is a good read regarding this, topc:

Computing shading in sRGB space is like doing math in a world where 1+1=3.

This is the problem you have when adding colors in sRGB.

As to whether $XYZ$ can be summed, I think so. If we look at the definition of the coordinates (for $S$ is the spectral function and $x, y, z$ are the CIE functions):

$X = \frac{1}{\int_\lambda y(\lambda) d\lambda} \int_\lambda S(\lambda) x(\lambda) d\lambda$

Now two $X$ coordinates $X_1, X_2$ would have the same definition, only the spectrals are different ($S_1, S_2$).

Thus you have

$X_1 + X_2 = \frac{1}{\int_\lambda y(\lambda) d\lambda} \int_\lambda S_1(\lambda) x(\lambda) d\lambda + \frac{1}{\int_\lambda y(\lambda) d\lambda} \int_\lambda S_2(\lambda) x(\lambda) d\lambda\\ = \frac{1}{\int_\lambda y(\lambda) d\lambda} \left(\int_\lambda S_1(\lambda) x(\lambda) d\lambda + \int_\lambda S_2(\lambda) x(\lambda) d\lambda\right)\\ = \frac{1}{\int_\lambda y(\lambda) d\lambda}\int_\lambda S_1(\lambda) x(\lambda) + S_2(\lambda) x(\lambda) d\lambda \\ = \frac{1}{\int_\lambda y(\lambda) d\lambda}\int_\lambda (S_1(\lambda) + S_2(\lambda)) x(\lambda) d\lambda\\ =X$

The same holds for other coordinates.

Therefore, your best option is probably to sum your XYZ coordinates and convert them to sRGB space in the end.

• Comforting to know that I'm doing this well. I also like your little quote ;) Well said, your answer is accepted. – Daniel Kareh Jan 16 '18 at 21:43