Multitexturing Question

Does the ARB multitextuting extension support multiple levels of blending?? As in could i have one texture more pronounced than another. Because all the examples I have seen both the textures are equally blended.

It’s not multitexturing itself that does that. It’s the texture function. What you are after is a job for the ARB_texture_env_combine extension.

And how do i do that? How do i use that extension to change the blending ratio?

Here is a link to the specs for the extension: http://oss.sgi.com/projects/ogl-sample/registry/ARB/texture_env_combine.txt

Diapolo

To be more specific, how textures are blended into each other is controlled by the function glTexEnv. For each texture, there is a texture blending stage. The input to each stage is the output from the previous one (for the first one, the input is the primary color from goroud shading). glTexEnv controls these texture blending stages and which operations they perform.

ARB_texture_env_combine is a type of operation that a glTexEnv can use. However, it is not the only type. I would start playing with glTexEnv without ARB_texture_env_combine to get a feel for how the functions and operations work.

You should notice that not all cards support ARB_texture_env_combine (GeForce and Radeon and up support it). For instance, EXT_texture_env_combine is more widely supported (e.g. works on TNT cards).

Im not sure you understand what i want… You are talking about different blending functions sorta. What i want is to change the blending level. For example, in multi pass you change the alpha values of the different passes on teh geometry. Say set one pass to 0.1 and the other to 0.9. That way the second pass is alot more dominant in the end… How do you do this with single pass multitexturing. What you told me i think is equivalent of different blending functions (in a way), what i want is the equivalent of changing the alpha value in glColor4f

Follow Diapolo’s link and read the spec for the texture_env_combine extension. It describes the extension pretty well.

When you understand it, set up the combiners like this. I think this is correct. Only tried it with paper and pencil

Combiner 0:
arg0 = GL_TEXTURE
func = GL_REPLACE

Combiner 1:
arg0 = GL_PREVIOUS_ARB
arg1 = GL_TEXTURE
arg2 = GL_PRIMARY_COLOR_ARB
func = GL_INTERPOLATE

Then you use the primary color (the glColor command for example) to control the blending level. The value describes the amount of color from the first texture you want to use.

glColor3f(1, 1, 1) means 100% first texture.
glColor3f(0, 0, 0) means 100% second texture.
glColor3f(0.6, 0.6, 0.6) means 60% first, and 40% second texture.

And the fun thing is that you can control the blending level for the individual channels.

glColor(1, 0, 0.5) takes the red channel from the first texture, the green channel from the second textuure, and 50% from the blue channel from each texture.

Excellent, thats exactly what i needed to know, thanks alot…

Just out of interest, say i had to change the level of blending for every terrain tile in say a 178*1788 grid. Wouldnt all those state changes be expensive?? Thats alot of state changes…

I do not think that changing the primary color is very expensive, at least not if you use vertex arrays or display lists. Of course, if you could figure out a way to store the blending parameters in a texture instead it would probably be faster.

It’s equivalent to doing light mapping rather than custom per-vertex lighting.

As Marcus said, changing the primary color is not very expensinve compared to real state changes. In fact, I don’t even consider the promary color as a state in the OpenGL state machine.

You can very well change the primary color on a per-vertex basis, without seeing much of a performance impact, assuming you have a somehwhat new graphics board and are not that geometry limited.

If you need to draw a huge grid, then I suggest you use vertex arrays instead, and not immediate mode.

Using a texture as blending factor either requires three texture units, two texture units and two passes, or two texture units and one pass if you can put the blending factor in the alpha channel of the second texture.

If you put the blending factor in the second texture, then, in the second combiner, set arg2 to GL_TEXTURE, and operand2 to GL_SRC_ALPHA (now I hope that was correct).

This may be a dumb question… but how do i change the vertex colours of the rendered multitexturing polygons?? say i set up the operand for GL_PRIMARY_COLOR_EXT as GL_SRC_ALPHA, that means blending is controlled by the alpha value. How then would i go about changing the actualy colour of the rendered polygon?? when i just change teh values for glColor4f nothing happens… I want to keep the same blending ratio but change the polygons color…

You mean you want to take the RGB part form glColor4, and use that as a base color, in the same way as the modulate function works?

Then you are in some deeper trouble. I believe that equation requires another combiner. Since you already use two texture units for the texture crossfading, you need a third unit.

