Simplest way to render image over top of another with another image used as mask in OpenGL?

The effect I'm looking for is to have a single large background image that is always visible (at full alpha) and then show a second image (what I call a light map or specular map) that is partially shown over the top based on a third image (which is effectively a mask).

The effect is similar to this effect except instead of simply darkening or lightening the background image using the third image it needs to mask the second without effecting the first at all.

The third image is the only one that moves therefore hard baking the third images alpha into the second image isn't an option.

If my explanation isn't clear I'll provide visual examples when I have more time.

I'd prefer not to go down a shader route as I haven't taught myself this area yet so unless I have too I'd rather try to achieve this with simple alpha blending. Happy to use a shader approach.

Cheers.

These third images are obviously light sources being cast onto the first image showing the specular information from the second image to simulate the light 'shining' off the objects in the first image. The solution I implement will need to allow two light sources to potentially overlap so my current thoughts are that the alpha values of the two images will need to be combined (Added?) to produce a final image which masks the second image?

Don't worry about things like coloured lights. For this technique the lights are all considered white.

• Since OpenGL 3 and OpenGL ES2 everything is done with shaders. So you have to learn shaders anyway... and it is much easier to make stuff with shaders than without them :) – kravemir Jun 12 '13 at 10:31
• If I understand correctly you have one fixed background. Few moving objects that reveals parts of another fixed image at areas that are overlapped by them (with mask). – kravemir Jun 12 '13 at 10:34
• Seems like you have the gist of it yes Miro. Are you saying there is no other way? Thanks. – Adam Naylor Jun 12 '13 at 11:01
• @Miro If it is indeed easier, could you provide an answer which roughly outlines the steps? Thanks. – Adam Naylor Jun 12 '13 at 13:13
• @Miro I'm not finding any documentation that states you have to use shaders in OpenGL 3/ES2. Could you please provide links to the information? Thanks. – Adam Naylor Jun 17 '13 at 7:37

For fixed-function, this might be what you want:

Essentially, use the blend modes (and proper use of the color channels vs alpha channel) to write a mask into your backbuffer and then render a foreground image masked.

With shaders, you can simply provide the mask/light texture as an input to the fragment shader, query the "real" input textures (for sprites or whatnot) and the mask texture and then discard fragments or blend them appropriately.

It's been long enough since I've used GLSL that the following code is probably syntactically invalid and certainly idiomatically off, but the gist of it is:

// mask.fragment.glsl
layout(location=1) uniform sampler2D sSprite;

in vec2 aTexCoord;
in vec4 aColor;

layout(location=0) out vec4 rtColor;

void main() {
vec4 sprite = texture2D(sSprite, aTexCoord);
rtColor = mask * sprite * aColor;
}


You can change up how you use mask to make it color-based, alpha-based, whatever. Using that snippet you would use the alpha channel of the mask texture to make hide details and the color to have the light change the output color, supporting colored lighting.

• Thanks @Sean Middleditch, I had tried the solution in the answer you linked to previously but I then read that glBlendFuncSeparate() wasn't available in some of the more modern versions of OpenGL (3 & ES2) is that correct? If so is there a way to do the fixed function approach without this call? If that's too much hassle I'll try and knock up a shader approach as you've outlined here. Thanks! – Adam Naylor Jun 18 '13 at 8:00
• Also, that link outlines almost exactly what I'm trying to achieve. – Adam Naylor Jun 18 '13 at 8:04
• glBlendFuncSeparate() is still available (and not deprecated as far as I can see) in all current OpenGL flavours. – GuyRT Jun 18 '13 at 10:22
• +1ed already, but I noticed a couple of things in the glsl. Don't you need a different uniform location for "sSprite"? Did you mean to write "mask.a" in the last line (since you say in the text "use the alpha channel...")? – GuyRT Jun 18 '13 at 10:27
• @GuyRT: typo for location fixed. I'm using all of mask since that way you get multiplicative blending for any color in the mask and you use alpha to make it mask off pixels, useful if you want to colorize your light mask. Make the mask color all white to have no color changes. If you don't want colorization, just use a one-component texture instead. – Sean Middleditch Jun 18 '13 at 17:09