Yet Another Blending Question.

Hi Everybody! :smiley:

Heres a slight variation of the common blending question.

Im working with 2D only, and need some simple colour descriminant transparancy. Thats is, anything on a texture that is of colour, say (1.0, 1.0, 1.0)RGB becomes transparent. Is this possible?

…And if so, who do I implement this? -Ive been looking over the glBlendFunc and its options, but a lot of the documentation is over my head, or just not applicable. My textures do not have an alpha channel…

Thank you!

Thats is, anything on a texture that is of colour, say (1.0, 1.0, 1.0)RGB becomes transparent. Is this possible?

Yes,you can convert the RGB texture to a RGBA texture.


 //Convert an RGB image to RGBA (GL_UNSIGNED_BYTE data type)
    for( j = 0, k = 0,l = 0  ; j < sizeY ; j++)
    {
      for( i = 0 ; i < sizeX ; i++)
      {
         //Transparent
         if( (rgb_image[k] == 255) && (repeat for green and blue component))
           {
             rgba_image[l++] = rgb_image[k++];
             rgba_image[l++] = rgb_image[k++];
             rgba_image[l++] = rgb_image[k++];
             rgba_image[l++] = 0;
           }
        else //opaque
        {
         rgba_image[l++] = rgb_image[k++];
         rgba_image[l++] = rgb_image[k++];
         rgba_image[l++] = rgb_image[k++];
         rgba_image[l++] = 255;
        }
    }
 }

Try with the following blending equation glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA). For texture wrap mode use GL_CLAMP_TO_EDGE for S and T.

If you see a slight white border around your sprites, come back here for ways to solve this.

Right-o, will try this now…

Thank you very much for the quick reply!! :slight_smile:

Hmmm, well I store my data as char, so that doesnt seem to work :s

– even with (char) type coercion

it should, GLubyte is basically char, if you can’t convert, then you have to make both of them the same type.

Okay, check mah code, and your right, works better now :slight_smile:

However, there still isnt any transparency :s


	/* reverse colours */
	for ( i=0; i< size; i+=3 )
	{
		temp = data[i];
		data[i] = data[i+2];
		data[i+2] = temp;
	}
	
	/* white - transparent conversion */
	for( i=0, l=0, k=0; i<globuiHeight; i ++ )
	{
		for( j=0; j<globuiWidth; j ++ )
		{
			if(( data[l] == (GLubyte)256 )&&( data[l+1] == (GLubyte)256 )&&( data[l+2] == (GLubyte)256 ))
			{
				dataRGBA[k++] = (GLubyte)data[l++];		//R
				dataRGBA[k++] = (GLubyte)data[l++];	//G
				dataRGBA[k++] = (GLubyte)data[l++];	//B
				dataRGBA[k++] = (GLubyte)0;			//A
			} else {
				dataRGBA[k++] = (GLubyte)data[l++];
				dataRGBA[k++] = (GLubyte)data[l++];
				dataRGBA[k++] = (GLubyte)data[l++];
				dataRGBA[k++] = (GLubyte)256;
			}
		}
	}

....

gluBuild2DMipmaps( GL_TEXTURE_2D, 4, globuiWidth, globuiHeight, GL_RGBA, GL_UNSIGNED_BYTE, dataRGBA );

Hope this makes it easier, where am I going wrong?

Thanks guys :slight_smile:

if(( data[l] == (GLubyte)256 )&&( data[l+1] == (GLubyte)256 )&&( data[l+2] == (GLubyte)256 ))

255… not 256. :slight_smile:

256 is a number on 9 bit.

Haha! what a basic mistake, yhea, cant belive I didnt spot that! :stuck_out_tongue:

Still no transparency though :frowning:

…If it did work, would I see the texure drawn before the transparent one? - in effect ‘behind it’, or just the colour of the primitive that textures bound to?

Atm, im just still seeing the white… :frowning:

Do you enable blending with glEnable(GL_BLEND)? Can you post some source code to see if your texture setting is right.

If it did work, would I see the texure drawn before the transparent one? - in effect ‘behind it’, or just the colour of the primitive that textures bound to?

