## Decomposing multitexturing to multiple passes

Sage
Posts: 1,234
Joined: 2002.10
Post: #1
OK. This is just another way of asking my other question.

Is it true that any multitexturing operation can be broken down into multiple passes with one texture unit?

If so, is it also true that it can be broken down in such a way that geometry can still be drawn in two complete passes, instead of one polygon from pass A, the same polygon from pass B, repeat? There might be state change required between the two passes.

Consider this situation:
Texture a bunch of overlapping, translucent geometry with two textures. First is solid. Second is an alpha texture, multiplying the first unit's alpha.

In the multitexturing case the hardware draws each polygon's alpha as the product of both textures and the current color. As long as the geometry is drawn back-to-front, it looks correct.

In the two pass case, all the polygons are drawn with the solid texture times the current color's alpha. Then, they are redrawn with the alpha texture, but (partially) obscured sections will get the wrong value, that of the foreground polygon.

Is there a trick to this I'm just not seeing?
Luminary
Posts: 5,143
Joined: 2002.04
Post: #2
I'm sorry, I'm really not following that.

Perhaps a diagram or something?
Sage
Posts: 1,234
Joined: 2002.10
Post: #3
All right, here it is explained in pictures.

texture unit 0 is bound to a base alpha texture (stripes)
texture unit 1 is bound to a modulating alpha texture ("ONE" or "TWO" for this example, though in practice it is the same texture for all quads)

Multitexturing case:

1) quad_one is drawn, with both textures modulating the base color.
2) quad_two is drawn, with both textures modulating the base color.

To clarify, quad_one is color (1, 1, 0, 0.7) and quad_two is color (0, 0, 1, 0.7) so there is translucency everywhere, not just where the alpha texture filtered.

Now, let's suppose that we want to do this using only one texture unit. (Actually, the reason is not because of lack of texture units, it is because I need to draw overlapping geometry to modify the alpha, without writing to the color buffer. But I figure this is equivalent to doing it using one texture unit.)

Here's one way to do it with one texture unit that works, but it takes (textures + 1) passes. The picture shows all six steps for clarity (reduced 50% for bandwidth...)

Multipass case:

1) quad_one's base alpha texture is drawn into the destination alpha buffer, using glBlendFunc(GL_ONE, GL_ZERO).
2) quad_one's modulating alpha texture is drawn into the destination alpha buffer, using glBlendFunc(GL_DST_ALPHA, GL_ZERO) and the alpha of the current color set to 1.
3) an untextured quad_one with the desired color is drawn to the color buffer only (alpha write disabled) using glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA).
4) quad_two's base alpha texture is drawn into the destination alpha buffer, using glBlendFunc(GL_ONE, GL_ZERO).
5) quad_two's modulating alpha texture is drawn into the destination alpha buffer, using glBlendFunc(GL_DST_ALPHA, GL_ZERO) and the alpha of the current color set to 1.
6) an untextured quad_two with the desired color is drawn to the color buffer only (alpha write disabled) using glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA).

The color buffer end result is the same, it just took more fillrate. I don't care so much about the fillrate (in practice, it will only be two passes, because I can write all alpha textures into the alpha buffer using multitexuring with one pass, and then a second pass for the untextured quad.)

However, the big problem with this is that there is a bunch of state change around drawing each quad, so I can't draw a group of geometry using VAR.

If I try to draw more than one quad at a time, the alpha values are wrong wherever the geometry overlaps. To illustrate, let's try to draw both quads in a group during the same pass.

Multipass_group case:

1) all quad's base alpha texture are drawn into the destination alpha buffer, using glBlendFuncglBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA).
2) all quad's modulating alpha texture are drawn into the destination alpha buffer, using glBlendFunc(GL_DST_ALPHA, GL_ZERO) and the alpha of the current color set to 1.
3) all untextured quads with the desired colors are drawn to the color buffer only (alpha write disabled) using glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA).

You can see that the alpha is wrong.

Ideas?
Sage
Posts: 1,234
Joined: 2002.10
Post: #4
And for a better example here's the multipass (group) method but using multitexturing to write both alpha masks at once, like I'd do in the real app.

Multipass_group multitexture case:

1) quad_one is drawn, with both alpha textures, into the destination alpha buffer using glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA).
2) quad_two is drawn, with both alpha textures, into the destination alpha buffer using glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA).
3) all untextured quads with the desired colors are drawn to the color buffer only (alpha write disabled) using glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA).

In the real app 1) and 2) could be one pass, the only state change in the example is rebinding between ONE and TWO textures.

Now you can see the real problem better which is that the color coverage for the quads are wrong.
Member
Posts: 72
Joined: 2006.10
Post: #5
There might be a way to get your last example to draw properly. It's not a very efficient way, but it may give you an idea.

When you arrive to draw the untextured polygons, you'd have to draw each of them two times with two different blending equations:

Code:
```glBlendEquation(GL_FUNC_SUBTRACT); //draw the quad glBlendEquation(GL_FUNC_ADD); //draw de quad again```

N.B. this works for the black background, I doubt the result would be good otherwise

When you draw the quad the first time, with a substractive blend equation, you would negate the effect of the combinasion of the two quads on the surface that that combinasion would affect. You can then safely draw the polygon again properly.

- Sohta