POV-Ray : Newsgroups : povray.advanced-users : D65 spectral locus Server Time: 16 Jun 2019 07:41:28 GMT
 D65 spectral locus (Message 1 to 10 of 16)
 From: Mike Horvath Subject: D65 spectral locus Date: 16 Mar 2017 15:49:24 Message: <58cab404\$1@news.povray.org>
```I'm trying to use this formula to plot the visible gamut in XYZ space.

http://www.brucelindbloom.com/index.html?Eqn_Spect_to_XYZ.html

Here is my code:

#local xSum = 0;
#local ySum = 0;
#local zSum = 0;
#local nSum = 0;
#for (i, 0, 89)
#local nSum = nSum + (xyz_table[i].y * D65_table[i]);
#end
#for (i, 0, 89)
#local xSum = 1/nSum * (xSum + xyz_table[i].x * 1 * D65_table[i]);
#for (j, 0, 89)
#local ySum = 1/nSum * (ySum + xyz_table[j].y * 1 * D65_table[j]);
#for (k, 0, 89)
#local zSum = 1/nSum * (zSum + xyz_table[k].z * 1 * D65_table[k]);
sphere
{
<xSum, ySum, zSum> * 10, 0.005
pigment {color rgb x}
}
#end
#end
#end

However, the resulting shape is box-shaped instead of cone-shaped. Am I
approaching things in the right way?

Mike
```
 From: Mike Horvath Subject: Re: D65 spectral locus Date: 16 Mar 2017 16:36:00 Message: <58cabef0\$1@news.povray.org>
```On 3/16/2017 11:49 AM, Mike Horvath wrote:
> I'm trying to use this formula to plot the visible gamut in XYZ space.
>
> http://www.brucelindbloom.com/index.html?Eqn_Spect_to_XYZ.html
>
> Here is my code:
>
>     #local xSum = 0;
>     #local ySum = 0;
>     #local zSum = 0;
>     #local nSum = 0;
>     #for (i, 0, 89)
>         #local nSum = nSum + (xyz_table[i].y * D65_table[i]);
>     #end
>     #for (i, 0, 89)
>         #local xSum = 1/nSum * (xSum + xyz_table[i].x * 1 * D65_table[i]);
>         #for (j, 0, 89)
>             #local ySum = 1/nSum * (ySum + xyz_table[j].y * 1 *
> D65_table[j]);
>             #for (k, 0, 89)
>                 #local zSum = 1/nSum * (zSum + xyz_table[k].z * 1 *
> D65_table[k]);
>                 sphere
>                 {
>                     <xSum, ySum, zSum> * 10, 0.005
>                     pigment {color rgb x}
>                 }
>             #end
>         #end
>     #end
>
> However, the resulting shape is box-shaped instead of cone-shaped. Am I
> approaching things in the right way?
>
>
> Mike

This works a bit better, but is still not right:

#local nSum = 0;
#for (i, 0, 89)
#local nSum = nSum + (xyz_table[i].y * D65_table[i]);
#end
#local xSum = 0;
#for (i, 0, 89)
#local xSum = xSum + xyz_table[i].x * 1 * D65_table[i];
#local ySum = 0;
#for (j, 0, 89)
#local ySum = ySum + xyz_table[j].y * 1 * D65_table[j];
#local zSum = 0;
#for (k, 0, 89)
#local zSum = zSum + xyz_table[k].z * 1 * D65_table[k];
#local xyYCoo = 1/nSum * <xSum, ySum, zSum>;
#local xyYCoo = XYZ2xyY(xyYCoo);
#local xyYCoo = <xyYCoo.x,xyYCoo.z,xyYCoo.y>;
sphere
{
xyYCoo, 1/80
pigment {color rgb x}
}
#end
#end
#end

Mike
```
 From: clipka Subject: Re: D65 spectral locus Date: 16 Mar 2017 23:53:20 Message: <58cb2570\$1@news.povray.org>
