Multitexturing - Problems setting vertex color

I have two textures that I am attempting to blend together, in the demo application I am trying to set the vertex color of the primitive that I am drawing with ‘glColor4ub(255, 0, 0, 255);’ So the primitive should be red when being rendered.

The first texture is red, but the second texture is not and instead remains as full white (255, 255, 255). So I basically want that second texture to be red as the first one.

I’ve been looking into various ways to blend but all have failed and at this point I am stumped. I’ve also tried GL_MODULATE in place of GL_ADD but that instead makes the final result way too dark.

Here is the code to draw and display the multi-textured polygon:


void render( void )
{
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	
	glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
	glTranslatef( 0.0f, 0.0f, -4.0f );

	//
	// STAGE 0
	//

	glActiveTextureARB( GL_TEXTURE0_ARB );
	glColor4ub(255, 0, 0, 255);
	glBindTexture( GL_TEXTURE_2D, g_textureID_0 );

	//
	// STAGE 1
	//

	glActiveTextureARB( GL_TEXTURE1_ARB );
	glColor4ub(255, 0, 0, 255);


	glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD );

	glBindTexture( GL_TEXTURE_2D, g_textureID_1 );
	glEnable( GL_TEXTURE_2D );
	
	//
	// Render our quad with two sets of texture coordinates...
	//

	glBegin( GL_QUADS );
	{
		glMultiTexCoord2fARB( GL_TEXTURE0_ARB, 0.0f, 0.0f );
		glMultiTexCoord2fARB( GL_TEXTURE1_ARB, 0.0f, 0.0f );
		glVertex3f( -1.0f, -1.0f, 0.0f );

		glMultiTexCoord2fARB( GL_TEXTURE0_ARB, 0.0f, 1.0f );
		glMultiTexCoord2fARB( GL_TEXTURE1_ARB, 0.0f, 1.0f );
		glVertex3f( -1.0f, 1.0f, 0.0f );

		glMultiTexCoord2fARB( GL_TEXTURE0_ARB, 1.0f, 1.0f );
		glMultiTexCoord2fARB( GL_TEXTURE1_ARB, 1.0f, 1.0f );
		glVertex3f( 1.0f,  1.0f, 0.0f );

		glMultiTexCoord2fARB( GL_TEXTURE0_ARB, 1.0f, 0.0f );
		glMultiTexCoord2fARB( GL_TEXTURE1_ARB, 1.0f, 0.0f );
		glVertex3f( 1.0f, -1.0f, 0.0f );
	}
	glEnd();

	SwapBuffers( g_hDC );
}

Full link to the test application can be found here:
http://www.speedyshare.com/743514512.html

So below are the two textures that I am trying to blend together:

Texture 1:

Texture 2:

And here is the result:

After reading your code, I think some glTexEnv function call are missing to make multi-texturing work like you want. Look at the glTexEnv documentation in the SDK.

Here is a sample code that use multi-texturing to interpolate between one texture (TEXTURE0) and a constant color.

        glTexEnvfv(GL_TEXTURE_ENV,GL_TEXTURE_ENV_COLOR,this->constColor);
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);
glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_INTERPOLATE);
glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE0_RGB,GL_TEXTURE);
glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND0_RGB,GL_SRC_COLOR);
glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE1_RGB,GL_PREVIOUS);
glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND1_RGB,GL_SRC_COLOR);
glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE2_RGB,GL_CONSTANT);
glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND2_RGB,GL_SRC_ALPHA);

I’ve noticed you mentioned GL_SOURCE2_RGB and GL_OPERAND2_RGB in the mix. Does that mean I will need to setup three textures to achieve the desired effect?

No, I use only one texture unit (TEXTURE0) in my example, I forget to add before all glTexEnv call glActiveTexture(GL_TEXTURE0). So if your effect need two texture unit you have to do something like this:

setup for texture unit 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,texture0_id);
some glTexEnv() calls.

setup for texture unit 1
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE2D,texture1_id);
some glTexEnv calls.

If your card permit the use of vertex and fragment shaders, use it. This will avoid you to work with the not so easy fixed function multi-texturing.

I am using the code you mentioned which I call after the first and second texture units, but now the second texture unit won’t even show up. Also glColor4ub(255, 0, 0, 255); doesn’t seem to have no effect on the polygon at all now.

Even after looking at the docs for glTexEnv, I am still failing to understand how this works.