See this thread for an example with transparency texture. Look at the screen shot.

a quick test to see if transparency and blending is working, set the color to (1,1,1,0.3), if it goes transparent then the blending mode works.
In that case it’s the whole creation of the texture that doesn’t.
My guess would be that the internal format (the second parameter in gluBuild2DMipmaps and third in glTexImage2D) is set to GL_RGB or 3, make sure it says GL_RGBA.

Hmm… Thanks for the links and color test advise. It seems that after attempting it, its the whole texture creating process that doesnt work! :s

Ive tried via extensive use of printf(); 's to get down to what im doing wrong, but everything seems to be working right, format loaded correctly, and all variables go to the right values, except this part.

Heres the code for my load image function, its quite long, but silly simple :stuck_out_tongue:


GLuint	globLoadImage( char* globsFileName, unsigned int globuiWidth, unsigned int globuiHeight, int globiTrans )
{
	/*Some nice var */
	FILE	*imageFile;
	GLubyte	*data, *dataRGBA;			/* Holds data, as we load it. &One for transparency	*/
	unsigned long size, i, j, k, l;		/* For da claculizzle								*/
    unsigned short int planes;          /* number of planes in image (must be 1)			*/
    unsigned short int bpp;             /* number of bits per pixel (must be 24)			*/
	unsigned int	chkDimension;		/* Var to check dimensions & make sure standard		*/
    char temp;                          /* temporary color storage for bgr-rgb conversion.	*/
	GLuint	texture;					/* holds the texture ID that we send back.			*/

	/* does file exist? */
	if(( imageFile = fopen( globsFileName, "rb" )) == NULL )
	{
		globLog( "[globLoadImage@globEng]: File Not Found! %s 
\
							Does it exist?
", globsFileName );
		return FALSE; //Cant go any further tbh
	}
	
	/* get width height from header, seek to. */
	fseek( imageFile, 18, SEEK_CUR );
	
	if(( i = fread( &chkDimension, 4, 1, imageFile )) != TRUE )
	{
		globLog( "[globLoadImage@globEng]: Error reading width of: %s 
\
							File could be corrupt.
", globsFileName );
		return FALSE;
	}
	if( chkDimension != globuiWidth )
	{
		globLog( "[globLoadImage@globEng]: Wrong image width: is %d, should be %u; from %s
", 
			chkDimension, globuiWidth, globsFileName );
		
		return FALSE;
	}
	
	if(( i = fread( &chkDimension, 4, 1, imageFile )) != TRUE )
	{
		globLog( "[globLoadImage@globEng]: Error reading height of: %s 
\
							File could be corrupt.
", globsFileName );
		return FALSE;
	}
	if( chkDimension != globuiHeight )
	{
		globLog( "[globLoadImage@globEng]: Wrong image height: is %d, should be %u; from %s
", 
			chkDimension, globuiHeight, globsFileName );
		
		return FALSE;
	}
	printf( "Dimensions: %ux%u
", globuiWidth, globuiHeight );
	
	/* Get the # planes from file */
	if(( i = fread( &planes, 2, 1, imageFile )) != TRUE)
	{
		globLog( "[globLoadImage@globEng]: Unable to read #planes from: %s 
\
							File could be corrupt.
", globsFileName );
		return FALSE;
	}
	if( planes != 1 )		/* check for errors */
	{
		globLog( "[globLoadImage@globEng]: Planes not 1 in: %s", globsFileName );
		return FALSE;
	}
	
	/* And now bbp data */
	if(( i = fread( &bpp, 2, 1, imageFile )) != TRUE )
	{
		globLog( "[globLoadImage@globEng]: Could not read bpp from %s
\
							File could be corrupt.", globsFileName );
		return FALSE;
	}
	if( bpp != 24 )
	{
		globLog( "[globLoadImage@globEng]: Invalid bpp (!24) in: %s
\
							File could be corrupt.", globsFileName );
		return FALSE;
	}

	/* Get to the data, allocate memory and load :) */
	fseek( imageFile, 24, SEEK_CUR );

	/* Calculate image size, */
	size = globuiWidth * globuiHeight * (bpp/8);
	data = ( GLubyte* ) malloc( size );
	i = globuiWidth * globuiHeight * (32/8);
	dataRGBA = ( GLubyte* ) malloc( i );
	
	printf( "bpp: %d bits or %d bytes, size: %d 
", bpp, bpp/8, size );
	if(( data == NULL )||( dataRGBA == NULL ))		//Has it worked?
	{
		globLog( "[globLoadImage@globEng]: Could not allocate memory for image.
" );
		return FALSE;
	}

    if (( i = fread( data, size, 1, imageFile )) != 1 ) 
	{
		globLog( "[globLoadImage@globEng]: Error reading image data from %s.
", globsFileName );
		return FALSE;
    }

	/* reverse colours */
	for ( i=0; i< size; i+=3 )
	{
		temp = data[i];
		data[i] = data[i+2];
		data[i+2] = temp;
	}
	
	if( globiTrans ) /* If transparency conversion, white == transparent */
	{
		for( i=0, l=0, k=0; i<globuiHeight; i++ )
		{
			for( j=0; j<globuiWidth; j++ )
			{
				if(( data[l] > 200 )&&( data[l+1] > 200 )&&( data[l+2] > 200 ))
				{
					printf( " :: %lu, %lu, %lu, %lu", i, j, k, l );
					dataRGBA[k++] = data[l++];	//R
					dataRGBA[k++] = data[l++];	//G
					dataRGBA[k++] = data[l++];	//B
					dataRGBA[k++] = 0;			//A
				} else {
					dataRGBA[k++] = data[l++];
					dataRGBA[k++] = data[l++];
					dataRGBA[k++] = data[l++];
					dataRGBA[k++] = 255;
				}
			}
		}
	} else { /* Otherwise, build RGBA image anyway, but full alpha ;P */
		for( i=0, l=0, k=0; i<globuiHeight; i++ )
		{
			for( j=0; j<globuiWidth; j++ )
			{
				dataRGBA[k++] = data[l++];
				dataRGBA[k++] = data[l++];
				dataRGBA[k++] = data[l++];
				dataRGBA[k++] = 255;
			}
		}
	}

    /*
	 * And now convert to GL texture, straight away
	 */
	glGenTextures( 1, &texture );
	glBindTexture( GL_TEXTURE_2D, texture );
	
	/* Set up environement var, tweak these, want white == transparent I say :D */
	glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );

	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );

	/* And now, finally build it */
	gluBuild2DMipmaps( GL_TEXTURE_2D, 4, globuiWidth, globuiHeight, GL_RGBA, GL_UNSIGNED_BYTE, dataRGBA );
	//glTexImage2D( GL_TEXTURE_2D, 0, 4, globuiWidth, globuiHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, dataRGBA );
	
	free( data );
	free( dataRGBA );
	
	return texture;
}

but everything seems to be working right, format loaded correctly, and all variables go to the right values, except this part.

I have tried your code and it work well. I have made minor modification like changing min and mag filter mode to take advantage of mipmap.

Try with the following drawing function:


GLvoid display(GLvoid)
{
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
   
  glEnable(GL_BLEND);
  glBlendFunc(GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D,texID);
  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_REPLACE);
  glBegin(GL_TRIANGLE_STRIP);
  glTexCoord2f(0.0,0.0);
  glVertex4f(-1.0,-1.0,0.0,1.0);
  glTexCoord2f(1.0,0.0);
  glVertex4f(1.0,-1.0,0.0,1.0);
  glTexCoord2f(0.0,1.0);
  glVertex4f(-1.0,1.0,0.0,1.0);
  glTexCoord2f(1.0,1.0);
  glVertex4f(1.0,1.0,0.0,1.0);
  glEnd();
  
  glDisable(GL_TEXTURE_2D);
  glDisable(GL_BLEND);
  glutSwapBuffers();
}

Hehe :smiley:

Thanks, I tried it, but to no avail, however, then after Ctrl-Z ing back to original code I got it working! :slight_smile:

Not sure how really… The code though is exactly the same as my original! heh :smiley:

Thank you anyhow!