```Am 16.03.2017 um 17:36 schrieb Mike Horvath:

> This works a bit better, but is still not right:
>
>     #local nSum = 0;
>     #for (i, 0, 89)
>         #local nSum = nSum + (xyz_table[i].y * D65_table[i]);
>     #end
>     #local xSum = 0;
>     #for (i, 0, 89)
>         #local xSum = xSum + xyz_table[i].x * 1 * D65_table[i];
>         #local ySum = 0;
>         #for (j, 0, 89)
>             #local ySum = ySum + xyz_table[j].y * 1 * D65_table[j];
>             #local zSum = 0;
>             #for (k, 0, 89)
>                 #local zSum = zSum + xyz_table[k].z * 1 * D65_table[k];
>                 #local xyYCoo = 1/nSum * <xSum, ySum, zSum>;
>                 #local xyYCoo = XYZ2xyY(xyYCoo);
>                 #local xyYCoo = <xyYCoo.x,xyYCoo.z,xyYCoo.y>;
>                 sphere
>                 {
>                     xyYCoo, 1/80
>                     pigment {color rgb x}
>                 }
>             #end
>         #end
>     #end

Sorry, but this is totally bonkers.

The indices into xyz_table are to be interpreted as representing
wavelengths.

So you're varying three wavelength variables independently: For one (i)
you're summing up the x component; for another one (j) you're summing up
the y component; and for yet another one (k) you're summing up the z
component.

What good do you expect this to do?

What you really need is a smart external loop or set of loops that
generates /spectra/, not wavelengths -- and then within that loop insert
a /single/ additional loop that varies a wavelength variable i, summing
up xyz_table[i] * D65_table[i] * spectral_power(i).
```
 From: Mike Horvath Subject: Re: D65 spectral locus Date: 17 Mar 2017 04:59:16 Message: <58cb6d24\$1@news.povray.org>
```On 3/16/2017 7:53 PM, clipka wrote:
>
> Sorry, but this is totally bonkers.
>
> The indices into xyz_table are to be interpreted as representing
> wavelengths.
>
> So you're varying three wavelength variables independently: For one (i)
> you're summing up the x component; for another one (j) you're summing up
> the y component; and for yet another one (k) you're summing up the z
> component.
>
> What good do you expect this to do?
>
> What you really need is a smart external loop or set of loops that
> generates /spectra/, not wavelengths -- and then within that loop insert
> a /single/ additional loop that varies a wavelength variable i, summing
> up xyz_table[i] * D65_table[i] * spectral_power(i).
>

Yes, how do I come up with these /spectra/? I don't have a
spectral_power(i) and it is not mentioned in the equations I am trying

http://www.brucelindbloom.com/index.html?Eqn_Spect_to_XYZ.html

Mike
```
 From: Mike Horvath Subject: Re: D65 spectral locus Date: 17 Mar 2017 05:26:52 Message: <58cb739c\$1@news.povray.org>
```This page

http://www.brucelindbloom.com/index.html?LabGamutDisplayHelp.html

Talks about generating "pulses" to determine the shape extents. It
doesn't really explain very well what the "pulses" are and what to do
with them.

Here is a collection of demos

http://www.brucelindbloom.com/index.html?LabGamutDisplayHelp.html

Mike
```
 From: clipka Subject: Re: D65 spectral locus Date: 17 Mar 2017 08:49:22 Message: <58cba312@news.povray.org>