void render( void )
{
	float blah[4] = { 1.0f, 0.0f, 0.0f, 1.0f };	//Red

    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	
	glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
	glTranslatef( 0.0f, 0.0f, -4.0f );

	//
	// STAGE 0
	//

	glActiveTextureARB( GL_TEXTURE0_ARB );

        glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
	glTexEnvfv(GL_TEXTURE_ENV,GL_TEXTURE_ENV_COLOR, blah);

	glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);
	glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_INTERPOLATE);
	glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE0_RGB,GL_TEXTURE);
	glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND0_RGB,GL_SRC_COLOR);
	glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE1_RGB,GL_PREVIOUS);
	glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND1_RGB,GL_SRC_COLOR);
	glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE2_RGB,GL_CONSTANT);
	glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND2_RGB,GL_SRC_ALPHA);

	glBindTexture( GL_TEXTURE_2D, g_textureID_0 );

	//
	// STAGE 1
	//

	glActiveTextureARB( GL_TEXTURE1_ARB );



	glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
	glTexEnvfv(GL_TEXTURE_ENV,GL_TEXTURE_ENV_COLOR, blah);

	glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);
	glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_INTERPOLATE);
	glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE0_RGB,GL_TEXTURE);
	glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND0_RGB,GL_SRC_COLOR);
	glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE1_RGB,GL_PREVIOUS);
	glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND1_RGB,GL_SRC_COLOR);
	glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE2_RGB,GL_CONSTANT);
	glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND2_RGB,GL_SRC_ALPHA);


	glBindTexture( GL_TEXTURE_2D, g_textureID_1 );
	glEnable( GL_TEXTURE_2D );


	
	//
	// Render our quad with two sets of texture coordinates...
	//

	glBegin( GL_QUADS );
	{
		glColor4ub(255, 0, 0, 255);
		glMultiTexCoord2fARB( GL_TEXTURE0_ARB, 0.0f, 0.0f );
		glMultiTexCoord2fARB( GL_TEXTURE1_ARB, 0.0f, 0.0f );
		glVertex3f( -1.0f, -1.0f, 0.0f );

		glMultiTexCoord2fARB( GL_TEXTURE0_ARB, 0.0f, 1.0f );
		glMultiTexCoord2fARB( GL_TEXTURE1_ARB, 0.0f, 1.0f );
		glVertex3f( -1.0f, 1.0f, 0.0f );

		glMultiTexCoord2fARB( GL_TEXTURE0_ARB, 1.0f, 1.0f );
		glMultiTexCoord2fARB( GL_TEXTURE1_ARB, 1.0f, 1.0f );
		glVertex3f( 1.0f,  1.0f, 0.0f );

		glMultiTexCoord2fARB( GL_TEXTURE0_ARB, 1.0f, 0.0f );
		glMultiTexCoord2fARB( GL_TEXTURE1_ARB, 1.0f, 0.0f );
		glVertex3f( 1.0f, -1.0f, 0.0f );
	}
	glEnd();

	SwapBuffers( g_hDC );
}

Also glColor4ub(255, 0, 0, 255); doesn’t seem to have no effect on the polygon at all now.
glColor4ub(255, 0, 0, 255) have no effect because the source GL_SOURCE0 of the texture unit 0 is GL_TEXTURE not GL_PREVIOUS. For texture unit 0 the previous source is the incomming fragment. For texture unit 1 GL_PREVIOUS is the incoming fragment from texture unit 0.

Give me a couple of minutes and I will try to give you a sample code that will do something like that:
(color of the polygon)*(color from texture unit 0) * (color from texture unit 1).

Here the textures setup code:


glPixelStorei(GL_UNPACK_ALIGNMENT,1);
    glActiveTexture(GL_TEXTURE0);
    glGenTextures(1,&texID);
    glBindTexture(GL_TEXTURE_2D,texID);
    
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);
    glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_MODULATE);
    glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE0_RGB,GL_PREVIOUS);
    glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND0_RGB,GL_SRC_COLOR);
    glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE1_RGB,GL_TEXTURE);
    glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND1_RGB,GL_SRC_COLOR);

 glTexImage2D(GL_TEXTURE_2D,0,image->getInternalTextureFormat(),image->s(),
                 image->t(),0,image->getPixelFormat(),image->getDataType(),
                 image->data());  
  
glGenTextures(1,&texID2);
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D,texID2);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    
    glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);
    glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_MODULATE);
    glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE0_RGB,GL_PREVIOUS);
    glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND0_RGB,GL_SRC_COLOR);
    glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE1_RGB,GL_TEXTURE);
    glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND1_RGB,GL_SRC_COLOR);
    
    glTexImage2D(GL_TEXTURE_2D,0,image2->getInternalTextureFormat(),image2->s(),
                 image2->t(),0,image2->getPixelFormat(),image2->getDataType(),
                          image2->data());    
    

Here is the drawing code:


 glEnable(GL_TEXTURE_2D);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D,texID);
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D,texID2);
    glBegin(GL_QUADS);
    glColor4f(1.0,1.0,1.0,1.0);//Change this color at your will
    glMultiTexCoord2f(GL_TEXTURE0,0.0,0.0);
    glMultiTexCoord2f(GL_TEXTURE1,0.0,0.0); 
    glVertex3f(-1.0,-1.0,-5.0);
    glMultiTexCoord2f(GL_TEXTURE0,0.0,1.0);
    glMultiTexCoord2f(GL_TEXTURE1,0.0,1.0);
    glVertex3f(1.0,-1.0,-5.0);
    glMultiTexCoord2f(GL_TEXTURE0,1.0,1.0);
    glMultiTexCoord2f(GL_TEXTURE1,1.0,1.0);
    glVertex3f(1.0,1.0,-5.0);
    glMultiTexCoord2f(GL_TEXTURE0,1.0,0.0);
    glMultiTexCoord2f(GL_TEXTURE1,1.0,0.0);
    glVertex3f(-1.0,1.0,-5.0);
    glEnd();
    glDisable(GL_TEXTURE_2D);

