I've been working in opengl for a while relatively smoothly, but recently I've noticed that when I render a primitive with a transparent texture onto my fbo texture (custom frame buffer) it makes the fbo texture transparent at the pixels the primitive's texture is transparent. The problem is that there are things behind this primitive (with solid color) already rendered before the transparent one. So the fbo texture should not be transparent at those pixels - blending a solid & transparent color should result in a solid color, shouldn't it?
So basically, opengl is adding transparency to my fbo-texture just because the last primitive drawn has transparent pixels even though there are solid colors behind it already drawn into the fbo texture. Shouldn't opengl blend the transparent texture with the fbo's existing pixels, and result in a solid color if the fbo texture is already filled with solid colors before rendering the transparent primitive?
What happens when I render my fbo texture to the default frame buffer, is that the clear color bleeds through parts of it - where the last drawn texture is transparent. But when I render the same scene straight to the default opengl frame buffer, the scene looks fine and the clear color is not bleeding into the transparent texture.
What's even more interesting is that the glClearColor - color is only visible where the primitive's texture's alpha has a gradient - the clear color has no influence on where the texture alpha is 1.0 or 0.0... is this a bug? It seems to affect the primitive's texture the most at pixels with 0.5 alpha. Then going further above or below decreases the glClearColor influence.
I know it's a bit of a complex question/situation, I honestly tried my best to explain
I'm using:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
to draw both the partly transparent primitive into the fbo-texture, and then the fbo texture to the default framebuffer
This is what the fbo-texture drawn into the default opengl fbo looks like:
glClearColor is set to red.
blending a solid & transparent color should result in a solid color, shouldn't it?
Only if your blend mode tells it to. And it doesn't:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
This applies the same blending operation to all four components of the colors. This causes the final alpha to be the result of multiplying the source alpha by itself and adding that to the destination alpha times 1-src alpha.
Now, you could use separate blend functions for the color and the alpha:
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
The last two parameters specify the blending for just the alpha, while the first two specify the blending for the RGB colors. So this preserves the alpha. Separate blend functionality is available on GL 3.x and above, but is also available as an extension on older hardware.
But it seems to me that you probably don't want to change the alpha at all. So simply mask alpha writes when rendering to the texture:
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
Don't forget to undo the alpha mask when you want to write to it again.
Related
This is how I render my brush in the fragment shader :
gl_FragColor.rgb = Color.rgb;
gl_FragColor.a = Texture.a * Color.a;
With this Blending function on a (0, 0, 0, 0) texture :
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
This is what I see when I draw my texture ADDED to my white background with glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) :
But this is what I get in my texture :
Can someone help me to understand why I got this grayed stroke in my texture ? Because I need to take a screenshot of this texture, and I want to have the same rendering but without white background.
[1st picture] When I draw my "view" I have a white background
[2nd picture] But I store my stroke in a texture who have a transparent background
You're doing two blending operations, one in your shader, one using the glBlendFunc call. When rendered directly to the screen it doesn't apply the glBlendFunc a second time, however, when rendering to a texture it gets applied when rendering to the texture, and then again when rendering the texture to the screen.
You have two options, 1) don't do blending your shader, 2) use a different blend function (I find glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); to work well). I find option 2 to work the best for me, handling OpenGL blend functions is notoriously annoying.
I am drawing a map texture and, on top of it, a colorbar texture. Both have alpha channel and I am using blending, set as
// Turn on blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
However, the following happens:
The texture on top (colorbar) with alpha channel imposes its black pixels, which I don't want to happen. The map texture should appear behind where the colorbar alpha = 0.
Is this related to the blending definitions? How should I change it?
Assuming the texture has an alpha channel and it's transparent in the right places, I suspect the issue is with the rendering order and depth testing.
Lets say you render the scale texture first. It blends correctly with a black background. Then you render the orange texture behind it, but the pixels from the scale texture have a higher depth value and cause the orange texture there to be discarded.
So, make sure you render all your transparent stuff in back to front order, or farthest to nearest.
Without getting into order independent transparency, a common approach to alpha transparency is as follows:
Enable the depth buffer
Render all your opaque geometry
Disable depth writes (glDepthMask)
Enable alpha blending (as in the OP's code)
Render your transparent geometry in farthest to nearest order
For particles you can sometimes get away without sorting and it'll still look OK. Another approach is using the alpha test or using alpha to coverage with a multisample framebuffer.
EDIT + BETTER SOLUTION:
In case anyone happens to run into the problem I was running into, there are two solutions. One is the solution accepted, but that only applies if you are doing things how I was. Let me explain what I was doing:
1.) Render star background to screen
2.) Render ships, then particles to the FBO
3.) Render FBO to screen
This problem, and therefor the solution to this problem, occurred in the first place because I was blending the FBO with the star background.
The real solution, which is supposedly also slightly faster, is to simply render the star background to the FBO, then render the FBO to screen with blending disabled. Using this method, I do not need to mess with glBlendFuncSeparate...
1.) Render stars, then ships, then particles to FBO
2.) Render FBO to screen with blending disabled
----------ORIGINAL QUESTION:----------
From what I understand of the issue, blending is being ignored somehow. The particle texture with alpha transparency completely overwrites below pixels.
I am creating a top-down game. The camera is slightly angled so that there is some feeling of depth. I am rendering my ships, then rending the particles above them...
After beginning the OpenGL context
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glCullFace(GL_BACK);
In the render loop, I do this:
glBindFramebuffer(GL_FRAMEBUFFER,ook->fbo);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
entitymgr_render(ook); //Render entities. Always 1.0 alpha textures.
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
//glBlendFunc(GL_SRC_ALPHA,GL_ONE); //This would enable additive blending for non-premult
particlemgr_render(ook); //Render particles. Likely always <1.0 alpha textures
//glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glBindFramebuffer(GL_FRAMEBUFFER,0);
If I run with the above code, I get results like this...
Particle tex:
Screenshot from OGL Profiler (Mac tool):
Screenshot of the FBO without any particle rendered:
Screenshot of the FBO with some particles rendered on top:
As you can see, the particle, despite having alpha transparency, doesn't blend with the ship rendered below. Instead, it just completely overwrites the pixels.
Final notes, setting pixel transparency in the shader blends correctly - the ship appears below. And here is my shader:
#version 150
uniform sampler2D s_tex1;
uniform float v4_color;
in vec4 vertex;
in vec3 normal;
in vec2 texcoord;
out vec4 frag_color;
void main()
{
frag_color=texture(s_tex1,texcoord)*v4_color;
if(frag_color.a==0.0) discard;
}
Let me know if there is anything I can provide.
Looks to me like it is rendering the alpha channel as well into the frame buffer, so when you write the particles, the src alpha channel is getting mixed with the destination alpha channel, which is not what you want here.
This is exactly why the glblendfuncseparate() function was created. Try this...
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
So, the alpha channel of your particles will be used to determine the colours of the final pixels, but the alpha channels of the source and destination will be added together.
My guess is that the FBO's rgb channels are being rendered correctly, but because it also has an alpha channel, and it is being drawn with blending enabled, the end result has incorrect transparency where the particle overlaps the spaceship.
Either use glBlendFuncSeparate (described here) to use different blend factors for the alpha channel when you're drawing the particles:
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
Or turn off blending altogether when you draw your FBO onto the screen.
In order to obtain texture transparency, other than:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
you should assure also that:
when creating the particle tex with glTexImage2D, use as format GL_RGBA (or GL_LUMINANCE_ALPHA if you are using gray shaded textures)
when drawing the particle texture, after the glBindTexture command, call
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
Instead of GL_BLEND, you could use the correct texture functions as described in
the glTexEnv reference: http://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml
I am wanting to set up a blend (without using shaders preferably) to produce the following.
I have a black/white textured quad, and a quad of a solid color(for example red). I'd like the blend to show the color (red) where all the white pixels are and black otherwise.
Is this possible and what does the code look like?
This typically not done by blending, but you could try glBlendFunc(GL_SRC_COLOR, GL_ZERO); drawing the red quad on top of the text.
However this will only work if there's no other content in the framebuffer.
I'm new at OpenGL and I can't find out how to do this:
I want to render a letter and be able to change it's color, so I have a texture with the letter on a transparent background. I managed to render it using this code:
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
But that renders the letter in black, as it's on the texture. How can I render it with the color setted with glColor4f?
Have you been messing with glTexEnv? If you did, call :
glTexEnv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)
and that will restore the default behaviour, which is to multiply the texture color with the vertex color.
There are a couple of other possibilities. One would be to put the shape of the letter into the stencil buffer, and then draw a quad in your preferred color. Another would be to draw your text in light grey, and use lighting to have it displayed in the color you want.