Spectral Power Distributions and Conversions
#1
Posted 26 June 2007 - 02:48 AM
This is all well and good, but I don't know how to create a SPD for any color, specifically red, green, and blue. I can find graphs online of various SPD's, but no tables. Could use a normal distribution graph centered around the wavelength of the color I want?
I can't find the standard CIE RGB color matching functions, only the xyz ones, and neither can I find a good, standard linear transformation between XYZ and RGB.
One other thing I'm wondering about is how much information I'm losing when I scale the RGB components to [0, 255] and truncate them. Right now I'm using CImg (http://cimg.sourceforge.net/) to display renders, and I'm using unsigned char's for each RGB value. Is this of any concern, or are the underlying operations on SPD's far more affective on the outcome of a color?
Finally I'm looking for a good reference on natural spline interpolation.
Thank you for any help possible.
#2
Posted 26 June 2007 - 05:24 AM
Another interesting way to generate SPDs is the Planck black-body formula, which lets you compute the radiation emitted by a hot object - for instance, with a temperature of 5700 Kelvin it should mimic sunlight (not including the influence of atmospheric scattering).
For SPDs for a few more light sources as well as spectral reflectance distributions for some common dielectric materials, visit this site. (Reflectance distributions for metals can be calculated using the Fresnel equations, with wavelength-dependent complex refraction indices provided by Luxpop.)
I don't think there is a "standard" CIE RGB color matching function, since the definition of RGB varies. Some RGB color matching functions are tabulated on this site (click the "E/W" buttons to see the tabulated data), but I would stick with using the XYZ color matching functions and transforming into the desired RGB space. Various XYZ-RGB transformations are detailed here. If you're not sure which one to use, sRGB (second from the bottom) is the standard. I couldn't find color matching functions for sRGB, but you could compute them yourself using the XYZ color matching functions and the XYZ->RGB transformation.
Regarding scaling and truncating RGB components, how much damage that does depends how bright your scene is. You'll probably want to look into tone mapping. A simple tone mapping that gives decent results is exposure, which is detailed here. There are many more complex methods of tone mapping too, but I've posted enough links already so I'll let you go research those on your own.
#3
Posted 26 June 2007 - 06:23 PM
And what's the difference between the 10-degree color matching function and the 2-degree color matching function?
#4
Posted 26 June 2007 - 11:33 PM
I thought about exacly this about 1 year ago, but I quite quickly abandoned the idea as I could only find a very minor gain: Materials that look different depending on the spectra of the light source.
(Example: 2 surfaces could look identical under one light source, but very different from each other under another light.)
That would be the result of the spectra of a light source, multiplied by the "spectral reflectance distributions" of the surface, multiplied by the response curves of the film/retina/CCD-chip have many solutions for the same result.
Wha was your plan for this?
#5
Posted 26 June 2007 - 11:56 PM
The only extra computation is converting to RGB if I hard-code the number of samples.
#6
Posted 27 June 2007 - 01:57 AM
flux00 said:
The trapezoidal/Simpson's rule probably isn't necessary; you can just average the CMF over the wavelength range corresponding to each of your channels and multiply that with the SPD (I'm assuming your SPDs will have the same number wavelength bins as output channels in the image; if not, then you may be able to achieve greater accuracy using the trapezoidal rule).
Quote
I'm not entirely sure, but I believe it has to do with the angle of incidence to the human eye - it's how far the point on the retina they're measuring is from the eye's focal point. So, I guess the 2-degree functions are for looking directly at something, and the 10-degree ones are for peripheral vision.
#7
Posted 27 June 2007 - 12:37 PM
geon said:
Something more important: refraction depends on the wavelength. If you increase the number of channels, prisms look better :) And atmospheric scattering is also a function of the wavelength.
#8
Posted 27 June 2007 - 01:56 PM
roel said:
Only for lights with a very un-even spectral distrubution. White light with a flat frequency curve would look fine anyway.
Of course, you could raytrace a scene with 100+ channels to see the induvidual spikes in the spectra of a light source. But that's exctly what I call a "minor gain".
#9
Posted 27 June 2007 - 04:35 PM
This is also nice because colors are no longer treated like 3-vectors. And yes, in general scenes, there isn't much gain, but there isn't much lost either.
Quick question about c++, if I declare a massive two-dimensional of floats, of say, (830-360+1)*3 values, would that be completely cleared from memory when it went out of scope? I sort of want to load select values from a table at compile-time, but don't want the table taking up memory during run-time.
#10
Posted 27 June 2007 - 08:34 PM
#11
Posted 27 June 2007 - 09:20 PM
function
{
array = ...
array[0][0] += 0.F;
}
A lot of the SPD function usages I've seen involve having values of 0 everywhere except the sample points. This way, the integral is just the sum of the product of each sample point and the color matching function at that point. I imagine this is done for the sake of efficiency, and if I actually went through and used some estimate of the integral, wouldn't it be much larger than just adding up the samples?
#12
Posted 27 June 2007 - 09:27 PM
flux00 said:
With distrubution raytracing, where the color of the refracted ray is randomized with the intensity of the spectra (of the unrefracted ray) as the weights. The chosen color would have a single frequency (= full saturation), and thus a single Index Of Refraction. To make the average color correct, the result of the trace would need to be scaled by the number of channels.
At least, that was what I thought. I haven't implemented this...
#13
Posted 27 June 2007 - 10:33 PM
#14
Posted 28 June 2007 - 02:51 AM
flux00 said:
function
{
array = ...
array[0][0] += 0.F;
}
I don't understand. Can you be more specific? What are you trying to do?
Quote
It's not that they're taking the SPD to be zero everywhere aside from the sample points, it's just that they're integrating it using a rectangle for each sample point instead of e.g. trapezoids. Strictly speaking you should scale by the width of the rectangle - for instance, if the SPD is sampled at 10 nanometer intervals, you'd scale the result by 10. But that's not really necessary; the numbers output by a raytracer are relative anyway. (Mathematically, you can just define your units of wavelength such that the scale goes away. For instance, if the SPD is sampled at 10 nanometer intervals, define the unit of wavelength as 10 nanometers so that the width of each rectangle is 1.)
Whatever integration method you choose, scale each CMF so that it integrates to one across the visual spectrum, and you should be fine.
#15
Posted 28 June 2007 - 05:13 PM
Ok, say I have the sampled SPD and the XYZ color matching functions. I multiply each sample of the SPD by the each respective color matching function, resulting in 3 functions. Simply summing up the samples of each function would mean integration by rectangles. Would integration by the trapezoid rule or Simpson's rule just mean weighting each sample?
e.g. the trapezoid rule would just become
(b-a)/(2n) * (f(x[0]) + 2f(x[1]) + ... + 2f(x[n-2]) + f(x[n-1]) to .5*f(x[0]) + f(x[1]) + ... + f(x[n-2]) + .5*f(x[n-1])
Or would I still divide the sum by n? How would I know expected range so I could scale each resulting XYZ component? Should I divide each component by the largest, or by the sum or every component? Would either work?
#16
Posted 28 June 2007 - 06:52 PM
I'm not sure what you're asking about the expected range of values - the radiance values in your SPD can be anywhere from 0 to infinity, so the XYZ/RGB values you'll get out of all this will be similiar. You use tone mapping later on to map this into the actual output range of your display.
#17
Posted 29 June 2007 - 09:13 AM
http://www.cs.sfu.ca..._8h-source.html
void XYZ(float xyz[3]) const {
xyz[0] = xyz[1] = xyz[2] = 0.;
for (int i = 0; i < COLOR_SAMPLES; ++i) {
xyz[0] += XWeight[i] * c[i];
xyz[1] += YWeight[i] * c[i];
xyz[2] += ZWeight[i] * c[i];
}
}
float Spectrum::XWeight[COLOR_SAMPLES] = {
0.412453f, 0.357580f, 0.180423f
};
float Spectrum::YWeight[COLOR_SAMPLES] = {
0.212671f, 0.715160f, 0.072169f
};
float Spectrum::ZWeight[COLOR_SAMPLES] = {
0.019334f, 0.119193f, 0.950227f
};
Are these values derived from the color matching function in some way?
#18
Posted 29 June 2007 - 04:17 PM
#19
Posted 30 June 2007 - 05:50 AM
#20
Posted 30 June 2007 - 07:27 AM
The question becomes how to choose the RGB primaries you use. Ideally, you would use primaries that match the spectra of light emitted by the red, green, and blue phosphors or liquid crystals in your monitor. In reality that may not be practical, since you might not know what those spectra are or you might be trying to make the program work for many different monitors. Hence the use of sRGB, which represents a sort of average over typical monitors, and also allows for image processing programs to convert the image into the primaries for a specific display device (which can be done using a linear transformation from sRGB).
The caveat about sRGB, and all common RGB color spaces, is that it's not possible to represent all visible colors using RGB values in the range [0, 1]^3. You can represent all visible colors if you allow RGB values outside that range, but of course in real life, monitors can only display values in [0, 1]^3, since they have a maximum power and they can't use negative voltages. XYZ is a set of primaries for which all visible colors fall inside the [0, 1]^3 cube.
1 user(s) are reading this topic
0 members, 1 guests, 0 anonymous users