Like I said that code will do (color of the quad)(color of the texture at texture unit 0)(color of the texture at texture unit 1)

That basically gave me the same effect that I got from the very beginning when I first toyed around with multitexturing. While the coloring is working, but the texture itself is so dark that the whole texture is almost pitch black.

I also tried increasing the modulation by x4 with:

‘glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, 4);’

but the texture still has a lot of dark spots which just isn’t easy on the eyes. If there’s no other solution, then I’ll just have to manually blit the two textures together to form one.

For texture unit 1 replace glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_MODULATE); with glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_ADD);

Edit: What kind of effect you want? It is something like this (polygon color)*(texture0 + texture1). If it’s that effect you want then you have to proceed like you write before, or use shaders.

Thats basically what I am going for. Its like taking one texture and then placing another texture (with 50% transparency/alpha) on top.

Also with glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_ADD); It basically produces that same effect that I had before where texture 0 is effected by polygon color and texture 1 is not.

It is possible to do (polygon color)*(texture0 + texture1) if your video card support GL_NV_texture_env_combine4 extension.

Here is the textures units setup:


//Texture unit 0
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
glActiveTexture(GL_TEXTURE0);
glGenTextures(1,&texID);
glBindTexture(GL_TEXTURE_2D,texID);    
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE4_NV);
glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_ZERO);
glTexImage2D(GL_TEXTURE_2D,0,image->getInternalTextureFormat(),image->s(),               image->t(),0,image->getPixelFormat(),image->getDataType(),
                 image->data());    

//Texture unit 1
glGenTextures(1,&texID2);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D,texID2);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE4_NV);
glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_ADD);
glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE0_RGB,GL_PRIMARY_COLOR);
glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND0_RGB,GL_SRC_COLOR);
glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE1_RGB,GL_TEXTURE0);
glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND1_RGB,GL_SRC_COLOR);
glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE2_RGB,GL_PRIMARY_COLOR);
glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND2_RGB,GL_SRC_COLOR);
glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE3_RGB_NV,GL_TEXTURE1);
glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND3_RGB_NV,GL_SRC_COLOR);
        glTexImage2D(GL_TEXTURE_2D,0,image2->getInternalTextureFormat(),image2->s(),                 image2->t(),0,image2->getPixelFormat(),image2->getDataType(),
                          image2->data());    
    

Edit: I forgot to add glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_ADD); for texture unit 1

If your video card do not support GL_NV_texture_env_combine4 but support GL_ARB_texture_env_crossbar and GL_ATI_texture_env_combine3. I think you can do something like this:


//texture unit 0
....
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);
glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_MODULATE);
glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE0_RGB,GL_TEXTURE);
glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND0_RGB,GL_SRC_COLOR);
glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE1_RGB,GL_PREVIOUS);
glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND1_RGB,GL_SRC_COLOR);
....


//texture unit 1
....
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);
glTexEnvf(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_MODULATE_ADD_ATI);
glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE0_RGB,GL_TEXTURE);
glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND0_RGB,GL_SRC_COLOR);
glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE1_RGB,GL_PREVIOUS);
glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND1_RGB,GL_SRC_COLOR);
glTexEnvf(GL_TEXTURE_ENV,GL_SOURCE2_RGB,GL_PRIMARY_COLOR);
glTexEnvf(GL_TEXTURE_ENV,GL_OPERAND2_RGB,GL_SRC_COLOR);


But I cannot test this code because my card don’t support both extensions.

Edit: After review, to be able to run this code you only need GL_ATI_texture_env_combine3 extension.

Excellent, that one works perfectly. Too bad there’s limits with what extensions supported by video cards…

Thanks for your help and patience :wink:

Just out of curiosity, is there other ways to achieve the arg0 * (arg1 + arg2) formula other than GL_ATI_texture_env_combine3?

Also, would GLSL (shaders) be able to achieve this?
I would prefer avoiding extensions that is not supported on all cards. If not then I’ll stick to with this and maybe play around with shaders for the time being.

I think the best way is to use GLSL shaders now. With GLSL shaders this should be very easy to do arg0 * (arg1 + arg2) in the fragment shader. I would like to use GLSL shaders but my video card is a NVidia TnT2. I think that I should buy a new computer soon. :slight_smile:

Edit: If you test which extension GL_NV_texture_env_combine4 and/or GL_ATI_texture_env_combine3 a graphic card support, you will support a lot of graphic cards. GL_NV_texture_env_combine4 is supported by NVidia TnT (1998) and up. GL_ATI_texture_env_combine3 is supported by ATI Radeon 7000 (1999) series and up, and NVidia Geforce 256 (1999) and up if I am not wrong. But this stuff use the fixed function pipeline that will be deprecated in the future.