Save OpenGL output with Alpha? - c++

Right now I'm drawing a cube with OpenGL, I'm using Windows and WGL context. I have blending enabled so my cube looks semi transparent. Basically the background == the clear color (Black). I'd like to be able to save the image in raw RGBA format which I can then make into a png. I basically want the cube to blend in with a NULL background (0,0,0,0). How could I save the OpenGL output and have the background color be (0,0,0,0) (transparent) Without using a color mask (like 255,0,255).
Thanks

Just draw the cube, setting the clear color to (0, 0, 0, 0), and save the output using glReadPixels.

Related

Why RGBA is making png image blackish?

I am trying to capture PNG image with transparent background. I have set GL_RGBA as format in glReadPixels. But the output PNG image looks a little blackish or with saturated color. If backgrouund is not transparent that is if I use GL_RGB format in glReadPixels expected image is captured.
Note: In both cases, I am capturing translucent(partially transparent) shaded cube. If cube is completely opaque, RGBA format works fine.
Any ideas as to why this is happening for transparent background?
Blackish image with RGBA format
Image with RGB format
The cube looks darker because it's semitransparent, and whatever you use to view the image blends the semitransparent parts of it with black background.
You might argue that the cube in the picture shouldn't be semitransparent since it's drawn on top of a completely opaque background, but the problem is that the widely-used
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
blending mode (which you seem to use as well) is known to produce incorrect alpha values when used to draw semitransparent objects.
Usually you can't see it because alpha is discarded when drawing to the default framebuffer, but it becomes prominent when inspecting outputs of glReadPixels.
As you noticed, to solve it you can simply discard the alpha component.
But if you for some reason need to have a proper blending without those problems, you need
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
Note that for this funciton to work, both source and destination images have to be in premultiplied alpha format. That is, you need to do color.rgb *= color.a
as a last step in your shaders.
The inverse operation (color.rgb /= color.a) can be used to convert an image back to the regular format, but if your images are completely opaque, this step is unnecessary.

Blend a clipped image together with a background into destination in one step

Please have a look at this image.
I'd like to show an clipped detail of the texture while the clipping rect can be animated so I cannot crop the image upfront. The position of the image is animated too.
I'd like to show it in front of a background. The background is a color or a texture itself.
I'd like to blend both the image and the background combined with opacity
< 1.0 to the destination.
The real requirement here is to render it in one step, avoiding a temporary buffer. Obviously a (simple) shader is needed for that.
What I already tried to achieve this:
Rendering the background first and then the image each with opacity < 1. The problem here: It lets the background shine through the image. The background is not allowed to be visible where the image itself is opaque.
It works when rendering both into a temporary buffer using opacity = 1 and then rendering this buffer to destination with opacity < 1, but this needs more (too much) resources.
I can combine two textures (background, image) in a shader, transform the texture coordinates each with a different transformation matrices. The probleme here is, that I'm not able to clip the image. The rendered geometry is a simple rectangle consisting of two triangles.
Can anybody hint me in the right direction?
You're basically trying to render this.
(Image blended with background) blended with destination
The part in parentheses, you can do with a shader, the blending with destination, you have to do with glBlendFunc, since the destination isn't available in the pixel shader.
It sounds like you know how to clip the image in the shader and rotate it by animating texture coordinates.
Let's call your image with the childreb on it ImageA, and the grey square ImageB
You want your shader to produce this at each pixel:
outputColor.rgb = ImageA.rgb * ImageA.a + ImageB.rgb * (1.0 - ImageA.a);
This blends your two images exactly as you want. Now set the alpha output from your pixel shader to be your desired alpha (<1.0)
outputColor.a = <some alpha value>
Then, when you render your quad with your shader, set the blend function as follows.
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
<draw quad>

OpenGL Blending Color over Monochrome

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.

Inverted-colors text on top of an OpenGL scene

I have a font texture which I use in order to draw text on top of my OpenGL scene.
The problem is that the scene's colors vary so much that any solid color I use is hard to read. Is it possible to draw my font texture with inverted colors?
A call to glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); would just draw it with a solid color, A call to glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); would draw it inverted, but would disregard the alpha values of the texture so you'd just see an inverted rectangle instead of the letters.
What I need is something equivalent to
glBlendFunc(GL_SRC_ALPHA * GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA);
Can this be achieved somehow without using shaders ?
Following dave's comment:
Instead of using a GL_ALPHA texture I generate a GL_RGBA texture where each pixel is equal:
(alpha, alpha, alpha, 0xff) (this is a greyscale image instead of a luminance image).
Then I use this texture with:
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR);
The result is: (1 - dest_color) x "src_alpha" + dest_color x (1 - "src_alpha")
which is exactly what I needed.
Copy the subsection of the screen you want to overwrite, you can use the CPU to invert this copied portion. Draw your newly made inverted texture to the screen using the text as a mask.
Note that this is slow, there's no doubt that shaders would be much faster.

Opengl: use a texture only to give alpha channel to a colored object

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.