Rendering textures with masks

Member
Posts: 161
Joined: 2005.07
Post: #1
Hi everyone, I recently decided to learn OpenGL ES on the iPhone and I'm trying to get various demos working. Right now I just want to draw a textured and masked quad to the screen. I have two 4bpp PVR images loaded in, one called texture, and one called mask, and I have a quad on my screen that I can texture using either image.

What I can't figure out, however, is how to apply the mask and the texture to the same quad and end up with a masked image. I tried texture blending and couldn't get that to work, and now I'm trying to use texture combiners but I can't get that working either. Here's what I have right now, although it keeps changing since I'm trying to figure out what's wrong:
Code:
// set up the coordinates for the quad
glVertexPointer(2, GL_FLOAT, 0, squareVertices);
glEnableClientState(GL_VERTEX_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, squareTexCoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

// switch to texture unit 0
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

// load the mask into the current unit
glBindTexture(GL_TEXTURE_2D, mask);    
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);

// use the texture's color values for Arg0
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);

// switch to texture unit 1
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);

// load the texture into the current unit
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_BLEND);

// use the texture's color values for Arg1
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);

// draw the quad
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
When I run that, I get a blank white square, which most likely means the texture didn't appear at all and not that the combined texture simply happened to be white.

Does anyone know what I'm doing wrong? Both images can be applied to the quad as a texture, so I know they're loaded into memory correctly, but I can't figure out how to blend the two images together to get the masked texture.
Quote this message in a reply
Member
Posts: 161
Joined: 2005.07
Post: #2
Hm, well I was able to get multitexturing working once I learned that each texture unit has its own texture coordinates that need to be set (which makes sense), but I don't know how to use one texture as a mask for the other.
Quote this message in a reply
Moderator
Posts: 1,560
Joined: 2003.10
Post: #3
Is there any reason you can't construct a single texture with an alpha channel? That's probably a lot easier to get working than to get a second texture to act as a mask.
Quote this message in a reply
Member
Posts: 161
Joined: 2005.07
Post: #4
Each image will appear in a wide variety of colors, so I figured I'd save some space by only storing the mask once.
Quote this message in a reply
Sage
Posts: 1,232
Joined: 2002.10
Post: #5
First, make sure you understand how multitexturing works.

This is spelled out definitively in the spec.
Read "3.7.13 Texture Application" which has a helpful diagram showing how multiple texture units are applied in order.
Then read "3.7.12 Texture Environments and Texture Functions", which has tables showing the math each TEX_ENV_MODE will perform.

Now, express your goal in terms of those math operations. You want to apply an alpha mask to an RGB image. This is equivalent to:
* sample the RGB image on unit0 (REPLACE produces {ImgR, ImgG, ImgB, 1.0} if the internal format of the image was RGB.)
* sample the alpha mask on unit1 (REPLACE produces {ImgR, ImgG, ImgB, MaskA} if the internal format of the mask was ALPHA.)
* Blend the masked image into the framebuffer.

Using COMBINE gives you a lot more control, but you don't need it for this simple masking operation.
Quote this message in a reply
Member
Posts: 161
Joined: 2005.07
Post: #6
So I just ran a masked PNG through Apple's texturetool, and it turns out a masked PVR is exactly the same size as a non-masked PVR (2,868 bytes with mipmaps). Since that implies that using separate masks will actually take up more space, I just saved all the images as masked PVRs and used glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA) and it looks great. Thanks for the idea!

And thanks, arekkusu, for the document you sent! I'll be sure to pore over it in my free time. I've been meaning to spend some time getting a solid understanding of all these little subsystems OpenGL has.
Quote this message in a reply
Post Reply