Reputation: 85
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.
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
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
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