Masking without a stencil buffer?

Member
Posts: 269
Joined: 2005.04
Post: #1
First, an image:

[Image: mask_problem.jpg]

On the left is a masked off area of the screen. On the right is random colors drawn where the mask is. Robocop represents some random complex 3D background.

I need to draw a large image (the color gradient) over only part of the screen (the masked off area). The large image doesn't change, however it does scroll around relative to the mask (the mask doesn't move or change). So I can't just slap an alpha map on the image and call it a day. Ordinarily this would be easy to accomplish with the stencil buffer, however this is for the iPhone that has no stencil buffer.

Any ideas?

EDIT: Here's another image to better explain what I'm looking for. Plus I'm bored:

[Image: mask_problem.gif]
Quote this message in a reply
Member
Posts: 45
Joined: 2006.07
Post: #2
I can't tell if the 3D background (henceforth Robocop) changes or not. If not: then render your rainbow (or whatever first). Put the mask as an alpha channel in the robocop image and draw it OVER the rainbow.

If robocop needs to change, first draw him. Then set up automatic texture coordinate generation so that it is linear in screen space. Then render your mask as an opaque triangle mesh with the rainbow texture.

Does that work?
Quote this message in a reply
Member
Posts: 269
Joined: 2005.04
Post: #3
mattz Wrote:I can't tell if the 3D background (henceforth Robocop) changes or not. If not: then render your rainbow (or whatever first). Put the mask as an alpha channel in the robocop image and draw it OVER the rainbow.

If robocop needs to change, first draw him. Then set up automatic texture coordinate generation so that it is linear in screen space. Then render your mask as an opaque triangle mesh with the rainbow texture.

Does that work?

Yea, Robocop just represents a 3D background that does change. So it has to be drawn first.

The problem with with the triangle mesh is that right now the mask is only in image format and is fairly complex (the star is a simplification). It would take a lot of triangles to approximate it properly.
Quote this message in a reply
Member
Posts: 45
Joined: 2006.07
Post: #4
Does the iPhone do fragment shaders and multitexturing? If so, it's trivial to write a fragment program that does what you want.

Otherwise, maybe you can use the depth buffer as a stencil buffer. Recipe:

- draw robocop
- clear the depth buffer
- enable alpha testing
- draw a single screen-aligned quad using the mask image as an alpha texture. this discards all fragments not in the mask
- disable alpha testing
- change the depth test to GL_EQUAL
- draw the same screen-aligned quad using the rainbow as a color texture
- profit!
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #5
You've got texture_env_combine and 2 stages, so render the 3D image first, then disable depth test, draw a full-screen quad with combine set up to cut out the star from the rainbow image.
Quote this message in a reply
Member
Posts: 269
Joined: 2005.04
Post: #6
mattz Wrote:Does the iPhone do fragment shaders and multitexturing? If so, it's trivial to write a fragment program that does what you want.

Alas, but no. Sad EDIT: Well multitexturing: yes, but shaders: no.

Quote:Otherwise, maybe you can use the depth buffer as a stencil buffer. Recipe:

- draw robocop
- clear the depth buffer
- enable alpha testing
- draw a single screen-aligned quad using the mask image as an alpha texture. this discards all fragments not in the mask
- disable alpha testing
- change the depth test to GL_EQUAL
- draw the same screen-aligned quad using the rainbow as a color texture
- profit!

That would probably work. I shall give it a try after I get back from Bond, James Bond.
Quote this message in a reply
Member
Posts: 87
Joined: 2006.08
Post: #7
As OneSadCookie said, this can be achieved by creating an alpha texture from your mask, and using some texture environment features to combine that with your mask. As a bonus, this will also get you soft edges if you want them, and you also don't have to generate geometry to populate the stencil buffer.

Texture unit 0 (foreground image): Mode: REPLACE
Texture unit 1 (mask): Mode: BLEND

If you want soft edges, enable framebuffer blending, and make sure you linearly filter the mask. If you want hard edges, make sure your mask also has hard edges, and use nearest filtering on the mask (or use alpha test, but that may have a larger performance impact).

See 3.7.12 in the ES 1 spec for full details.
Quote this message in a reply
Moderator
Posts: 1,562
Joined: 2003.10
Post: #8
As an alternate approach, could you simply translate on the Y axis of the texture matrix? Not sure if that works in OpenGL ES, but if it does, it seems like it could accomplish this...
Quote this message in a reply
Member
Posts: 269
Joined: 2005.04
Post: #9
Took some fiddling around, but the texture combiners eventually worked. Thanks guys. Smile
Quote this message in a reply
Nibbie
Posts: 1
Joined: 2009.07
Post: #10
Bachus Wrote:Took some fiddling around, but the texture combiners eventually worked. Thanks guys. Smile

How did you arrive to that solution. Can you please gimme a code snippet to point me in the right direction.
Quote this message in a reply
Member
Posts: 269
Joined: 2005.04
Post: #11
arca1n Wrote:How did you arrive to that solution. Can you please gimme a code snippet to point me in the right direction.

It's basically what Frogblast said. The mask texture is white (although any color would work) and alpha-mapped. GL_REPLACE replaces the color values in the mask texture with those in the gradient texture, while keeping the alpha values. So the gradient is drawn with the alpha of the mask. Pseudo-code:

Code:
// Set up the texture and combiner
glClientActiveTexture(GL_TEXTURE0);
glActiveTexture(GL_TEXTURE0);

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

// Bind the mask texture and texCoords
glBindTexture(GL_TEXTURE_2D, maskTexID);
glTexCoordPointer(2, GL_FLOAT, 0, maskTexCoords);

// Set gradient texture and bind
glClientActiveTexture(GL_TEXTURE1);
glActiveTexture(GL_TEXTURE1);

glBindTexture(GL_TEXTURE_2D, gradientTexID);
glTexCoordPointer(2, GL_FLOAT, 0, gradientTexCoords);

// Draw
glVertexPointer(2, GL_FLOAT, 0, verts);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

// Set back our old settings
glClientActiveTexture(GL_TEXTURE0);
glActiveTexture(GL_TEXTURE0);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

If you're really bored (and have a few bucks), you can see the end result of this thread on the Illuminations title screen. Sneaky
Quote this message in a reply
Nibbie
Posts: 2
Joined: 2009.11
Post: #12
What do you mean by alpha-mapped?

I've got my mask texture, a white circle. and my texture i want to clip, a rainbow gradient square. I'm trying to use your technique but it just renders the mask on the screen.

any help appreciated.
Quote this message in a reply
Sage
Posts: 1,482
Joined: 2002.09
Post: #13
You are probably loading your texture as RGB, you need to load an alpha texture. You can do this by passing GL_ALPHA as the internal format to glTexImage2D().

Scott Lembcke - Howling Moon Software
Author of Chipmunk Physics - A fast and simple rigid body physics library in C.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  OpenGL ES Texture Masking airfire 6 15,350 Mar 17, 2014 07:07 PM
Last Post: baioses
  SLOW performance drawing multiple polygons per frame with stencil buffer clam61 7 4,415 Apr 27, 2013 11:53 AM
Last Post: clam61
  OpenGL ES Texture Masking dalasjoe sin 0 3,952 Apr 13, 2012 12:17 AM
Last Post: dalasjoe sin
  Making 2D Stencil Shadows Soft metacollin 16 15,794 Jul 22, 2009 01:59 PM
Last Post: NelsonMandella
  Alpha Masking Problem bonanza 5 3,882 Jun 29, 2008 11:58 AM
Last Post: maximile