```Am 17.03.2017 um 06:27 schrieb Mike Horvath:
>
> http://www.brucelindbloom.com/index.html?LabGamutDisplayHelp.html
>
> Talks about generating "pulses" to determine the shape extents. It
> doesn't really explain very well what the "pulses" are and what to do
> with them.

Ah, yes. That's the thing I had come up with as well. Here's my attempt
at explaining how it works.

First, notice that the colours that make up the surface of the shape are
the same no matter what colour space you choose: Converting it from e.g.
CIE XYZ to CIE xyY or CIE L*a*b distorts the shape, but doesn't affect
its topology.

I will focus on CIE xyY colour space, because in this colour space the
shape has a property I will exploit.

Let's start by finding the "girth" of the shape in xyY space -- the
points that have the most extreme xy coordinates, farthest away from the
equal-energy point at x=y=1/3.

Obviously, the most extreme xy coordinates of real colours you can ever
get are those of pure monochromatic spectra, i.e. spectra where all the
power is focused into a single wavelength, like this one:

Power (%)
|
100 _|
|               !
80 __|               !
|               !
60 __|               !
|               !
40 __|               !
|               !
20 __|               !
|               !
0 ___|_______________!___________________________
|   |   |   |   |   |   |   |   |   |   |    Wavelength (nm)
350 400 450 500 550 600 650 700 750 800 850

If we were talking about emissive spectra, such a colour could be
arbitrarily bright, because we could put arbitrarily much power into it.
However, we want to examine reflected light, so we can't exceed 100%.

Now notice that since we asked for a single wavelength, we got a
spectrum with an infinitesimally small width. Which also means that if
this is the spectrum of a reflector, it can only reflect an
infinitesimally small portion of the incoming light.

This means that as we approach the most extreme xy coordinates, the
brightness approaches zero -- in other words, the "girth" of our shape
is at Y=0 (or, more precisely, infinitesimally small Y).

Notice that the shape of this "girth" is exactly the famous CIE xy
horseshoe.

Now suppose we want to consider all the possibilities we have to
increase the brightness of our initial monochromatic spectrum:

We don't need to follow this idea any further, as it would be equivalent
to splitting up that non-monochromatic spectrum into an infinite number
of monochromatic spectra, and adding those one after the other.

Power (%)
|
100 _|
|               !
80 __|               !
|               !
60 __|               !       !
|               !       !
40 __|               !       !
|               !       !
20 __|               !       !
|               !       !
0 ___|_______________!_______!___________________
|   |   |   |   |   |   |   |   |   |   |    Wavelength (nm)
350 400 450 500 550 600 650 700 750 800 850

Note that this added spectrum corresponds to a particular xy coordinate
on the horseshoe, and mixing it into our initial spectrum will shift the
xy coordinate of our resulting colour towards that point on the
horseshoe. This will take us _inside_ the shape, so we're not interested
in such a colour.

(C) Widen our spectrum:

Power (%)
|
100 _|
|               #
80 __|               #
|               #
60 __|               #
|               #
40 __|               #
|               #
20 __|               #
|               #
0 ___|_______________#___________________________
|   |   |   |   |   |   |   |   |   |   |    Wavelength (nm)
350 400 450 500 550 600 650 700 750 800 850

Note that this also _slightly_ shifts the xy coordinate towards the
center of the horseshoe, but it is the best we can get for the new
brightness. Therefore, the resulting colour _is_ on the surface of the
shape.

Now our spectrum is no longer monochromatic.

How can we make this colour even brighter? Well, through the very same
processes:

(C) Widen our spectrum.

Once again, (A) is of no interest since it can be achieved in smaller
steps via either (B) or (C); (B) would take us inside the shape; and (C)
is the way to go.

However, now that our spectrum is no longer infinitesimally small, we
can (and have to) take a closer look at such a widened spectrum.

Consider the following two spectra:

(C.1)

Power (%)
|
100 _|
|               #
80 __|              ###
|              ###
60 __|             #####
|             #####
40 __|             #####
|             #####
20 __|            #######
|            #######
0 ___|___________#########_______________________
|   |   |   |   |   |   |   |   |   |   |    Wavelength (nm)
350 400 450 500 550 600 650 700 750 800 850

(C.2)

Power (%)
|
100 _|
|             #####
80 __|             #####
|             #####
60 __|             #####
|             #####
40 __|             #####
|             #####
20 __|             #####
|             #####
0 ___|_____________#####_________________________
|   |   |   |   |   |   |   |   |   |   |    Wavelength (nm)
350 400 450 500 550 600 650 700 750 800 850

Let's assume both have the same brightness and also the same hue.

Notice how (C.2) is tighther than (C.1). As a result, it is more
saturated -- as a matter of fact it is the maximum saturation you can
get for that hue and brightness. So (C.2) is on the surface of our
shape, while (C.1) is slightly inside.

We can repeat the process until we have widened our spectrum to cover
the entire visible range: That's the whitepoint, so we can go no further
up in Y; and we also can't get more colourful without reducing the
brightness.

Thus, all colours on the surface of our shape have one thing in common:
Their spectrum is at 100% over a contiguous range of wavelengths, and 0%
outside that range. Their only difference is the width of that range,
and its location.

Are we done yet? Nope, there's one thing we have forgotten: The purple line.

At the purple side of the shape, the purest and brightest colours you
can get are additions of one spectra at the extreme blue end and another
one at the extreme red end, like this one:

Power (%)
|
100 _|
####                                 #######
80 __####                                 #######
####                                 #######
60 __####                                 #######
####                                 #######
40 __####                                 #######
####                                 #######
20 __####                                 #######
####                                 #######
0 ___####_________________________________#######
|   |   |   |   |   |   |   |   |   |   |    Wavelength (nm)
350 400 450 500 550 600 650 700 750 800 850

To keep the algorithm simple, it is convenient to think of the visible
spectrum as "wrapping around" at purple, so the above spectrum can be
thought of as being at 100% in the range from 800nm to 400nm (wrapping
around in between).

There. Now you know the common property of all reflection spectra that
map to the surface of the shape you're after. I hope this helps you
devise an algorithm to compute them in a systematic fashion.
```
 From: Mike Horvath Subject: Re: D65 spectral locus Date: 18 Mar 2017 20:35:54 Message: <58cd9a2a\$1@news.povray.org>
