2017-05-08 4 views
0

Ich versuche, etwas wie ein Malwerkzeug zu implementieren und stecken mit einem Problem Alpha-Chanel der Bürste. Mein Pinsel ist eine PNG-Textur mit transparentem Hintergrund. Ich zeichne den RGBA-Puffer ein. Mein Code:Anstrich in Puffer. Problem mit Alpha-Kanal

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(...) 

Es funktioniert, aber wenn ich meine Bürste stoppen, Alpha-Kanal von der Bürste wird in dem Puffer zu akkumulieren Farbe ersetzen aus.

enter image description here

Ich bin nicht vertraut mit zu nahe in Opengl Mischen und haben Problem mit Mischparameter. Ist mein Problem in der Mischung oder etwas anderes?

Update:

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

Ok. Ich habe beide ausprobiert, aber die Ergebnisse sind ähnlich und erklären mein Problem nicht. Sehen Sie sich an:

1) glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); und zwei pre-multipliziert .PNG Textur - mit einem schwarzen und mit weißen.

enter image description here

2) glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); und straight-alpha Textur.

enter image description here

+0

Ist der Tiefentest deaktiviert? – dari

+0

Ja. Wenn ich es aktiviere, ändert sich nichts. – OpenGLNoob

+0

Das Bild, das du gepostet hast - es ist ein Bild von was? Was ist der 'Draw FBO' Code, 'Draw Brush' Code und wie hast du deinen FBO eingerichtet? – ybungalobill

Antwort

1

Wenn mit einem geraden Alphakanal in eine Textur Mischen, die richtigen Mischungsgleichungen beinhalten eine Division durch die Alpha-Werte, und solche Gleichungen können nicht innerhalb der linearen Formeln, die OpenGL (und GPUs) liefern mit ausdrücken die glBlendFunc und glBlendFuncSeparate.

Stattdessen sollten Sie vormultipliziertes Alpha verwenden. Grundsätzlich sind Sie, dass durch

glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 

einmal anrufen, und dafür zu sorgen, dass alle Ein- und Ausgänge sind premultiplied alpha.

jedoch Standard-PNGs sind in geraden alpha (obwohl Nicht-Standard-PNGs mit premultiplied alpha existieren ... wahrscheinlich nicht Ihr Fall). Um mit ihr umgehen können Sie entweder premultiply die PNGs, wenn man sie laden, oder verwenden Sie folgendes, wenn in drawBrush:

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 

, dass eine gerade Alpha-Shader-Ausgabe erhalten wird und mischen Sie sie in einen integrierten Alphaframebuffer. Wenn Sie diesen Framebuffer auf dem Bildschirm wiedergeben, denken Sie daran, das glBlendFunc für das multiplizierte Alpha (das erste) zu verwenden.

+0

Vielen Dank für Ihre Antwort! Ich werde im Auge behalten, wie es sich auf das Renderergebnis in der Zukunft auswirken wird. Ich habe versucht, Ihre Lösung und andere Kombinationen mit und ohne Premultipling (siehe Update), aber scheint mir Problem liegt an anderer Stelle. Mein Framebuffer akkumuliert nicht nur Farbe sondern auch Alpha-Wert in Game-Loop und beeinflusst FBO. Wenn ich einen Pinsel stoppe, fängt es an zu bluten wie Tinte auf einem Papier. Jetzt versuche ich herauszufinden, wie ich es lösen kann, aber ich kann nicht. ( – OpenGLNoob

+0

@OpenGLNoob: Ist dir klar, dass du keinen mausbezogenen Code gepostet hast, und deshalb können wir nicht mit diesem Teil helfen? Bitte lerne ein [Minimal , Vollständiges und überprüfbares Beispiel] (http://stackoverflow.com/help/mcve) – ybungalobill

+0

Ja, Sie haben Recht Mein Fehler war, dass ich meine FBO per Mausbewegung nicht änderte und die Malpipeline direkt in die Spielschleife plazierte FBO sammelte Alpha jeden Frame und es war der Grund meines Problems. Danke! – OpenGLNoob