How do I draw a rainbow in Freeglut?

倾然丶 夕夏残阳落幕 提交于 2019-11-29 14:05:38
Spektre

I generate spectral colors like this:

void spectral_color(double &r,double &g,double &b,double l) // RGB <- lambda l = < 380,780 > [nm]
    {
         if (l<380.0) r=     0.00;
    else if (l<400.0) r=0.05-0.05*sin(M_PI*(l-366.0)/ 33.0);
    else if (l<435.0) r=     0.31*sin(M_PI*(l-395.0)/ 81.0);
    else if (l<460.0) r=     0.31*sin(M_PI*(l-412.0)/ 48.0);
    else if (l<540.0) r=     0.00;
    else if (l<590.0) r=     0.99*sin(M_PI*(l-540.0)/104.0);
    else if (l<670.0) r=     1.00*sin(M_PI*(l-507.0)/182.0);
    else if (l<730.0) r=0.32-0.32*sin(M_PI*(l-670.0)/128.0);
    else              r=     0.00;
         if (l<454.0) g=     0.00;
    else if (l<617.0) g=     0.78*sin(M_PI*(l-454.0)/163.0);
    else              g=     0.00;
         if (l<380.0) b=     0.00;
    else if (l<400.0) b=0.14-0.14*sin(M_PI*(l-364.0)/ 35.0);
    else if (l<445.0) b=     0.96*sin(M_PI*(l-395.0)/104.0);
    else if (l<510.0) b=     0.96*sin(M_PI*(l-377.0)/133.0);
    else              b=     0.00;
    }
  • l is input wavelength [nm] < 380,780 >
  • r,g,b is output RGB color < 0,1 >

This is simple rough sin wave approximation of real spectral color data. You can also create table from this and interpolate it or use texture ... output colors are:

there are also different approaches like:

  1. linear color - composite gradients

  2. human eye X,Y,Z sensitivity curves integration

    you have to have really precise X,Y,Z curves, even slight deviation causes 'unrealistic' colors like in this example

To make it better you have to normalize colors and add exponential sensitivity corrections. Also these curves are changing with every generation and are different in different regions of world. So unless you are doing some special medical/physics softs it is not a good idea to go this way.

| <- 380nm ----------------------------------------------------------------- 780nm -> |

[edit1] here is mine new physically more accurate conversion

I strongly recommend to use this approach instead (it is more accurate and better in any way)

Well, not completely right. Here I made a javascript example of it. Sodium yellow (589nm) is too orange and Halpha red (656nm) is too brown....

Save this example into an HTML file (jquery needed) and load it into a browser: page.html?l=[nanometers]

<!DOCTYPE html>
<html><head>
<script src='jquery.js'></script>
<script>


/*
 * Return parameter value of name (case sensitive !)
 */
function get_value(parametername)
{
    readvalue=(location.search ? location.search.substring(1) : false);

    if (readvalue)
    {
       parameter=readvalue.split('&');
       for (i=0; i<parameter.length; i++)
       {
           if (parameter[i].split('=')[0] == parametername)
             return parameter[i].split('=')[1];
       }
    }
    return false;
}

function spectral_color(l) // RGB <- lambda l = < 380,780 > [nm]
{
  var M_PI=Math.PI;
  var r=0,g,b;
  if (l<380.0) r=     0.00;
  else if (l<400.0) r=0.05-0.05*Math.sin(M_PI*(l-366.0)/ 33.0);
  else if (l<435.0) r=     0.31*Math.sin(M_PI*(l-395.0)/ 81.0);
  else if (l<460.0) r=     0.31*Math.sin(M_PI*(l-412.0)/ 48.0);
  else if (l<540.0) r=     0.00;
  else if (l<590.0) r=     0.99*Math.sin(M_PI*(l-540.0)/104.0);
  else if (l<670.0) r=     1.00*Math.sin(M_PI*(l-507.0)/182.0);
  else if (l<730.0) r=0.32-0.32*Math.sin(M_PI*(l-670.0)/128.0);
  else              r=     0.00;
       if (l<454.0) g=     0.00;
  else if (l<617.0) g=     0.78*Math.sin(M_PI*(l-454.0)/163.0);
  else              g=     0.00;
       if (l<380.0) b=     0.00;
  else if (l<400.0) b=0.14-0.14*Math.sin(M_PI*(l-364.0)/ 35.0);
  else if (l<445.0) b=     0.96*Math.sin(M_PI*(l-395.0)/104.0);
  else if (l<510.0) b=     0.96*Math.sin(M_PI*(l-377.0)/133.0);
  else              b=     0.00;
  var rgb = Math.floor(r*256)*65536+Math.floor(g*256)*256 + Math.floor(b*256);
  rgb = '000000' + rgb.toString(16);
  rgb = '#' + rgb.substr(-6).toUpperCase();

  $('#color').html([r,g,b,rgb,l]);
  $('body').css('background-color', rgb);
}

</script>
</head><body>
<div id='color'></div>
<script>
spectral_color(get_value('l'));
</script>
</body>
</html>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!