OpenGL颜色插值

Wil*_*une 9 opengl interpolation

我目前正在开发一个C++和OpenGL的小项目,我正在尝试实现类似于photoshop中的颜色选择工具,如下所示.

在此输入图像描述

但是我在插入大方块时遇到了麻烦.使用8800 GTS在我的台式计算机上工作时结果相似,但混合并不顺畅.

这是我正在使用的代码:

GLfloat swatch[] = { 0,0,0, 1,1,1, mR,mG,mB, 0,0,0 };
GLint swatchVert[] = { 400,700, 400,500, 600,500, 600,700 };

glVertexPointer(2, GL_INT, 0, swatchVert);
glColorPointer(3, GL_FLOAT, 0, swatch);
glDrawArrays(GL_QUADS, 0, 4);
Run Code Online (Sandbox Code Playgroud)

使用英特尔图形HD 3000移动到我的笔记本电脑上,这个结果甚至更糟,代码没有变化.

http://i.imgur.com/wSJI2.png

我认为OpenGL将四边形分成两个三角形,所以我尝试使用三角形渲染并在方形中间插入颜色,但它仍然与我希望的结果完全匹配.

在此输入图像描述

dat*_*olf 12

OpenGL对从顶点着色器发出的值到片段着色器的每个片段输入值使用重心插值.您所看到的就是将四边形分成三角形的效果,就像您已经猜到的那样.

现在看一下:有一个右上角的三角形,里面有红色,因此内插红色很好.然后是左下角的三角形,里面只有灰色.当然,右上三角形的红色不会影响左下角的灰色.

问题是,插值发生在RGB空间中,但是为了你想要的结果必须放在HSV或HSL空间中,其中H(Hue)将保持不变.

然而,这不仅仅是插值问题.阻碍你的是,颜色不会线性插值; 大多数显示器都应用了非线性函数,也称为"伽玛"(实际上,伽马是应用于输入值的功率的指数).

您的OpenGL上下文可能是否在颜色校正的颜色空间中.你需要测试一下.然后知道帧缓冲器驻留在哪个颜色空间中,必须使用片段着色器将重心坐标的每个片段变换(使用顶点着色器评估)应用到每个片段值中.


num*_*ric 11

我已经快速制作了一个成功插入颜色的顶点/片段着色器:

#ifdef GL_ES
precision highp float;
#endif

uniform vec2 resolution;

void main(void)
{
    vec2 p = gl_FragCoord.xy / resolution.xy;
    float gray = 1.0 - p.x;
    float red = p.y;
    gl_FragColor = vec4(red, gray*red, gray*red, 1.0);
}
Run Code Online (Sandbox Code Playgroud)

这是结果: 在此输入图像描述

现在将它应用于四边形会产生正确的结果,因为插值是使用xy坐标在整个表面上完成的.请参阅@ datenwolf关于其工作原理的详细说明.

编辑1为了在功能颜色选择器中获得全部颜色,可以交互式修改色调(请参阅/sf/answers/646439811/).

在线演示:http://goo.gl/Ivirl

#ifdef GL_ES
precision highp float;
#endif

uniform float time;
uniform vec2 resolution;

const vec4  kRGBToYPrime = vec4 (0.299, 0.587, 0.114, 0.0);
const vec4  kRGBToI     = vec4 (0.596, -0.275, -0.321, 0.0);
const vec4  kRGBToQ     = vec4 (0.212, -0.523, 0.311, 0.0);

const vec4  kYIQToR   = vec4 (1.0, 0.956, 0.621, 0.0);
const vec4  kYIQToG   = vec4 (1.0, -0.272, -0.647, 0.0);
const vec4  kYIQToB   = vec4 (1.0, -1.107, 1.704, 0.0);

const float PI = 3.14159265358979323846264;

void adjustHue(inout vec4 color, float hueAdjust) {
    // Convert to YIQ
    float   YPrime  = dot (color, kRGBToYPrime);
    float   I      = dot (color, kRGBToI);
    float   Q      = dot (color, kRGBToQ);

    // Calculate the hue and chroma
    float   hue     = atan (Q, I);
    float   chroma  = sqrt (I * I + Q * Q);

    // Make the user's adjustments
    hue += hueAdjust;

    // Convert back to YIQ
    Q = chroma * sin (hue);
    I = chroma * cos (hue);

    // Convert back to RGB
    vec4 yIQ   = vec4 (YPrime, I, Q, 0.0);
    color.r = dot (yIQ, kYIQToR);
    color.g = dot (yIQ, kYIQToG);
    color.b = dot (yIQ, kYIQToB);
}

void main(void)
{
    vec2 p = gl_FragCoord.xy / resolution.xy;
    float gray = 1.0 - p.x;
    float red = p.y;
    vec4 color = vec4(red, gray*red, gray*red, 1.0);
    adjustHue(color, mod(time, 2.0*PI));
    gl_FragColor = color;
}
Run Code Online (Sandbox Code Playgroud)

编辑2:如果需要,与纹理坐标一起使用的着色器(应用于纹理坐标从0到1的四边形)应该看起来像这样.未经测试.

片段着色器:

void main(void)
{
    vec2 p = gl_TexCoord[0].st;
    float gray = 1.0 - p.x;
    float red = p.y;
    gl_FragColor = vec4(red, gray*red, gray*red, 1.0);
}
Run Code Online (Sandbox Code Playgroud)

直通顶点着色器:

void main()
{
    gl_TexCoord[0]=gl_MultiTexCoord0; 
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
Run Code Online (Sandbox Code Playgroud)