```On 3/17/2017 4:49 AM, clipka wrote:
> There. Now you know the common property of all reflection spectra that
> map to the surface of the shape you're after. I hope this helps you
> devise an algorithm to compute them in a systematic fashion.
>

I was able to get some coding help from Bruce Lindbloom to generate the
XYZ coordinates. So, I have points and I have colors. But I do not have
a mesh. Do you have any tips on generating the mesh? Did you use one
color for each triangle, or did you create some sort of gradient?

Mike
```
 From: Mike Horvath Subject: Re: D65 spectral locus Date: 18 Mar 2017 22:08:01 Message: <58cdafc1\$1@news.povray.org>
```On 3/18/2017 4:36 PM, Mike Horvath wrote:
> On 3/17/2017 4:49 AM, clipka wrote:
>> There. Now you know the common property of all reflection spectra that
>> map to the surface of the shape you're after. I hope this helps you
>> devise an algorithm to compute them in a systematic fashion.
>>
>
> I was able to get some coding help from Bruce Lindbloom to generate the
> XYZ coordinates. So, I have points and I have colors. But I do not have
> a mesh. Do you have any tips on generating the mesh? Did you use one
> color for each triangle, or did you create some sort of gradient?
>
>
> Mike
>
>
>

Also, is the shape stacked like a wedding cake? Are there the same
number of sections in each layer?

Mike
```
 From: clipka Subject: Re: D65 spectral locus Date: 19 Mar 2017 21:49:28 Message: <58cefce8\$1@news.povray.org>
```Am 18.03.2017 um 23:08 schrieb Mike Horvath:
> On 3/18/2017 4:36 PM, Mike Horvath wrote:
>> On 3/17/2017 4:49 AM, clipka wrote:
>>> There. Now you know the common property of all reflection spectra that
>>> map to the surface of the shape you're after. I hope this helps you
>>> devise an algorithm to compute them in a systematic fashion.
>>>
>>
>> I was able to get some coding help from Bruce Lindbloom to generate the
>> XYZ coordinates. So, I have points and I have colors. But I do not have
>> a mesh. Do you have any tips on generating the mesh? Did you use one
>> color for each triangle, or did you create some sort of gradient?

I created and linked the points according to the following scheme:

.###.... -- ..###... -- ...###.. -- ....###.
\        /  \        /  \        /
\      /    \      /    \      /
\    /      \    /      \    /
\  /        \  /        \  /
..##.... -- ...##... -- ....##..
/  \        /  \        /  \
/    \      /    \      /    \
/      \    /      \    /      \
/        \  /        \  /        \
..#..... -- ...#.... -- ....#... -- .....#..

where each `.` represents an interval in the spectrum that's at 0% power
and each `#` represents an interval in the spectrum that's at 100% power.

