How to set up the correct blend function? - opengl

I would like to achieve the effect like the image shown:
When the star pass through a mask, part of the star which under the mask is not shown.
I tried to use blend function, but I don't know how to set up the correct blend function.
I followed this example ( https://gist.github.com/mattdesl/6076846 ), but still can't figure out how to achieve the result I want.
Can anyone teach me how to find the blend function to achieve this effect ??

You can't do that only with the blending function.
One possible solution is to draw only the part of the star that is visible. You just have to draw a smaller quad.
Another solution is to multiply the star texture alpha by the alpha of the gray texture in the fragment shader (so you need to bind both textured when drawing the star). But that only works if the gray part of the screen is a whole texture and not made of several tiles. I would choose the first solution.
Third solution, you draw the background again on top of the star to hide it.
In first two cases, you only need the usual alpha blending function. To draw the background you can just disable the blending.

Related

Opengl, blend only when destination pixels' alpha value is positive

I'm searching for a function/way to make blending work only when destination pixels' (i.e. the back buffer) alpha value is greater than 0.
What i'm looking for is something like the glAlphaFunc which tests the incoming fragments, but in my case i want to test the fragments already found in the back buffer.
Any ideas?
Thank you in advance
ps. I cannot do a pixel-by-pixel test in the drawing function because this is set as a callback function to the user.
Wait, your answer is somewhat confusing, but i think what you're looking for is something like this : opengl - blending with previous contents of framebuffer
Sorry for this, but i think it's better answering instead of commenting.
So, let me explain better giving an example.
Let's say we have to draw something (whatever the user wants, like a table) and after that (before swapping the buffers of course) we must draw over it the "saved" textures using blending.
Let's say we have to draw two transparent boxes. If those boxes are to be saved in a different texture, this can be done by:
Clear the screen with (0, 0, 0, 0)
set blend function (GL_ONE, GL_ZERO)
draw the box
save it to texture.
Now, whenever the user wants to redraw them all, he simply draws the main theme (the table) and over it draws the textures using blend function (GL_SOURCE_ALPHA, GL_ONE_MINUS_SOURCE_ALPHA).
This works fine. But if the user wants to save both boxes in one texture and the boxes overlap, how can we save the blending of those two boxes without blend them with the "cleared" background?
Summarizing, the final image of the whole painting should be a table with two boxes (let's say a yellow and a green box) over it, blended with function (GL_SOURCE_ALPHA, GL_ONE_MINUS_SOURCE_ALPHA).

How can I blend two colours to a mix of them in OpenGL?

I'm rendering both a blue and a red line (in the context of an anaglyph). When the red line and blue line overlap I want a purple color to be rendered instead of the line in front.
I am using OpenGL. Some of the code I have tried so far is this:
glBlendFunc(GL_ONE, GL_DST_ALPHA);
This causes the overlap to render white, and the line appears as follows:
I thought maybe using an RGB scale factor on top of this blend would be the right thing to do.
So I tried using the glBlendFuncSeparate which takes parameters:
Source Factor RGB
Destination Factor RGB
Source Factor Alpha
Destination Factor Alpha
I could not find parameters which made this work for me.
I also attempted using glBlendEquation with an additive equation, but didn't notice any success in that method.
How do I produce a function which successfully blends the two lines into a purple color?
Edit:
I've noticed that glBlendFunc(GL_ONE, GL_DST_ALPHA) does perform some blending to produce intermediate colors (the actual lines are just nonsensical here, it was just to display some blending).
I'm rendering both a blue and a red line (in the context of an anaglyph)
Not the answer you expect, but the answer you need: The usual approach to render anaglyph images in OpenGL is not to use blending. Blending is hard enough to get right, you don't want to mess things up further with the anaglyph part.
There are two commonly used methods:
Rendering each view into a FBO attached texture and combining them in a postprocessing step.
using glColorMask to select the active color channels for each rendering step.
I think for now you're good with the color mask method: Do it as following:
display:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glViewport(…)
# prepare left view
setup_left_view_projection()
glColorMask(1,0,0, 1); # red is commonly used for the left eye
draw_scene()
glClear(GL_DEPTH_BUFFER_BIT) # clear the depth buffer (and just the depth buffer!)
# prepare right view
setup_right_view_projection()
glColorMask(0,1,1, 1); # cyan is commonly used for the right eye
draw_scene()
The typical blend function is glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);; note that the final color changes according to the draw order.
Blend functions are not so obvious, so a graphical representation sometimes is better; check out for example this site.

OpengGL Light Blending

I am writing a Lights/Shadows system for my game using Java alongside the LWJGL. For each one of the Light-Emitting Entities I generate such a texture:
I should warn you that these Textures are full of (0, 0, 1) or (1, 0, 0) pixels, and the gradient effect is achieved with the alpha channel. I interpret the Alpha channel as a gradient factor.
Afterwards, I wish to blend every light/shadow texture together on a single texture, each at it's respective correct position. For that, I use a Framebuffer. I tried to achieve the desired effect using the following blend equation/function combination:
glBlendEquationSeparateEXT(GL_FUNC_ADD, GL_MAX);
glBlendFuncSeparateEXT(GL_SRC_ALPHA, GL_DST_ALPHA, GL_ONE, GL_ONE);
I chose GL_ONE/GL_ONE for the Alpha Channel Blend Function arbitrarily, for GL_MAX will only do max(Sa, Da), as stated here, which means that the scaling factors are not used. The result of this combination is the following:
This image was obtained with Apple's OpenGL Driver Profiler, so I did not render it using my application (which could mess with the final result). The next step would be to render this texture over the actual game using multiply-blending, in order to darken the image, but the lights/shadows texture is obviously wrong, because we can see the edges of individual light/shadow textures over each other.
How should I proceed to achieve the desired result?
Edit:
I forgot to explain my choices for the scaling factors:
I think that it would be right to simply add the colors of each light (pondering each of them with their respective alpha values) and choose the alpha of the final fragment to be the biggest of each overlapping light.
Imagine that one of your texture rectangles was extended outside its current border with some arbitrary pattern, like pure green. Imagine further that we were somehow allowed to use two different blending functions, one inside the border, and one outside. You would get the same image you have here (none of the green showing) if outside the border you used the blend function
glBlendFuncSeparateEXT(GL_ZERO, GL_ONE, GL_ONE, GL_ONE)
We would then want whatever blending function we use inside to give us a continuous blending result. The blending function
glBlendFuncSeparateEXT(GL_SRC_ALPHA, GL_DST_ALPHA, GL_ONE, GL_ONE)
would not give us such a result. It is not so much because the first parameter which would mean ignoring the source near the border (small alpha on the border, if I read your image description correctly). So it must be the second parameter. We want the destination only when the source alpha is small. Change GL_DST_ALPHA to GL_ONE_MINUS_SRC_ALPHA. This would be more standard, but maybe I'm not understanding your objectives?

OpenGL blending function to elminate primitive overlap but maintain overall opacity

I have some geometry which has a single primitive set that's a tri-strip. Some of the triangles in the primitive overlap, so when I add a material to the geometry with an alpha value I see the overlap (as expected). I want to get rid of this effect without changing the geometry though -- I tried playing around with different blending modes (glBlendFunc()) but I couldn't get this to work. I got some interesting results, but nothing that would eliminate opacity effects within the primitives of the tri strip, and preserve opacity for the entire object. I'm using OpenSceneGraph, but it provides a method to call glBlendFunc() for the geometry in question.
So from the image, assume that pink roads, purple roads and yellow roads constitute three separate objects, each created using a single tri strip (there are multiple strips, but for arguments sake, pretend that there were only three different colored tri strips here). I basically don't want to see the self intersections within the same color
Also, my question is pretty much the same as this one: OpenGL, primitives with opacity without visible overlap, but I should note that when I tried the blending mode in accepted answer for that question, the strips weren't rendered in the scene at all.
I've had the same issue in a previous project. Here's how I solved it :
glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA)
and draw the rectangles. The idea behind this is that you draw a
rectangle with the desired transparency which is taken from the
framebuffer, but in the progress mask the area you've drawn to so that
your subsequent rectangles will be masked there.
Source : Stackoverflow : Overlapping rectangles
One way to do this is to render each set of paths to a texture and then draw the texture onto the window with alpha. You can do this for each color of path.
This outlines the general idea.

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.