2

I'm trying to use alhpa masking with glAlphaBlend and all his parameters. I found a lot similar answer on stackoverflow but i doesn't realise anything.

I have three images, a background (1), a mask (2), and text (3).

What i want is to draw the background, substract my mask to the text to finally obtain the image (A).

Image Example

Draw background

glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
glClear(GL_DEPTH_BUFFER_BIT);
glEnable(GL_BLEND);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
glBegin(GL_QUADS);
glColor4ub(0,0,0,255);
glVertex2d(mxIncrust0 - bgwidth, myIncrust0);
glVertex2d(mxIncrust0, myIncrust0);
glVertex2d(mxIncrust0, myIncrust0 + textheight);
glVertex2d(mxIncrust0 - bgwidth, myIncrust0 + textheight);
glEnd();
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFuncSeparate(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA, GL_ZERO, GL_ONE);

Draw Text

But Anything is working !

What is the real way to achieve it ?

My question is different because it is not based on OpenGL ES but only Open GL.

Maypeur
  • 387
  • 4
  • 18
  • `But Anything is working !` What on earth could this mean? What result you've got? There are no mediums on SO. – Ivan Aksamentov - Drop Sep 11 '14 at 13:40
  • I understand, i'm trying to say that i tried every answer on stack but anything is doing the right thing ! – Maypeur Sep 11 '14 at 13:44
  • Then show us what you've got. Also note, there is no such thing as "Draw a mask". The only thing that draws is `Draw*` calls. You don't need to draw a mask. Mask will be combined with your text texture on output merger stage ("per-sample operations" in GL slang). Before you show us drawing code and resulting screenshot, I can only advise you to take a look at opengl docs: [Rendering Pipeline Overview](http://www.opengl.org/wiki/Rendering_Pipeline_Overview) – Ivan Aksamentov - Drop Sep 11 '14 at 13:49
  • If i don't paste this code it is only because it doesn't help. – Maypeur Sep 11 '14 at 13:56
  • After i made a lot of different things, like using only blend, trying different values for glBlendEquation, glBlendFunc i can't achieve what i want, here is a sample of one way i tried, but i tried about 50 differents ways, so do you want i paste 2000 lines of code with only one different parameters each ? Finally it doesn't help me to send me the link of the manuel, if you doesn't have the skills to help me let another one do. Thanks. – Maypeur Sep 11 '14 at 14:00
  • 2
    Your desired output could be accomplished very easily in a shader. You would first render the background. Then enable blending and attach both the mask texture and the text texture and multiply the alpha of the text texture by the mask value. – user3256930 Sep 11 '14 at 16:33
  • This is exactly the way i'm trying to do with blending ! I never used shader, maybe you have a good link where i can start. Thanks. – Maypeur Sep 11 '14 at 20:44
  • Possible duplicate of [Images and mask in OpenGL ES 2.0](https://stackoverflow.com/questions/18550226/images-and-mask-in-opengl-es-2-0) – Nande Feb 14 '19 at 01:48

3 Answers3

8

The "real way" to accomplish this is to use shader programs and modern OpenGL .Why do you use that deprecated API?We are in the year 2014 with OpenGL 4.5 as the latest version.You even can't claim you care about backward compatibility as even some really old cards(well,5 years old) today support at least GL 3.2 which is fully programmable.And you know what,even with the GL 2.0 you still can use shaders, but working with the deprecated API takes you nowhere if you plan to code OpenGL for your living in the near future.

Now,using shaders,masking is one of the most trivial tasks. You would typically pass 2 textures into the fragment shader.1 - Diffuse texture(actual texture to cover the surface) 2 - Mask texture (maybe a single channel grayscale texture)

The fragment shader would look like this:

#version 150
uniform sampler2D maskTex;
uniform sampler2D colorTex;

out vec4 colorOut;
in smooth vec2 texCoords;
void main(){ 

     vec4 color = texture(colorTex,texCoords);
     vec4 mask  = texture(maskTex,texCoords);

     colorOut =vec4(color.rgb,color.a * mask.r);//alpha value can be in any channel ,depends on texture format.
}

As simple as it can be.Hope it helps.

P.S make sure you mipmap the alpha texture as well,in case the diffuse texture is mipmapped. Also please note my example doesn't come to solve your specific task but to show you how basic masking is done in programmable OpenGL.From here it is easy to figure out what to do ;)

Addendum:

Someone in the comments below wondered why on earth one would want to use an extra texture just for holding alpha mask data.Here is my answer:

In many complex application users use additional textures called alpha maps to mask out pixels of primary texture,also taking into account the alpha of that texture during the process, and there is no reason to "merge" alpha channels into one texture map because it would require an extra step and a waste of runtime for no real purpose.In some complex rendering scenarios those alpha maps can be generated only during different render passes on request and later fetched into fragment shader for final usage. So in such a case the application doesn't even have that data before runtime. Also,same alpha mask can be required by many different color textures. So does it make sense to merge it into all of those? Sure it doesn't. The practice above is well known and pretty efficient comparing to merging transparency data on CPU just to avoid extra texture sampling.

Michael IV
  • 11,016
  • 12
  • 92
  • 223
  • Thank you very much for this complete response, i found similars example using shader. It seemes to be understandable but my first problem is that for the text it is not a texture and i generate my mask with a basic gl_quad ! PS : It doesn't solve the way i was searching for but with that it seems to be first more performant and second as you say better for the futur. I will try it during next few days... – Maypeur Sep 12 '14 at 09:17
  • @PurpleIce First, I suggest you to be kind even if you disagree with someone on SO.In this example, I have shown usage of ALPHA MAP,which contributes extra alpha information to the alpha channel already existent in the colorTex. The problem with your comment is that you don't see the whole picture of such a use case. See my addendum above. – Michael IV Mar 01 '19 at 10:28
2

I finally found a solution with glClipPlane, i didn't find any solution with shader since it isn't texture.

So how it works ? 1) I draw my background (quad, lines...) 2) I define and active a limit below nothing is draw on the left and a limit above nothing is draw on the right 3) I draw everything i need (quad, lines, my text...) 4) i disable the clip.

