How to draw an OpenGL alphamap with filled foreground and background? - opengl

I'm drawing text from a texture atlas containing an alphamap GL_ALPHA, GL_UNSIGNED_BYTE --- it's produced by stb_truetype, if that's any help. Right now I'm drawing with GL_BLEND enabled and the texture with all the default settings. I can set the foreground colour with glColor3f, the background is transparent, and everything works fine.
The problem is, on some platforms drawing transparent text is too slow. And I don't actually need it; the background is always a solid colour. I am, in fact, filling it with glRectf just before drawing the texture.
Experiments have shown that disabling GL_BLEND fixes all my performance issues, but of course that gives me solid blocks of colour instead of text. Looking at the documentation for glTexEnvi, it seems to me that it ought to be possible to draw the texture without blending, getting it to just apply the alpha value to fixed source and destination colours. But I can't figure out how, the documentation is rather opaque, and just trying stuff isn't helping.
(Maybe I need to have GL_BLEND enabled but tell it somehow to use my background colour rather than reading from the framebuffer?)
Can anyone enlighten me?
I am using old-fashioned fixed-pipeline pre-shader OpenGL, by the way, so I can't simply do all this in the shader fragment.

Related

How do I make my object transparent but still show the texture?

I'm trying to render a model in OpenGL. I'm on Day 4 of C++ and OpenGL (Yes, I have learned this quickly) and I'm at a bit of a stop with textures.
I'm having a bit of trouble making my texture alpha work. In this image, I have this character from Spiral Knights. As you can see on the top of his head, there's those white portions.
I've got Blending enabled and my blend function set to glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
What I'm assuming here, and this is why I ask this question, is that the texture transparency is working, but the triangles behind the texture are still showing.
How do I make those triangles invisible but still show my texture?
Thanks.
There are two important things to be done when using blending:
You must sort primitives back to front and render in that order (order independent transparency in depth buffer based renderers is still an ongoing research topic).
When using textures to control the alpha channel you must either write a shader that somehow gets the texture's alpha values passed down to the resulting fragment color, or – if you're using the fixed function pipeline – you have to use GL_MODULATE texture env mode, or GL_DECAL with the primitive color alpha value set to 0, or use GL_REPLACE.

How to override texture color in opengl?

