I am generating a bitmap for a text display with OpenGL using Cairo/Pango. I generate the bitmap as RGBA with a transparent background and with the text in either black or white. (Let's assume black.)
If I load this bitmap as an OpenGL texture and display it, it appears as black text or white text, as expected.
I'd like to be able to color the text using only the original texture, but with OpenGL taking care of the coloring.
Preferably, I'd like to use glColor to set the color, but I'm willing to use glBlendColor or GL_TEXTURE_ENV_COLOR.
However, I can't get any of those options to work.
I've try what seem like innumerable combinations of
- white text or black text
- enabling blending or using GL_TEXTURE_ENV_MODE's GL_BLEND
- trying GL_MODULATE, GL_REPLACE, and GL_COMBINE
- trying various differnt glBlendFunc combinations
I've been searching online and reading the spec for a few hours and I'm really at the end of my rope.
Can anyone point me to the right place to get the answer to this?
The simplest way to go is to have your text bitmap with white text and transparent background.
Then, to color it, you have to make sure that TEXTURE_ENV_MODE is set to MODULATE :
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
With this, the draw color will be glColor * textureColor == glColor (as textureColor is white)
Then you have to enable blending to handle your transparent background :
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
or, if your bitmaps are in premultiplied alpha form :
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
Instead of supplying a full RGBA set, let the text just determinine the non-/transparency, i.e. just supply an alpha channel. Then use the normal glColor to set the text color.
It sounds like you can create the bitmap as you see fit. If that's the case, instead of black on white, I'd draw the text into the alpha channel. Then to color the text, you draw a rectangle (or whatever) of the color you want. Then draw your texture over it. Where the texture is opaque, you'll get the texture color. Where the texture is transparent, the background color will show through.
To do that, you will have to set up glBlendFunc. The usual should be fine:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
You also have to turn on blending for texturing:
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
Related
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.
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 loading a PNG using:
theImage = [NSBitmapImageRep imageRepWithContentsOfFile:imagePath];
from which I can successfully create a gl texture and render correctly without any transparency. However, when I switch blending on using:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
The texture renders with the correct transparent background, but the image colours are incorrect.
I have tried several options in the blend function, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_DST_ALPHA, etc.
I was taught maybe I need to reorder the bits in the image data, maybe the channels have been mixed up, but I would not expect it to render correctly when blending is off in that case.
Alternatively, I could use libPNG I guess, but I would like to try using a NSBitmapImageRep if it is possible.
How about supplying a screenshot?
Anyway, your blending function is wrong either way for simple transparency channel blending. It should be either
normal alpha: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
or
premultiplied alpha: glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)
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.
I'm trying to draw grayscale image in color as texture in OpenGL using two colors. Black goes to color1 and white goes to color2. Texture is loaded using GL_RGBA.
I have tried two solutions:
1)
Load image as texture
Draw image on screen
Enable blending
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); and draw rectangle with color1
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE); and draw rectangle with color2
But... When I apply first color, there is no black color on screen and when second color is applied it is combined with first color too.
2)
Save image as texture but don't use grayscale image, use white image with alpha channel that is same as grayscale
Draw rectangle with color1
Draw image
But... When image is drawn it doesn't use color1 where image is transparent, instead it uses current color set with glColor.
Any help will come in handy :)
In general, when dealing with OpenGL texturing pipeline, I recommend writing down the end result you want. here, you want your grayscale color to be used as an interpolant between your 2 colors.
out_color = mix(color1, color2, texValue)
The math for this actually is something like:
out_color = color1 + (color2 - color1) * texValue
So... is there a texture environment value that helps do that ? Yes, and it's also called GL_BLEND (not to be confused with the blending to frame buffer that glEnable(GL_BLEND) enables).
So... something like
// pass color1 as the incoming color to the texture unit
glColor4fv(color1);
GLfloat color2[4] = { ... };
// ask for the texture to be blended/mixed/lerped with incoming color
glTexEnvi(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_BLEND);
// specify the color2 as per the TexEnv documentation
glTexEnvfv(GL_TEXTURE_2D, GL_TEXTURE_ENV_COLOR, color2)
There is no need to draw multiple times or anything more complicated than this, like you tried to do. The texturing pipeline has plenty of ways to get controlled. Learn them to your advantage!
Your #2 idea would work, but it seems like you didn't set blending correctly.
It should be:
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );