我如何在Freeglut中画彩虹?

qua*_*ant 7 c++ opengl freeglut

我正试图在openGL中绘制一个彩虹色的情节传奇.这是我到目前为止所得到的:

glBegin(GL_QUADS);
for (int i = 0; i != legendElements; ++i)
{
    GLfloat const cellColorIntensity = (GLfloat) i / (GLfloat) legendElements;
    OpenGL::pSetHSV(cellColorIntensity*360.0f, 1.0f, 1.0f);

    // draw the ith legend element
    GLdouble const xLeft = xBeginRight - legendWidth;
    GLdouble const xRight = xBeginRight;
    GLdouble const yBottom = (GLdouble)i * legendHeight /
    (GLdouble)legendElements + legendHeight;
    GLdouble const yTop = yBottom + legendHeight;

    glVertex2d(xLeft, yTop); // top-left
    glVertex2d(xRight, yTop); // top-right
    glVertex2d(xRight, yBottom); // bottom-right
    glVertex2d(xLeft, yBottom); // bottom-left
}

glEnd();
Run Code Online (Sandbox Code Playgroud)

legendElements是构成"彩虹"的离散方块的数量.xLeft,xRight,yBottom并且yTop是构成每个平方的顶点.

函数OpenGL::pSetHSV看起来像这样:

void pSetHSV(float h, float s, float v) 
{
    // H [0, 360] S and V [0.0, 1.0].
    int i = (int)floor(h / 60.0f) % 6;
    float f = h / 60.0f - floor(h / 60.0f);
    float p = v * (float)(1 - s);
    float q = v * (float)(1 - s * f);
    float t = v * (float)(1 - (1 - f) * s);
    switch (i) 
    {
        case 0: glColor3f(v, t, p);
            break;
        case 1: glColor3f(q, v, p);
            break;
        case 2: glColor3f(p, v, t);
            break;
        case 3: glColor3f(p, q, v);
            break;
        case 4: glColor3f(t, p, v);
            break;
        case 5: glColor3f(v, p, q);
    }
}
Run Code Online (Sandbox Code Playgroud)

我从http://forum.openframeworks.cc/t/hsv-color-setting/770获得了这个功能

但是,当我绘制它时,它看起来像这样:

在此输入图像描述

我想要的是一系列红色,绿色,蓝色,靛蓝色,紫色(所以我想通过Hue线性迭代.但是,这似乎并不是真正发生的事情.

我真的不明白RGB/HSV的转换是如何pSetHSV()工作的,所以我很难确定问题.

编辑:这是固定版本,受Jongware的启发(矩形被错误地绘制):

// draw legend elements
glBegin(GL_QUADS);
for (int i = 0; i != legendElements; ++i)
{
    GLfloat const cellColorIntensity = (GLfloat) i / (GLfloat) legendElements;
    OpenGL::pSetHSV(cellColorIntensity * 360.0f, 1.0f, 1.0f);

    // draw the ith legend element
    GLdouble const xLeft = xBeginRight - legendWidth;
    GLdouble const xRight = xBeginRight;
    GLdouble const yBottom = (GLdouble)i * legendHeight /
    (GLdouble)legendElements + legendHeight + yBeginBottom;
    GLdouble const yTop = yBottom + legendHeight / legendElements;

    glVertex2d(xLeft, yTop); // top-left
    glVertex2d(xRight, yTop); // top-right
    glVertex2d(xRight, yBottom); // bottom-right
    glVertex2d(xLeft, yBottom); // bottom-left
}

glEnd();
Run Code Online (Sandbox Code Playgroud)

Spe*_*tre 8

我生成这样的光谱颜色:

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;
    }
Run Code Online (Sandbox Code Playgroud)
  • l 是输入波长 [nm] < 380,780 >
  • r,g,b 输出RGB颜色 < 0,1 >

这是sin实际光谱颜色数据的简单粗波近似.你也可以从这里创建表并插入它或使用纹理...输出颜色是:

spectral_colors

还有不同的方法,如:

  1. 线性颜色 - 复合梯度

  2. 人眼X,Y,Z灵敏度曲线积分

    你必须拥有非常精确的X,Y,Z曲线,即使轻微的偏差也会导致像这个例子中那样"不切实际"的颜色

    人眼XYZ灵敏度

为了使其更好,您必须标准化颜色并添加指数灵敏度校正.这些曲线也随着每一代而变化,并且在世界的不同地区有所不同.因此,除非你正在做一些特殊的医疗/物理软件,否则这样做并不是一个好主意.

光谱颜色比较

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

[edit1] 这里 是我新的物理更准确的转换

我强烈建议使用这种方法(它以任何方式更准确,更好)