2017-05-08 96 views
0

我嘗試實現像繪畫工具一樣的東西,並與刷子的問題阿爾法通道卡住。我的畫筆是具有透明背景的.PNG紋理。我繪製在RGBA緩衝區中。我的代碼:在緩衝區中繪畫。問題與阿爾法香奈爾

initFBO(...) 
... 

glEnable(GL_BLEND); 
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
glClearColor(1.0f, 0.0f, 0.0f, 1.0f); 

glBindFramebuffer(GL_FRAMEBUFFER, FBO); 
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 

drawBrush(...) 

glBindFramebuffer(GL_FRAMEBUFFER, 0); 

drawFBO(...) 

它的工作原理,但如果我停止我的刷,刷從alpha通道將在緩衝區從更換顏色積累。

enter image description here

我不熟悉,在OpenGL太近混合,並有問題與混合參數。我在混合或其他方面存在問題嗎?

更新:

initFBO(GLuint &framebuff, GLuint &text) 
{ 
    glGenFramebuffers(1, &framebuff); 
    glBindFramebuffer(GL_FRAMEBUFFER, framebuff); 
    glGenTextures(1, &text); 

    glBindTexture(GL_TEXTURE_2D, text); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screenWidth, screenHeight, 0, GL_RGB, GL_FLOAT, NULL); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, text, 0); 
    glBindFramebuffer(GL_FRAMEBUFFER, 0); 

drawBrush(glm::vec2 mousePosition, GLuint texture, Shader shader) 
{ 
    glm::mat4 model; 
    model = glm::translate(model, glm::vec3(mousePosition, 1.0)); 

    GLfloat brushVertices[] = 
    { 
     -0.1f, 0.1f, 0.0f, 0.0f, 1.0f, 
     -0.1f,-0.1f, 0.0f, 0.0f, 0.0f, 
     0.1f, 0.1f, 0.0f, 1.0f, 1.0f, 
     0.1f,-0.1f, 0.0f, 1.0f, 0.0f 
    }; 

    glGenVertexArrays(1, &brushVAO); 
    glGenBuffers(1, &brushVBO); 
    glBindVertexArray(brushVAO); 
    glBindBuffer(GL_ARRAY_BUFFER, brushVBO); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(brushVertices), &brushVertices, GL_STATIC_DRAW); 
    glEnableVertexAttribArray(0); 
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0); 
    glEnableVertexAttribArray(1); 
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); 
    glBindVertexArray(0); 

    shader.set(); 
    glUniform1i(glGetUniformLocation(shader.Program, "texture"), 0); 
    glUniformMatrix4fv(glGetUniformLocation(shader.Program, "model"), 1, GL_FALSE, glm::value_ptr(model)); 
    glActiveTexture(GL_TEXTURE0); 
    glBindTexture(GL_TEXTURE_2D, texture); 

    glBindVertexArray(brushVAO); 
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 
    glBindVertexArray(0); 
} 

drawFBO(GLuint texture, Shader shader) 
{ 
    GLfloat screenquadVertices[] = 
    { 
    -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 
    -1.0f, -1.0f,0.0f, 0.0f, 0.0f, 
    1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 
    1.0f, -1.0f, 0.0f, 1.0f, 0.0f 
    }; 

    glGenVertexArrays(1, &screenquadVAO); 
    glGenBuffers(1, &screenquadVBO); 
    glBindVertexArray(screenquadVAO); 
    glBindBuffer(GL_ARRAY_BUFFER, screenquadVBO); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(screenquadVertices), &screenquadVertices, GL_STATIC_DRAW); 
    glEnableVertexAttribArray(0); 
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0); 
    glEnableVertexAttribArray(1); 
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); 
    glBindVertexArray(0); 

    shader.set(); 
    glUniform1i(glGetUniformLocation(shader.Program, "texture"), 0); 
    glActiveTexture(GL_TEXTURE0); 
    glBindTexture(GL_TEXTURE_2D, texture); 

    glBindVertexArray(screenquadVAO); 
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 
    glBindVertexArray(0); 
} 

UPDATE2

確定。我嘗試了你的推薦,但結果是相似的,並沒有解釋我的問題。看看:

1)glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);和兩個預乘.PNG紋理 - 黑色和白色。

enter image description here

2)glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);和直-α質地。

enter image description here

+0

是否禁用了深度測試? – dari

+0

是的。如果我使它沒有改變。 – OpenGLNoob

+0

您發佈的圖片 - 這是什麼圖片?什麼是「畫FBO」代碼,「畫筆」代碼,以及您是如何設置FBO的? – ybungalobill

回答

1

當共混到具有直alpha通道的紋理,正確的混合式涉及除以α值,並且這樣的公式可以不是線性的公式的OpenGL(和GPU)的與提供內被表達glBlendFuncglBlendFuncSeparate

而應該使用預乘alpha。原則上你通過呼叫

glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 

一次,並確保所有的輸入和輸出都預乘alpha。

但是,標準PNG是直接alpha(雖然非標PNG與預乘alpha存在...可能不是你的情況)。爲了對付它,你既可以預乘當你加載它們,或使用PNG圖像下面的drawBrush時:

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 

這將讓直阿爾法着色器輸出,並將其融入一個預乘alpha幀緩存。因此,將該幀緩衝區呈現在屏幕上時,請記住使用glBlendFunc作爲預乘alpha(第一個)。

+0

謝謝你的回答!我將牢記它將來如何影響渲染結果。我嘗試了你的解決方案和其他組合,並且不帶預乘(看起來更新),但在我看來問題在於其他地方。我的framebuffer不僅在遊戲循環中累積顏色,而且累積alpha值,並影響FBO。當我停止刷子時,它會像紙張上的墨水一樣開始流血。 (( – OpenGLNoob

+0

@OpenGLNoob:你是否意識到你沒有發佈鼠標相關的代碼,因此我們無法提供幫助?請學會發佈一個[Minimal ,完整和可驗證的例子](http://stackoverflow.com/help/mcve) – ybungalobill

+0

是的,你是對的我的錯誤是我沒有控制通過鼠標移動來更新我的FBO,並將繪製管道直接放入遊戲循環。FBO每幀都在積累alpha,這是我的問題的原因。謝謝! – OpenGLNoob