Archived

This topic is now archived and is closed to further replies.

jmschust

glBlendFunc vs Multitexture

Recommended Posts

I would like to know if there is some more information on the differences or similarites b/t using standard blend functions and multitexturing. For example I know that the standard blend b/t two textures is glBlendFunc( GL_ONE, GL_ONE) which also seems to be the standard thing that happens when using two textures in a mutlitexture environment. Example: glActiveTextureARB(GL_TEXTURE0_ARB); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texid1); glActiveTextureARB(GL_TEXTURE1_ARB); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texid2); Add in all the glTexEnv combinations and you extend this. Bottom Line: Is there some sort of chart that shows the corresponding algorithm for multitexturing that the blendfunc would be equivalent too?

Share this post


Link to post
Share on other sites
I think you are searching for glTexEnv where you can setup the parameters for the texture, including blending...even blending to the polygon (yes, there is a blend func between the texture and the base polygon.) The standart is modulate, you can use GL_MODULATE, GL_DECAL and othr that I don''t remember!! For add and alpha and other stuf, you need extensions (EXT_ENV_COMBINER4 is a good one, EXT_ENV_ADD is mostly simpler!!!)

If you want, I can post the usage of all this...just ask
Filami

Techno Grooves

Share this post


Link to post
Share on other sites
blend function works on the pixel thats about to be written to the colour buffer and the pixel already on the colour buffer. You can scale each by various constants, and then the results of each is added. Ie, GL_ONE,GL_ONE will scale both by one and add them. GL_ZERO,GL_ONE will be 'invisible' because the new pixel is scaled by zero, the existing one is scaled by 1. so no change occurs. This can let you do some very nice effects, ie, multiplying the pixel you just drew by the inverse of the current pixel, or whatnot.

Multi-texturing is quite different.
with multi-texturing you cannot use the existing pixel. You can, however, apply some blending operations to each texture that is laid down. Usually this is just MODULATE (multiply together) ADD (add both), DECAL (simply replaces old texture, ie, is somewhat useless), REPLACE (same deal). DECAL shouldn't be used.
However, the GL_ARB_texture_env_combine extension allows a lot more flexibility. Firstly you can specify what happnes to the alpha components seperatly (VERY useful), you can also define 'sources', that are either alpha or colour, so you could multiply by the current textures alpha component. Outputs from each can also be scaled by 1,2 or 4. plus a couple of useful blending modes are added. SUBTRACT, INTERPOLATE (very useful) and ADD_SIGNED (good for detail texturing) and DOT3 with the ARB_texture_env_dot3extension. The functionality of this isn't quite on the level of D3D's texture unit operations, but it's a lot easier to use.


an example of multi-texturing...
You could do terrain that has texture transitions (rock on hills, grass on flat areas), a detail texture, and a lightmap in 4 texture units. You'd need to use GL_ARB_texture_env_crossbar if you wanted it to be independant of geometry, but still. This effect would require 3 passes without ENV_COMBINE.

| - Project-X - my mega project.. yup, still cracking along - | - adDeath - an ad blocker I made - | - email me - |

[edited by - RipTorn on March 5, 2003 8:35:13 PM]

Share this post


Link to post
Share on other sites
Thanks for the info,

Could you maybe point me to docs or tutorials about the crossbar extention? I don''t mind doing multipass I don''t need a very high frame rate (it''s actually based on user input, one frame per keystroke) but I do need to do three sets of combination.

I already have the code that I need for two, but the thrid one has me in a bind. Here please help out:

Here is the first:


  

// setup textures


m_app->m_glActiveTextureARB(GL_TEXTURE0_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_basemap->m_id);

m_app->m_glActiveTextureARB(GL_TEXTURE1_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_holemap->m_id);

// setup position and texture coords


m_app->m_glActiveTextureARB(GL_TEXTURE0_ARB);

glVertexPointer(3, GL_FLOAT, sizeof(Vertex), &m_sphere->verts[0].position);
glEnableClientState(GL_VERTEX_ARRAY);

glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &m_sphere->verts[0].texCoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

// setup texture coords for texture 1


m_app->m_glClientActiveTextureARB(GL_TEXTURE1_ARB);
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &m_sphere->verts[0].texCoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

// setup for the blend...


m_app->m_glClientActiveTextureARB(GL_TEXTURE0_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);

m_app->m_glActiveTextureARB(GL_TEXTURE1_ARB);

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);

// draw


glDrawElements(GL_TRIANGLES, m_sphere->m_fsize * 3, GL_UNSIGNED_INT, m_sphere->indices);

//Disable textures

glDisable(GL_TEXTURE_2D);

// cleanup and clear


m_app->m_glClientActiveTextureARB(GL_TEXTURE1_ARB);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);

m_app->m_glClientActiveTextureARB(GL_TEXTURE0_ARB);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);


// RIGHT NOW I JUST DO ANOTHER BLEND HERE, I''LL GO INTO WHY THIS REALLY DOESN''T DO WHAT I NEED


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

// setup second set textures


m_app->m_glActiveTextureARB(GL_TEXTURE0_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_nightmap->m_id);

m_app->m_glActiveTextureARB(GL_TEXTURE1_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_holemap->m_id);

// setup position and texture coords


m_app->m_glActiveTextureARB(GL_TEXTURE0_ARB);

glVertexPointer(3, GL_FLOAT, sizeof(Vertex), &m_sphere->verts[0].position);
glEnableClientState(GL_VERTEX_ARRAY);

glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &m_sphere->verts[0].texCoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

// setup texture coords for texture 1


m_app->m_glClientActiveTextureARB(GL_TEXTURE1_ARB);
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &m_sphere->verts[0].texCoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

// setup for the blend...


