Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using alpha from texture to draw solid color

How can I use OpenGLES 1.1 (iPhone) to draw a texture, but only using the alpha to draw some color?

The result should be the exact same alpha mask from the original texture, with a single solid color inside instead of the original colors.

I am using glDrawArrays with glCoordPointer and glVertexPointer.

I think doing two passes, one with the texture and one with a solid color to to this. I just can't seem to find the invert of glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);.

Edit: after some more looking around, I thinks this should be possible to achieve using glTexEnvf. It's just a matter of finding the right arguments.

like image 629
sharvey Avatar asked Nov 14 '10 01:11

sharvey


2 Answers

As mentionned, glTexEnv is the way to go.

To replace the RGB components of your texture and keep its alpha untouched, you could try something like this (this code uses red as replacement color):

glColor4f( 1.0f, 0.0f, 0.0f, 1.0f );

glActiveTexture( GL_TEXTURE_0 );
glEnable( GL_TEXTURE_2D );
glBindTexture(GL_TEXTURE_2D, spriteTexture);

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);

// ... draw as usual

Here come some explanations.

When using GL_COMBINE, you have complete control on how the input/output of the different texture stages are combined together. In this case, we specify that we want to replace (GL_REPLACE) the RGB components of texture stage 0 with what comes from the previous stage (GL_PREVIOUS) which in this case is a single color (set with glColor4f).

We did not set anything special for the alpha component as we want the regular behavior. Adding the following lines would have had the same effect as if not included (default behavior):

glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE);   
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
like image 144
Ozirus Avatar answered Sep 18 '22 17:09

Ozirus


If you can use OpenGL ES 2.0, you could do this with a custom fragment shader. If you're using a framework that is built on 1.1 or are targeting devices that don't support 2.0, this won't be much help. But if you can, this is how you do it:

uniform lowp sampler2D sampler; // which texture unit to use
uniform lowp vec4 solidColor;

varying highp vec2 fragmentTexCoord;

void main()
{
    // Get the color with an alpha of zero
    vec4 color = vec4(1,1,1,0) * solidColor;
    // Get the alpha from the texture, zero the r,g,b components
    vec4 alpha = vec4(0,0,0,1) * texture2D(sampler, fragmentTexCoord);
    // their sum is the solid color with the alpha mask of the texture
    gl_FragColor = color + alpha;
}

If you can ensure the solidColor has an alpha of zero you could skip the multiplication step.

like image 32
benzado Avatar answered Sep 22 '22 17:09

benzado