I’m afraid you have to find another solution. Check out some vendor specific extensions, like NV_register_combiners and NV_texture_env_combine4. Don’t know what ATI supports, but I’m sure they got some too.

MrShoe:

when i just change teh values for glColor4f nothing happens… I want to keep the same blending ratio but change the polygons color…

You have to repeat the parts you want to keep and change the one you want to change …

ex:

glColor4f(1.0f,0.5f,0.0f,0.8f); //orange, 80% blending
draw_stuff();
glColor4f(1.0f,0.5f,0.0f,0.5f); //still orange, 50% blending
draw_other_stuff();
glColor4f(1.0f,1.0f,0.0f,0.5f); //yellow, but still 50% blending
draw_even_more_stuff();

You can put the vertex colors into vertex arrays alongside your vertex coordinates. This way you can change color and/or blending per vertex.

Could I instead do the following? I want to change the color because im using per vertex radiosity for my terrain… So i need the tiles that are in shadow to be darker. If i cant simply change the vertex color, I could in multipass blending but i cant in single pass (not easily according to you guys). Cant i just have a 3rd texture pass with just a black texture?? and blend the black texture in accordingly. This brings me to the other question. Why doesnt OpenGL let me do a 3rd texture pass?? Code:

// Grass texture
glActiveTextureARB(GL_TEXTURE0_ARB);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_REPLACE);
// Sand Texture
glActiveTextureARB(GL_TEXTURE1_ARB);
glBindTexture(GL_TEXTURE_2D, texture[1]);
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_PRIMARY_COLOR_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_INTERPOLATE_EXT);

// Detail Texture
glActiveTextureARB(GL_TEXTURE2_ARB);
glBindTexture(GL_TEXTURE_2D, texture[2]);
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD_SIGNED_EXT);

If i do this it only draws the grass and the detail texture, but it ignores the sand texture… does any1 have any idea why??

Could I instead do the following? I want to change the color because im using per vertex radiosity for my terrain… So i need the tiles that are in shadow to be darker. If i cant simply change the vertex color, I could in multipass blending but i cant in single pass (not easily according to you guys). Cant i just have a 3rd texture pass with just a black texture?? and blend the black texture in accordingly. This brings me to the other question. Why doesnt OpenGL let me do a 3rd texture pass?? Code:

// Grass texture
glActiveTextureARB(GL_TEXTURE0_ARB);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_REPLACE);
// Sand Texture
glActiveTextureARB(GL_TEXTURE1_ARB);
glBindTexture(GL_TEXTURE_2D, texture[1]);
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_PRIMARY_COLOR_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_INTERPOLATE_EXT);

// Detail Texture
glActiveTextureARB(GL_TEXTURE2_ARB);
glBindTexture(GL_TEXTURE_2D, texture[2]);
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD_SIGNED_EXT);

If i do this it only draws the grass and the detail texture, but it ignores the sand texture… does any1 have any idea why??

Be aware that you are using three texture units. I don’t know what graphics card you have, but make sure you DO have three texture units available. As far as I know, only Radeon and GF3 has three or more texture units (among the consumer level cards that is).

Call glGetIntegerv with GL_MAX_TEXTURE_UNITS_ARB to find out how many texture units you got. If you only have two, then when you activate the third unit, you should get an error, GL_INVALID_ENUM.

The last four calls to glTexEnvi would then operate on the second texture unit, since that unit was last successfully activated, and would overwrite the commands above that was intended for the second unit. That is why you get no sand texture, cause you bind another texture, the detail texture, on the second unit.

GF1 / GF2: 2 texture Units
Radeon: 3 texture units
Kyro 2: 4 texture units
GF3: 4 texture units
Radeon 8500: 6 texture units

I guess for the thing you want to do you have to use a multi-pass solution.

Diapolo

Hmmm, back to multipass i suppose :frowning:
one last question then. How do i turn off multitexturing? Because after i init multitexturing, everything renders fine, but after i call glMultiTexCoord2fARB… EVERYTHING is rendered using the multitexturing texture… Like, say i render the grass texture onto the terrain using multitexture. After that everything else is also rendered using the grass texture, even if i have specified a different texture using glBindTexture… So, how do i turn off multitexturing??