m_app->m_glClientActiveTextureARB(GL_TEXTURE0_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);

m_app->m_glActiveTextureARB(GL_TEXTURE1_ARB);

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);

// draw


glDrawElements(GL_TRIANGLES, m_sphere->m_fsize * 3, GL_UNSIGNED_INT, m_sphere->indices);

//Disable textures

glDisable(GL_TEXTURE_2D);

m_app->m_glClientActiveTextureARB(GL_TEXTURE1_ARB);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
m_app->m_glClientActiveTextureARB(GL_TEXTURE0_ARB);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);



So, what I am doing is blending the first texture with my lightmap. Then the second texture is blended inversely with the same lightmap. Then I''m blending the two together. (Just so you understand why, I''m making a globe image with a nightside and a dayside image on the same globe)

Now, I have this working, great! But this is just a simulation toward what I really want.

I also have this code:


  

m_app->m_glActiveTextureARB(GL_TEXTURE0_ARB);
glBindTexture(GL_TEXTURE_2D, m_bumpmap->m_id);
glEnable(GL_TEXTURE_2D);

//Bind normalisation cube map to texture unit 1

m_app->m_glActiveTextureARB(GL_TEXTURE1_ARB);
glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mp_cubemap->m_id);
//glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, normalisationCubeMap);

glEnable(GL_TEXTURE_CUBE_MAP_ARB);
m_app->m_glActiveTextureARB(GL_TEXTURE0_ARB);

//Set vertex arrays

glVertexPointer(3, GL_FLOAT, sizeof(Vertex), &m_sphere->verts[0].position);
glEnableClientState(GL_VERTEX_ARRAY);

//Send texture coords for normal map to unit 0

glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &m_sphere->verts[0].texCoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

//Send tangent space light vectors for normalisation to unit 1

m_app->m_glClientActiveTextureARB(GL_TEXTURE1_ARB);
glTexCoordPointer(3, GL_FLOAT, sizeof(Vertex), &m_sphere->verts[0].tangentSpaceLight);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
m_app->m_glClientActiveTextureARB(GL_TEXTURE0_ARB);

//Set up texture environment to do (tex0 dot tex1)*color

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);

m_app->m_glActiveTextureARB(GL_TEXTURE1_ARB);

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_DOT3_RGB_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB);

m_app->m_glActiveTextureARB(GL_TEXTURE0_ARB);

glDrawElements(GL_TRIANGLES, m_sphere->m_fsize * 3, GL_UNSIGNED_INT, m_sphere->indices);

//Disable textures

glDisable(GL_TEXTURE_2D);

m_app->m_glActiveTextureARB(GL_TEXTURE1_ARB);
glDisable(GL_TEXTURE_CUBE_MAP_ARB);
m_app->m_glActiveTextureARB(GL_TEXTURE0_ARB);

//disable vertex arrays

glDisableClientState(GL_VERTEX_ARRAY);

glDisableClientState(GL_TEXTURE_COORD_ARRAY);

m_app->m_glClientActiveTextureARB(GL_TEXTURE1_ARB);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
m_app->m_glClientActiveTextureARB(GL_TEXTURE0_ARB);

//Return to standard modulate texenv

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);


//Enable multiplicative blending

glBlendFunc(GL_DST_COLOR, GL_ZERO);
glEnable(GL_BLEND);


glBindTexture(GL_TEXTURE_2D, m_basemap->m_id);
glEnable(GL_TEXTURE_2D);

glVertexPointer(3, GL_FLOAT, sizeof(Vertex), &m_sphere->verts[0].position);
glEnableClientState(GL_VERTEX_ARRAY);

glNormalPointer(GL_FLOAT, sizeof(Vertex), &m_sphere->verts[0].normal);
glEnableClientState(GL_NORMAL_ARRAY);

glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &m_sphere->verts[0].texCoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

glDrawElements(GL_TRIANGLES, m_sphere->m_fsize * 3, GL_UNSIGNED_INT, m_sphere->indices);

//Disable texture

glDisable(GL_TEXTURE_2D);

//disable vertex arrays

glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);




Well, this gives me a bump map that is blended with my dayside texture.

That''s great too.

Now I want to use my bump map instead of the lightmap (holemap) in the first example.

So what I think I need to do is be able to do the glBlendFunc(GL_DST_COLOR, GL_ZERO); in the multitexture way. Do that twice like I do in the first example and blend those results.

PLEASE HELP :.(

Share this post


Link to post
Share on other sites
I don't have a huge amount of time now, so I'm going to have to be fairly quick.

the crossbar extension is used to allow you to use a texture from any texture unit for any stage in the multi-texture process. This is obviously very useful in some restricted situations. I think yours might be one of them. You don't need a tut on it, all you have to do is if the extension is in the extension string, then you can use TEXTUREn _ARB in glTexEnvi instead of GL_TEXTURE.


With this, for example, you could set up a nice base effect in the colour channels (say, a detail texture using add_signed), and in the alpha channel do a dot product of a normal map and a cube normalization map or colour info. The second texture unit could simply modulate them. Bingo, you have dot-product lit detail textured object in _2_ texture units. Although doing this with only 2 textures is tricky, but I think you should hopfully get the drift that it's really powerful what you can do.

basically crossbar allows you to sometimes cut a texture unit or sometimes two from the same effect. Just note that D3D doesn't have an equivalent (unless you delve into pixel shaders)

glBlendFunc(GL_DST_COLOR, GL_ZERO); is the same as GL_MODULATE blending.

| - Project-X - my mega project.. yup, still cracking along - | - adDeath - an ad blocker I made - | - email me - |

[edited by - RipTorn on March 7, 2003 2:00:46 AM]

Share this post


Link to post
Share on other sites