2012-11-03 106 views
8

我目前正在C++和OpenGL中開發一個小項目,並試圖實現類似於Photoshop中的顏色選擇工具,如下所示。OpenGL顏色插值

enter image description here

但是我有大型廣場的插值麻煩。 使用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); 

移動到我的筆記本採用Intel顯卡HD 3000,這個結果是即使在代碼沒有變化更糟。

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

我認爲這是OpenGL的分裂四成兩個三角形,所以我嘗試使用三角形渲染,並在廣場中間插顏色自己,但它仍犯規的結果,我所期待的完全匹配。

enter image description here

回答

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); 
} 

這裏的結果: enter image description here

應用它在四,現在產量的正確的結果,因爲使用xy座標真正在整個表面上完成插值。請參閱@ datenwolf的詳細說明,瞭解爲什麼這會起作用。

EDIT 1爲了獲得全範圍的功能性顏色選擇器的顏色,所以能夠交互式地修改色相(見https://stackoverflow.com/a/9234854/570738)。

Live在線演示: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; 
} 

編輯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); 
} 

直通頂點着色器:

void main() 
{ 
    gl_TexCoord[0]=gl_MultiTexCoord0; 
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
} 
+0

謝謝您的回答,我有經驗非常少GLSL雖然我似乎記得如果你想使用着色器,你必須實現一切,因爲它完全取代了OpenGL管道。有沒有簡單的方法來使用你提供的着色器,只將它應用到一次glDrawArrays()的調用? –

+0

@意志財富:只要你堅持使用OpenGL-2.1及以下版本,你就可以有選擇地使用着色器。即大多數情況下使用固定功能管道,但只有一些着色器。只有OpenGL-3核心和更高版本*必須使用着色器。但老實說:使用着色器讓生活變得更簡單,所以我強烈建議在任何地方使用它們。 – datenwolf

+0

@意志財富我通常會使用框架或圖形引擎來更容易地管理着色器。不過,我將此引用至:http://nehe.gamedev.net/article/glsl_an_introduction/25007/跳至「GLSL API如何在OpenGL應用程序中使用GLSL」部分。本節將向您展示如何在這些評論中更好地融入glsl着色器。 – num3ric

9

的OpenGL使用重心插值上從頂點着色器發射到片段着色器的所述每片段的輸入值的值。你所看到的是將四邊形分割成三角形的效果,因爲你已經猜對了。

現在看看它:有一個右上角的三角形,裏面有紅色,因此內插了一個紅色的量。然後是左下三角形,只有灰色。當然,右上三角形的紅色不會影響左下角的灰色。

問題是,插值發生在RGB空間中,但是您希望的結果必須放置在HS(Hue)將保持恆定的HSV或HSL空間中。

然而,這不僅僅是一個插值問題。你的方式也是這樣,這種顏色不會線性插入;大多數顯示器都應用了非線性函數,也稱爲「伽馬」(實際上伽瑪是輸入值的功率指數)。

您的OpenGL上下文可能處於顏色校正的顏色空間中或不在。你需要測試這個。然後,知道幀緩衝區駐留在哪個色彩空間中,則必須使用片段着色器將重心座標的每片段變換(使用頂點着色器評估)應用到每個片段值。

3

我不喜歡上投票的答案,因爲它是如此的字面只有真正專注於衝在簡單的答案,所以我想基於頂點顏色用一個簡單的替代進來:

#version 330 core 

smooth in vec4 color; 
smooth in vec2 uv; 

out vec4 colorResult; 

void main(){ 
    float uvX = 1.0 - uv.st.x; 
    float uvY = uv.st.y; 

    vec4 white = vec4(1, 1, 1, 1); 
    vec4 black = vec4(0, 0, 0, 1); 

    colorResult = mix(mix(color, white, uvX), black, uvY); 
} 

這很容易解釋和推理。 mix是一個線性插值,或者是glsl中的lerp。所以我沿着逆x軸在頂點顏色和白色之間進行混合,這使得我左上角的白色和右上角的純色。結果,我沿y軸混合黑色,使底部呈黑色。

希望這會有所幫助,我遇到了這個答案,發現除了硬烘烤的紅色,綠色或藍色調色板之外,沒有什麼幫助,adjustHue位根本就不是我想要的。

基本上得到這個工作,你希望將所有的頂點顏色設置爲你想要的顏色,並確保您的UV座標設置:

TL: UV(0, 0), COLOR(YOUR DESIRED COLOR) 
BL: UV(0, 1), COLOR(YOUR DESIRED COLOR) 
BR: UV(1, 1), COLOR(YOUR DESIRED COLOR) 
TR: UV(1, 0), COLOR(YOUR DESIRED COLOR)