2017-05-08 6 views
0

J'essaie de mettre en œuvre quelque chose comme un outil de peinture et bloqué avec un problème de canal alpha de la brosse. Mon pinceau est une texture .PNG avec un arrière-plan transparent. Je dessine dans le tampon RGBA. Mon code:Peinture dans le tampon. Problème avec alpha chanel

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

Il fonctionne, mais si j'arrête mon pinceau, le canal alpha de la brosse sera d'accumuler dans la mémoire tampon pour remplacer la couleur de.

enter image description here

Je ne suis pas familier avec le mélange dans Opengl trop près et ont problème avec les paramètres de mélange. Est-ce que mon problème est dans le mélange ou autre chose?

Mise à jour:

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. J'ai essayé à la fois votre recomend mais les résultats sont simmilar et n'expliquent pas mon problème. Regardez:

1) glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); et deux texture .PNG prémultipliée - avec noir et blanc.

enter image description here

2) glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); et texture linéaire alpha.

enter image description here

+0

Le test de profondeur est-il désactivé? – dari

+0

Oui. Si je l'active, rien ne change. – OpenGLNoob

+0

L'image que vous avez affichée - c'est une image de quoi? Qu'est-ce que le code "Draw FBO", le code "Draw brush" et comment avez-vous configuré votre FBO? – ybungalobill

Répondre

1

Lorsque le mélange dans une texture avec un canal alpha linéaire, les équations de mélange correctes impliquent une division par les valeurs alpha, et de telles équations ne peuvent pas être exprimées dans les formules linéaires OpenGL (et GPU) fournissent glBlendFunc et glBlendFuncSeparate. Au lieu de cela, vous devez utiliser alpha pré-multiplié. En principe, vous faites cela en appelant

glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 

une fois, et veiller à ce que toutes vos entrées et sorties sont prémultipliée alpha. Cependant, les fichiers PNG standard sont en alpha pur (bien que les fichiers PNG non standard avec alpha pré-multiplié existent ... ce n'est probablement pas votre cas). Pour y faire face, vous pouvez soit Prémultiplier les PNGs lorsque vous les chargez ou utilisez ce qui suit dans drawBrush:

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 

qui va obtenir une sortie de shaders alpha droite et se fondre dans un prémultipliée alpha framebuffer. Par conséquent, lors du rendu de ce framebuffer à l'écran, n'oubliez pas d'utiliser le glBlendFunc pour l'alpha prémultiplié (le premier).

+0

Merci pour votre réponse! Je garderai à l'esprit comment cela influence le résultat du rendu dans le futur. J'ai essayé votre solution et d'autres combinaisons avec et sans prémultiplier (look update), mais il me semble que le problème est ailleurs. Mon framebuffer accumule non seulement la couleur mais aussi la valeur alpha dans la boucle de jeu et influence sur FBO. Quand j'arrête une brosse, elle commence à saigner comme de l'encre sur un papier. Maintenant, j'essaie de comprendre comment le résoudre, mais je ne peux pas. (( – OpenGLNoob

+0

@OpenGLNoob: vous vous rendez compte que vous n'avez posté aucun code lié à la souris, et donc nous ne pouvons pas vous aider avec cette partie? Exemple complet et vérifiable] (http://stackoverflow.com/help/mcve) – ybungalobill

+0

Oui, vous avez raison, mon erreur était que je ne contrôlais pas la mise à jour de mon FBO par le mouvement de la souris et que je plaçais le pipeline de peinture dans la boucle du jeu directement Le FBO accumulait des alpha à chaque image et c'était la raison de mon problème. – OpenGLNoob