OpenGL ES Texture Masking

What’s the best choice when trying to mask a texture
like they do in there iphone apps? ColorSplash, iSteam, etc?

I started learning OPENGL ES like… 4 days ago (I’m a total
rookie) and tried the following approach:

  1. I created a colored texture2D, a grayscale version of the first
    texture and a third texture2D called mask

  2. I also created a texture2D for the brush… which is grayscale and
    it’s opaque (brush = black = 0,0,0,1 and surroundings = white =
    1,1,1,1). My intention was to create an antialiased brush with smooth
    edges but i’m fine with a normal one right now

  3. I searched for masking techniques on the internet and found this
    tutorial ZeusCMD - Design and Development Tutorials : OpenGL ES Programming Tutorials - Masking
    about masking. The tutorial tells me to use blending to achieve
    masking… first draw colored, then mask with
    glBlendFunc(GL_DST_COLOR, GL_ZERO) and then grayscale with
    glBlendFunc(GL_ONE, GL_ONE) … and this gives me something close to
    what i want… but not exactly what i want. The result is masked but
    it’s somehow overbright-ed

  4. For drawing to the mask texture i used an extra frame buffer object (FBO)

I’m not really happy with the resulting image (overbright-ed picture)
nor with the speed achieved with this method. I think the normal way
was to draw directly to the grayscale (overlay) texture2D affecting
only it’s alpha channel in the places where the brush hits. Is there a
fast way to achieve this? I have searched a lot and never got an
answer that’s clear and understandable. Then, in the main draw loop I
could only draw the colored texture and then blend the grayscale ontop
with glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA).

I just want to learn to use OPENGL ES and it’s driving me nuts because i can’t get it to work properly. An advice, a link to a tutorial would be much appreciated.

Robert

PS. Sorry for my bad english… i’m from Romania

Hi,

I’m guessing you’re using OpenGL ES 2.0 and not 1.1. since you mentioned framebuffer objects. To achieve the effect I think you’re after you could use a fragment shader like this:


precision mediump float;
uniform sampler2D colorTexture;
uniform sampler2D bwTexture;
uniform sampler2D maskTexture;
varying vec2 textureCoords;

void main()
{
    vec4 color = texture2D(colorTexture, textureCoords.uv);
    vec4 bw = texture2D(bwTexture, textureCoords.uv);
    float alpha = texture2D(maskTexture, textureCoords.uv).a;
    gl_FragColor = mix(color, bw, alpha);
}

The main idea is to use the mix() GLSL ES built-in function to blend together the color and black & white versions of the image. The amount of mixing is controlled through the mask texture.

Achieving the same effect on OpenGL ES 1.1 is a little more complicated, but doable using texture environment combiners. First, draw the black & white version of the image onto the screen. Then set up the following RGB combiner settings:


/* First stage: color texture */
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE2D, colorTexture);
glTexEnvi(GL_TEXTURE_2D, GL_COMBINE_RGB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_2D, GL_SRC0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_2D, GL_OPERAND0_RGB, GL_SRC_COLOR);
/* Second stage: interpolation with the mask texture */
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE2D, maskTexture);
glTexEnvi(GL_TEXTURE_2D, GL_COMBINE_RGB, GL_INTERPOLATE);
glTexEnvi(GL_TEXTURE_2D, GL_SRC0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_2D, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_2D, GL_SRC1_RGB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_2D, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_2D, GL_SRC2_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_2D, GL_OPERAND2_RGB, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_2D, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi(GL_TEXTURE_2D, GL_SRC0_ALPHA, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_2D, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
/* Set the primary color to transparent black to make sure the B&W texture shows through where the mask is transparent */
glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
glEnable(GL_BLEND);