I am working on engine (http://b2dengine.com/) to implement my game idea, which is already in progress. Now for quite a while I am stuck with this problem with text rendering.
I have texture atlas that contains all supported/needed characters in a single png image. Character mapping is defined by Font class.
Everything works fine, characters are rendered correctly and accurately. Thing is that I also need ability to change color of the text.
This sounds and I bet it is simple but I cant make it work.
I am using this gl blend function to get desired effect.
GL.instance.glBlendFunc(GL.instance.GL_SRC_ALPHA, GL.instance.GL_ONE_MINUS_SRC_ALPHA);
In most cases it works, well as long as the color is somewhat dark. But when its set to white, I can see artifacts. I can provider screenshot if needed.
Also for this to work, "text" in texture must be white.
I am using opengl 1.1 ( yes I know its old, but I am just not ready for shaders ).
So in short, my question is: how to render a texture and completely replace the color? Keeping only alpha channel.
E.g. if its black and 80% transparent in png, when I render I want it green at 80% transparency on screen.
I think this will work, though these are some anciently deprecated functions and I don't remember too much about them anymore.
With your texture unit active which has the text texture, try setting these options:
glTexEnv(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
glTexEnv(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnv(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR);
glTexEnv(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE);
I believe this will replace the RGB of your fragment with the incoming fragment color (glColor), and completely ignore the RGB channel of the texture. Having said this, it would be a lot better if you just uploaded an alpha channel texture to begin with.
Make sure to check for errors, and if it doesn't work, you can see if I've grabbed something incorrectly from here: http://www.opengl.org/sdk/docs/man/xhtml/glTexEnv.xml

OpenGl Rendering Transparent .png with Random White Pixels

I am working on a game with a friend and we are using openGl, glut, devIL, and c++ to render everything. Simply, Most of the .pngs we are using are rendering properly, but there are random pixels that are showing up as white.
These pixels fall into 2 categories. The first are pixels on the edge of the image. These are resulting from the anti-aliasing going on from photoshop's stroke feature (which i am trying to fix). The second is the more mysterious one. When the enemy is standing still, the texture looks fine, but as soon as it jumps a random white line appears on the top of it.
The line on top is of varying solidity (this shot is not the most solid)
It seems like a blending issue, but I am not as familiar with the way openGl handles the transparency (our code for transparency was learned from the other questions on stack overflow though I couldn't find anything on this issue, however). I am hoping something will fix both issues, but am more worried about the second.
Our current setup code:
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
Transparent areas of a bitmap also have a color. If it is 100% transparent, you usually can't see it. Photoshop usually fills white in these areas.
If you are using minifying or magnifying flags that are not GL_NEAREST, then you will have interpolation. If you interpolate in between two pixels, where one is blue and opaque, and the other is white and transparent, then you will get something that is 50% transparent and light-blue. You may also get the same problem with mimaps, as interpolation is used. If you use mipmaps, one solution is to generate them yourself. That way, you can ignore the transparent areas when doing the interpolations. See some good explanations here: http://answers.unity3d.com/questions/10302/messy-alpha-problem-white-around-edges.html
Why are you using png files? You save some disk space, but need to include complex libraries like devil. You don't save any space in the delivery of an application, as most tools that creates delivery packages have very efficient compression. And you don't save any memory on the GPU, which may be the most critical.
This looks like an artifact in your source PNG. Are you sure there are no such light opaque pixels there?
White line appearing on top could be a UV interpolation error from neighbor texture in your texture atlas (or padding if you pad your NPOT textures to POT with white opaque pixels). Thats why usually you need to pad textures with at least one edge pixel in every direction. That won't help with mipmaps though, as Lars said - you might need to use custom mipmap generation or drop it altogether.

OpenGL FBO - White pixels appear transparent

I'm making a 2D game using OpenGL. I recently tried implementing Framebuffer-objects, and I am having some problems regarding blending.
I'm creating an FBO (using GL_RGBA as format).
When I render to the FBO, I first clear it to fully transparent black, and disable GL_BLEND. I then draw my textures and then I enable GL_BLEND again.
When I'm drawing the FBO-texture, I use GL_SRC_ALPHA and GL_ONE_MINUS_SRC_ALPHA as source and destination pixels respectively, as the blending-function. I am rendering it as a textured quad.
This does not work properly, as white pixels appear transparent. I have tried experimenting with different blend-function values, but all that I have tried have had issues. I do not fully understand how blending works, so it's hard for me to wrap my head around this. Maybe I'm missing something obvious here?
Here's an image of how it looks right now. There is supposed to be a glow around the button when it is being highlighted, but instead the pixels around it appear transparent: http://i.snag.gy/RnV4s.jpg
You can also see two boxes of text in the image. The top one is drawn normally, without an FBO. The textures are also rendered normally without an FBO, so I know that the problem lies within my framebuffer-code somewhere.
I have pasted my "RenderTarget" class to pastebin (I'm used to calling it a rendertarget instead of FBO): http://pastebin.com/dBXgjrUX
This is how I use it:
RT->Begin();
// draw stuff
RT->End();
RT->Draw();
Can someone help me? Let me know if you need any more info about my issue.
Edit:
Here are the properties of OpenGL that I set on startup:
// Initialize shaders
shaderManager.InitializeStockShaders();
// Set some OpenGL properties
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glShadeModel(GL_SMOOTH);
glAlphaFunc(GL_GREATER, 0.0f);
// Enables/disables
glEnable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glDisable(GL_DITHER);
glDisable(GL_LIGHTING);
I'ts a bit difficult to tell what your problem is exactly, because you didn't provide source code. Alas, I see several potential troublemakers:
First you told that you want to draw a glow around the button. I presume, that all the buttons are drawn into the FBO, merging them into a UI overlay. Glow sounds to me, like you want to blend something, so you probably also want to have blending enabled, drawing to the FBO.
Next be aware of depth buffer issues. Blending and Depth Buffering have peculiar interactions. In your case I suggest disabling depth testing and depth writes to the FBO (or not using a depth buffer attachment to the FBO at all). Draw the glowing button last, so that it won't block the other buttons from being drawn. Also you must make sure, that your glow comes out with a nonzero alpha value, otherwise it will blend transparent. This is something you control in your shaders, or texture environment (depending on what you use).
Update 1:
Your FBO class doesn't propperly ensure, that textures attached to a bound framebuffer must not be bound themself. It's easy to fix though, by moving attachment code into bind, where the textures are also unbound apropriately. See my edited pastebin http://pastebin.com/1uVT7VkR (I probably missed a few things).

Alpha blending with multiple textures leaves colored border

Following problem: I have two textures and I want to combine these two into a new texture. Thus, one texture is used as background, the other will be overlaid. The overlay texture is getting initialized with glClearColor(1.0, 1.0, 1.0, 0.0). Objects are draw onto the texture, these objects do have alpha values.
Now blending between the two textures leaves a white border around the objects. The border comes from the fact that the background color in the second texture is white, isn't it?
How can I use alpha blending where I do not have to think about the background color of the overlaying texture?
I solved the problem myself, but thanks a lot to all of you guys!
The problem was following: to combine both textures I used glblend(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) which does not work due to the fact that OpenGL uses pre-multiplied alpha values. Blending with glblend(GL_ONE, GL_ONE_MINUS_SRC_ALPHA), works as the source term now will be:
1*src_alpha*src_color!
How can i use alpha blending where i do not have to think about the background color of the overlaying texture?
You can't; your blend function incorporates the background color into it, because it may not actually be the "background". You render multiple objects to the texture, so the "background" color may in fact be a previously rendered object.
Your best bet is to minimize the impact. There's no particular need for the background color to be white. Just make it black. This won't make the artifacts go away; it will hopefully just make it less noticeable.
The simple fact is that blending in graphics cards simply isn't designed to be able to do the kinds of compositing you're doing. It works best when what you're blending with is opaque. Even if there are layers of transparency between the opaque surface and what you're rendering, it still works.
But if the background is actually transparent, with no fully opaque color, the math simply stops working. You will get artifacts; the question is how noticeable they will be.
If you have access to more advanced hardware, you could use some shader-based programmatic blending techniques. But these will have a performance impact.
Although I think you probably get better results with a black background, as Nicol Bolas pointed out. But you should double check your blending functions, because as you point out, it SHOULD not matter...
1.0 * 0.0 + 0.734 * 1.0 = 0.734
What I don't really get is why your base texture is fully transparent? Is that intended? Unless you blend the textures and then use them somewhere else initializing to Alpha = 1.0 is a batter idea.
Make sure you disable depth writing before you draw the transparent texture (so one transparent texture can't "block" another, preventing part of it from being drawn). To do so just call glDepthMask(false). Once you are done drawing transparent objects, call glDepthMask(true) to set depth writing back to normal.