- On each line from left to right, the "box" spectra have a constant
width, but the starting point and end point shift from blue to red.

- On each line from bottom left to top right, the "box" spectra have a
constant starting point, but their width increases as the end point
shifts from blue to red.

- On each line from top left to bottom right, the "box" spectra have a
constant end point, but their width decreases as the starting point
shifts from blue to red.

Remember to define a point where your spectrum wraps around from red to
blue. The "mod" function helps a lot with that.

> Also, is the shape stacked like a wedding cake? Are there the same
> number of sections in each layer?

The layers shown as horizontal lines in the diagram above will /not/ be
perfectly horizontal in the colour space, due to the varying brightness
associated with each wavelength interval; but each layer will have the
same number of points.
```
 From: Mike Horvath Subject: Re: D65 spectral locus Date: 19 Mar 2017 22:04:34 Message: <58cf0072\$1@news.povray.org>
```On 3/19/2017 5:49 PM, clipka wrote:
> Am 18.03.2017 um 23:08 schrieb Mike Horvath:
>> On 3/18/2017 4:36 PM, Mike Horvath wrote:
>>> On 3/17/2017 4:49 AM, clipka wrote:
>>>> There. Now you know the common property of all reflection spectra that
>>>> map to the surface of the shape you're after. I hope this helps you
>>>> devise an algorithm to compute them in a systematic fashion.
>>>>
>>>
>>> I was able to get some coding help from Bruce Lindbloom to generate the
>>> XYZ coordinates. So, I have points and I have colors. But I do not have
>>> a mesh. Do you have any tips on generating the mesh? Did you use one
>>> color for each triangle, or did you create some sort of gradient?
>
> I created and linked the points according to the following scheme:
>
>     .###.... -- ..###... -- ...###.. -- ....###.
>          \        /  \        /  \        /
>           \      /    \      /    \      /
>            \    /      \    /      \    /
>             \  /        \  /        \  /
>           ..##.... -- ...##... -- ....##..
>             /  \        /  \        /  \
>            /    \      /    \      /    \
>           /      \    /      \    /      \
>          /        \  /        \  /        \
>     ..#..... -- ...#.... -- ....#... -- .....#..
>
> where each `.` represents an interval in the spectrum that's at 0% power
> and each `#` represents an interval in the spectrum that's at 100% power.
>
> - On each line from left to right, the "box" spectra have a constant
> width, but the starting point and end point shift from blue to red.
>
> - On each line from bottom left to top right, the "box" spectra have a
> constant starting point, but their width increases as the end point
> shifts from blue to red.
>
> - On each line from top left to bottom right, the "box" spectra have a
> constant end point, but their width decreases as the starting point
> shifts from blue to red.
>
> Remember to define a point where your spectrum wraps around from red to
> blue. The "mod" function helps a lot with that.
>
>> Also, is the shape stacked like a wedding cake? Are there the same
>> number of sections in each layer?
>
> The layers shown as horizontal lines in the diagram above will /not/ be
> perfectly horizontal in the colour space, due to the varying brightness
> associated with each wavelength interval; but each layer will have the
> same number of points.
>

Did you use a function to color the shape, or did you color each
triangle in a solid color? I am doing the latter at the moment using the
xyz2RGB() macro that comes with Lightsys. It works okay, but you can see
each and every triangle as a result. I don't like that.

I also tried re-using the function I used to color the sRGB gamut, and
the result is very wonky and random looking. Not good.

Mike
```