Multitexturing ... again

Hello,

I am currently trying to improve speed on a tilemapped game. The tiles are all in one big texture. If two or more diffrent floor tiles are neighbours the system creates a transistion on one tile: The base floor tile is rendered first then the transition is rendered on top of the tile. The transistion is a tile with transparent parts in it. On top of this the walls of the game are rendered in a separate layer. Most of the wall field is transparent.

Currenty the engine uses multi-pass rendering which works - but the performance is quite bad. I want to improve this and now I try to use multi-texturing.

Currently I succeded in rendering two tiles above each other but the result is not what I expected. I get problems because of the transparency.
I think GL_DECAL is nearly what I want but there are problems if the floor-texture has transparent parts:
If I render the wall above the floor the wall is only visible if the floor is opaque. If the floor is transparent the wall disappears too.

I think I have to use GL_COMBINE but with which paramters?

Perhaps a little example will help:

1st field is the background from the current scene
2nd field is the texture 1
3rd field is the texture 2
4th field is the result
. = transparent pixel


B..B....   ...11...   ........    B.B11...
.B..B...   ...11...   ........    .B.11...
..B..B.. + ...11... + 22222222 => 22222222
...B..B.   ...11...   ........    ..B11.B.
....B..B   ...11...   ........    ...11..B

If the texture is semi-transparent it should be possible to see the layer below mixed with the current layer.

Is it possible to get this result with multi texturing? How must I set the parameters for the texture engine?

I’m using OpenGL ES 1.1 on iPhone.

Assuming you want to collapse two passes of single-textured (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) blending into one pass, the result should be this:

B’ = T1 * T1.a + B * (1 - T1.a)
B’’ = T2 * T2.a + B’ * (1 - T2.a)
= T2 * T2.a + (T1 * T1.a + B * (1 - T1.a)) * (1 - T2.a)
= T1 * T1.a * (1 - T2.a) + T2 * T2.a + B * (1 - T1.a) * (1 - T2.a)

You can achieve this with the following texenv/blend setup:


glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, ...);
glTexEnvi(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_COMBINE);
// rgb = texture0.rgb * texture0.alpha
glTexEnvi(GL_TEXTURE_2D, GL_COMBINE_RGB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_2D, GL_SRC0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_2D, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_2D, GL_SRC1_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_2D, GL_OPERAND1_RGB, GL_SRC_ALPHA);
// alpha = texture0.alpha
glTexEnvi(GL_TEXTURE_2D, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi(GL_TEXTURE_2D, GL_SRC0_ALPHA, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_2D, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);

glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, ...);
glTexEnvi(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_COMBINE);
// rgb = texture1.rgb * texture1.alpha + previous.rgb * (1 - texture1.alpha)
glTexEnvi(GL_TEXTURE_2D, GL_COMBINE_RGB, GL_INTERPOLATE);
glTexEnvi(GL_TEXTURE_2D, GL_SRC0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_2D, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_2D, GL_SRC1_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_2D, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_2D, GL_SRC2_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_2D, GL_OPERAND2_RGB, GL_SRC_ALPHA);
// alpha = (1 - texture1.alpha) * (1 - previous.alpha)
glTexEnvi(GL_TEXTURE_2D, GL_COMBINE_ALPHA, GL_MODULATE);
glTexEnvi(GL_TEXTURE_2D, GL_SRC0_ALPHA, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_2D, GL_OPERAND0_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_2D, GL_SRC1_ALPHA, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_2D, GL_OPERAND1_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);

Thanks. This did not exactly work… but it contained the trick I was looking for: using (1-alpha) for the calculation!


	glActiveTexture(GL_TEXTURE0);
	glClientActiveTexture( GL_TEXTURE0 );
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, [texture name]);
	glTexCoordPointer(2, GL_FLOAT, sizeof(ccMultiVertex), &quads[0].bl.t0x);
	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_TEXTURE );
	glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );

	glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE );
	glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE );
	glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

	glActiveTexture(GL_TEXTURE1);
	glClientActiveTexture( GL_TEXTURE1 );
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, [texture name]);
	glTexCoordPointer(2, GL_FLOAT, sizeof(ccMultiVertex), &quads[0].bl.t1x);	

	glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
	
	glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE );
	glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE );
	glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
	glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS );
	glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
	glTexEnvi( GL_TEXTURE_ENV, GL_SRC2_RGB, GL_TEXTURE );
	glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA );

	glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE );
	glTexEnvi( GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS );
	glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA );
	glTexEnvi( GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE );
	glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
	
//	glEnableClientState(GL_TEXTURE_COORD_ARRAY); 
	 glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
	
	glVertexPointer(3, GL_FLOAT, sizeof(ccMultiVertex), &quads[0].bl.vx);
	glDrawElements(GL_TRIANGLES, n*6, GL_UNSIGNED_SHORT, indices);	

The strange thing is that the multi texturing does not save any time. Even worse: Multipass is faster!

Mean frame rate for 1000 frames:

Multitexturing:
2 * 2 * 150 tiles = 34.533615 Frames

Multipass rendering:
4* 1 * 150 tiles = 36.954876 Frames

:?

With this small amount of geometry there should be little difference between multitexturing and multipass since all the blending happens in on-chip memory anyway. Multitexturing being slower probably means there are more texture cache misses due to two textures being used at the same time. What texture format are you using?

In any case the performance you are getting seems to be quite low. I assume you are using a 15x10 grid of 32x32 tiles, and the texels are mapped 1:1? Do you use GL_NEAREST as texture filter? What is the background layer you blend with, and what other objects are drawn?

Currently the texture is not yet optimized. Currently I use a .png-image: 24bit + alpha. 16Bit should work. I have not yet tested this because the graphics are not yet ready and I am not sure about the loss…
The image is a 512x512 pixels texture with all tiles on it. Both texture stages use the same texture.
The texels are mapped 1:1, GL_NEAREST ist activated for filtering.
For the tests I currently only draw the tiles. Background is just black - perhaps I’ll disable clearing it because the complete scene will be overdrawn each time.

How big is the texture cache on iPhone? Could it help to change the order of the tiles in the texture?

You could just give it a try to test the performance difference.

For the tests I currently only draw the tiles. Background is just black - perhaps I’ll disable clearing it because the complete scene will be overdrawn each time.

I’d recommend not removing the clear as there’s virtually no cost to it. If you’re just using a flat colour as background you shouldn’t need blending, though.

Could it help to change the order of the tiles in the texture?

No.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.