PoisonedPorkchop
PoisonedPorkchop

Reputation: 85

Rendering Overwriting Transparency When Rendering to Texture When Using Transparency

When rendering to a texture (secondary framebuffer) in OpenGL, anything transparent overwrites the transparency of what is below, rather than adding transparency as transparency should. This means if I render a transparent object on top of an existing opaque object, the result is a texture that is transparent, even though it should be opaque.

https://i.sstatic.net/Y0YiT.png

In this picture, the space is rendered as a background normally, the framebuffer is then changed and opaque blue is then rendered, then, the green/red are rendered. The texture that the framebuffer was rendering to is used to render onto the original framebuffer(the window), and the result is as seen.

Some code:

Framebuffer/Texture Creation:

        int texture = glGenTextures();
        framebufferID = glGenFramebuffers();
        glBindFramebuffer(GL_FRAMEBUFFER,framebufferID);
        glBindTexture(GL_TEXTURE_2D, texture);
        int width,height;
        width = (int)(getMaster().getWindow().getWidth()*(xscale/(16f*getMaster().getGuiCamera().getWidth()))*1.2f);
        height = (int)(getMaster().getWindow().getHeight()*(yscale/9f)*1.15f);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture,0);
        int depth = glGenTextures();
        glBindTexture(GL_TEXTURE_2D, depth);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 0);
        this.texture = new Texture(texture,width,height,true);
        glDrawBuffer(GL_FRONT_AND_BACK);

The depth buffer here was something I tried to get it to work, but it had no effect on the output texture though.

Render Code:

        getMaster().returnToViewportAfterFunction(new Vector2i(texture.getWidth(),texture.getHeight()),
            () -> getMaster().returnToFramebufferAfterFunction(framebufferID, () -> {

                shapeShader.bind();
                glEnable(GL_BLEND);
                glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
                model.bind();
                shapeShader.setUniform("color", 0f, 0f, 1f, 1f); //Blue
                shapeShader.setUniform("projection", this.camera.getProjectionForGuiWindow(vec2zero, xscale, yscale));
                glDrawElements(GL_TRIANGLES, model.getVerticeCount(), GL_UNSIGNED_INT, 0);

                shapeShader.setUniform("color", 0f, 1f, 0f, 0.5f); //Green
                shapeShader.setUniform("projection", this.camera.getProjectionForGuiWindow(vec2zero, xscale/2f, yscale/2f));
                glDrawElements(GL_TRIANGLES, model.getVerticeCount(), GL_UNSIGNED_INT, 0);

                shapeShader.setUniform("color", 1f, 0f, 0f, .2f); //Red
                shapeShader.setUniform("projection", this.camera.getProjectionForGuiWindow(vec2zero, xscale/4f, yscale/2f));
                glDrawElements(GL_TRIANGLES, model.getVerticeCount(), GL_UNSIGNED_INT, 0);

                glDisable(GL_BLEND);

                model.unbind();
            })
        );
        //Renders the texture we just made
        shader.bind();
        model.bind();
        textureCoords.bind(texture);

        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        shader.setUniform("color", 1f, 1f, 1f, 1f);
        shader.setUniform("projection", camera.getProjectionForGuiWindow(getPosition(), xscale, yscale));
        glDrawElements(GL_TRIANGLES, model.getVerticeCount(), GL_UNSIGNED_INT, 0);
        glDisable(GL_BLEND);

        model.unbind();

Rendering over opaque objects in framebuffer 0 with a transparent object does not cause the resulting pixels to be transparent, else they would appear as a blend of the glClearColor and the opaque object, so why does this happen in the framebuffer in which I am using to render to a texture? Shouldn't it be consistent? I feel that maybe I'm missing some attachment to my framebuffer but I can't be sure what. I saw a solution that said to use glColorMask(true,true,true,false), the last false meaning no alpha writes, which appears at first glance to work, but why should I disable transparency when transparency is what I'm going for? It also appears to cause many issues if left on. Can anyone lend some insight? Thanks in advance!

EDIT: the glColorMask was not the solution, after further analysis.

Upvotes: 1

Views: 781

Answers (2)

PoisonedPorkchop
PoisonedPorkchop

Reputation: 85

For anyone wondering, best solution to my issue was to use glBlendFuncSeparate(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA,GL_ONE_MINUS_DST_ALPHA,GL_ONE) instead of glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

Upvotes: 0

datenwolf
datenwolf

Reputation: 162214

You have to use a separable blending function which treats RGB and Alpha values separately: glBlendFuncSeparate. For the RGB values you keep using GL_SRC_ALPHA, GL_SRC_ONE_MINUS_ALPHA. For the Alpha values use something like GL_ONE, GL_ONE so that things simply add up.

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);

Upvotes: 1

Related Questions