// Draw the background
double* leftMask = new double[4];
leftMask[0] = 1;
leftMask[3] = -mClipXL; // Be careful to use -Limit for the left limit
glClipPlane(GL_CLIP_PLANE0, leftMask);
delete[] leftMask;
glEnable(GL_CLIP_PLANE0);

double* rightMask = new double[4];
rightMask[0] = -1;  // Be careful to use -1 for the right limit
rightMask[3] = mClipXR;
glClipPlane(GL_CLIP_PLANE1, rightMask);
delete[] rightMask;
glEnable(GL_CLIP_PLANE1);

// draw the text

// disable the clip to draw anything else.
glDisable(GL_CLIP_PLANE0);
glDisable(GL_CLIP_PLANE1);

It's working very very well !!!

Maypeur
  • 387
  • 4
  • 18
1

You can also use the stencil buffer for this. First you would enable stenciltesting:

glEnable(GL_STENCIL_TEST);

Then you first draw your masking quad only in the stencil buffer:

//begin mask
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glStencilFunc(GL_NEVER, 0, 0);
glStencilOp(GL_INCR, GL_KEEP, GL_KEEP);
glClear(GL_STENCIL_BUFFER_BIT);
//draw your mask, a quad in your case

Then you draw the masked part:

    ////masked fill part
    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    glStencilFunc(GL_NOTEQUAL, 0, 1);
    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
    // draw the masked element, the text in your case

Disable stencil testing again

glDisable(GL_STENCIL_TEST);

Depending on your needs you can change glStencilFunc() and glStencilOp() parameters to achieve the desired clipping effect.