OpenGL alpha blending oddities

Started by
2 comments, last by J2902 15 years, 1 month ago
I'm working on a project with a friend and we are using SDL with OpenGL, and we also have alpha blending. Now, alpha blending is giving us a few oddities, and here is a link to how it normally looks. http://img249.imageshack.us/img249/5103/normal.png Sometimes, however, it transforms into this... http://img249.imageshack.us/img249/9671/strange.png When the program really hates me, it does this -- http://img256.imageshack.us/img256/4835/strange2.png So, any ideas as to why its doing this? ------------- I understand that rendering order is important: the screen is rendered as such: (grid then selections then UI then units -- see code below if this was confusing)

void GameScreen::render()
{
        grid.Draw();

	if((draw_selection))
	{
		// If we are not in the panel's plane, then don't draw the selection box
		if(!UI.CursorIsInPanels(MouseOffsetsScreen.x, MouseOffsetsScreen.y))
			DrawPrimitives->DrawSquare(selection_startX - ClipPlane->GetX(), selection_startY - ClipPlane->GetY(), selection_endX - ClipPlane->GetX(), selection_endY - ClipPlane->GetY(), blue);

		for(int i = 0; i < characters.size(); i++)
			if(characters->Intersects(GetRect(selection_startX, selection_startY, selection_endX, selection_endY)))
				characters->DrawRect();
	}

        glDepthMask(GL_FALSE);
	RenderSelections();

	UI.DrawTrans();
	overlay.DrawTrans();
	soundGUI.DrawTrans();
	aNavGraph.DisplayEdges();
	DrawPrimitives->DrawSquare(10, 555, 120, 590, black, 1.0f);
	
	soundGUI.DrawOpaq();
	overlay.DrawOpaq();
	UI.DrawOpac();

	glDepthMask(GL_TRUE);

    //Calculate the frames per second and create the string
	TextDisplay->DisplayMessage("FPS: ", red, 20, 560, float(FONT_SIZE_MEDIUM));
	TextDisplay->DisplayMessage(fpsCaption, red, 80, 560, float(FONT_SIZE_MEDIUM));

	if(fpsCounter.get_ticks() > 150)
	{
		
		_itoa_s(int(fpsFrame / (fpsCounter.get_ticks() / 1000.f)), fpsCaption, 10);
		fpsCounter.start();
		fpsFrame = 0;
		
	}

	fpsFrame++;

	RenderEntities();
}

Here is how the grid is rendered

void Grid::Draw()
{
	
	for(int x = 0; x < MAP_WIDTH; x++)
		for(int y = 0; y < MAP_HEIGHT; y++)
		{
			Entity::ResetZLevel();
			for(int i = 0; i < NUMBER_OF_LAYERS; ++i)
			{

			        if(!gridButtons[x][y].IsIgnoredTile())
				       gridButtons[x][y].applySurface();

				

			        if(gridButtons[x][y].GetDrawBox())
				       gridButtons[x][y].DrawBox();

				
		}
				
	}

	
}

The DrawTrans // RenderSelection functions just call this function:

void GLPrimitives::DrawSquare(int x1, int y1, int x2, int y2, OGL_Color color)
{
	glColor4f(color.r, color.g, color.b, color.a);
	SDL_Rect aRect = GetRect(x1, y1, x2, y2);

	glBegin(GL_QUADS);
		glVertex3f( GLfloat(aRect.x), GLfloat(aRect.y), 1.0f );
		glVertex3f( GLfloat(aRect.x + aRect.w), GLfloat(aRect.y), 1.0f );
		glVertex3f( GLfloat(aRect.x + aRect.w), GLfloat(aRect.y + aRect.h), 1.0f );
		glVertex3f( GLfloat(aRect.x), GLfloat(aRect.y + aRect.h), 1.0f );
	glEnd();
}


The RenderEntities function just calls the applySurface function


void Entity::applySurface()
{

        if(imageID == ignoredImage) // optimization; don't draw something that isn't going to show up!
                return;                                


	SDL_Rect aRect(Rect);

        // Zooming in / out
	aRect.x *= m_scaler;
	aRect.y *= m_scaler;
	aRect.w *= m_scaler;
	aRect.h *= m_scaler;

	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

	if(ClipPlane->IsInPlane(aRect))
	{
	        glScalef(m_scaler, m_scaler, 1.0f);

	        glTranslatef(Rect.x - ClipPlane->GetX(), Rect.y - ClipPlane->GetY(), m_z);
		glCallList(m_displayLists[imageID]);
		glLoadIdentity();
	}
}

Here is the texture loading function (includes glCallList(...) marked with a big ----------------- comment)


void Entity::Load_Image(const char* filename)
{

	// ... big or small endian code commented out
	
	// Load in the image from the filename
	SDL_Surface *orig;
	orig = IMG_Load(filename);
	if(orig == NULL)
	{
		assert("Texture not correctly loaded" && false);
	}

	SDL_Surface* paddedOrig = SDL_CreateRGBSurface(SDL_SWSURFACE, unsignedNextPowerOfTwo(orig->w), unsignedNextPowerOfTwo(orig->h), WINDOW_BPP,
		RGBAFormat.Rmask, RGBAFormat.Gmask, RGBAFormat.Bmask, RGBAFormat.Amask);

	SDL_Surface *surface;
	if(orig->w != unsignedNextPowerOfTwo(orig->w) || orig->h != unsignedNextPowerOfTwo(orig->h))
	{
		SDL_BlitSurface(orig, NULL, paddedOrig, NULL);
		surface = SDL_ConvertSurface(paddedOrig, &RGBAFormat, SDL_SWSURFACE);
	}
	else 
		surface = SDL_ConvertSurface(orig, &RGBAFormat, SDL_SWSURFACE);

	// Convert the surface to a format readable by openGL
	m_images_sizes.resize(m_images_sizes.size() + 1);
	m_images_sizes[m_images_sizes.size() - 1].h = paddedOrig->h;
	m_images_sizes[m_images_sizes.size() - 1].w = paddedOrig->w;

	SDL_FreeSurface(orig);
	SDL_FreeSurface(paddedOrig);

	// get the number of channels in the SDL surface
    nOfColors = surface->format->BytesPerPixel;
    if (nOfColors == 4)     // contains an alpha channel
    {
            if (surface->format->Rmask == 0x000000ff)
                    texture_format = GL_RGBA;
            else
                    texture_format = GL_BGRA;
    } else if (nOfColors == 3)     // no alpha channel
    {
            if (surface->format->Rmask == 0x000000ff)
                    texture_format = GL_RGB;
            else
                    texture_format = GL_BGR;
    } else {
            assert("Loaded image is not truecolor" && false);
    }

	// Have OpenGL generate a texture object handle for us
	glGenTextures( 1, &texture );
 
	// Bind the texture object
	glBindTexture( GL_TEXTURE_2D, texture );
 
	// Set the texture's stretching properties
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
 
	// Edit the texture object's image data using the information SDL_Surface gives us
	glTexImage2D( GL_TEXTURE_2D, 0, nOfColors, surface->w, surface->h, 0,
                      texture_format, GL_UNSIGNED_BYTE, surface->pixels );



	// Free memory and return the texture
	SDL_FreeSurface(surface);

    m_images.push_back(texture);


	// Increase display list size
	m_displayLists.resize(m_displayLists.size() + 1);
	m_displayLists[m_displayLists.size() - 1] = glGenLists(1);


        /* ---------------------------------------------------------------------- */
	/* Build the list ------------------------------------------------------- */
        /* ---------------------------------------------------------------------- */
	glNewList(m_displayLists[m_displayLists.size() - 1], GL_COMPILE);
	
		// Set color to (nothing)
		glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

		// Bind the texture
		glBindTexture(GL_TEXTURE_2D, texture);


		SDL_Rect aRect;
		aRect.x = 0;
		aRect.y = 0;

		aRect.x = (aRect.x - ClipPlane->GetX());
		aRect.y = (aRect.y - ClipPlane->GetY());
		aRect.w = m_images_sizes[m_images_sizes.size() - 1].w;
		aRect.h = m_images_sizes[m_images_sizes.size() - 1].h;


		glBegin(GL_QUADS);
			//Top-left vertex (corner)
			glTexCoord2i( 0, 0 );
			glVertex3f( aRect.x, aRect.y, 0.0f );
				
			//Bottom-left vertex (corner)
			glTexCoord2i( 1, 0 );
			glVertex3f( GLfloat(aRect.x + aRect.w), GLfloat(aRect.y), 0.0f );
				
			//Bottom-right vertex (corner)
			glTexCoord2i( 1, 1 );
			glVertex3f( GLfloat(aRect.x + aRect.w), GLfloat(aRect.y + aRect.h), 0.0f );
				
			//Top-right vertex (corner)
			glTexCoord2i( 0, 1 );
		        glVertex3f( GLfloat(aRect.x), GLfloat(aRect.y + aRect.h), 0.0f );
	        glEnd();
	glEndList();
}

Here is how I have set up OpenGL


void initGL()
{

    glClearColor( 0, 0, 0, 1 );

    glMatrixMode( GL_PROJECTION );
        glPushMatrix();
    glLoadIdentity();

    glOrtho( 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0.0f, -1.0f, 2.0f );

    glMatrixMode( GL_MODELVIEW );
	glPushMatrix();
    glLoadIdentity();

    glEnable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
    glFrontFace(GL_CW);
    glEnable(GL_ALPHA_TEST);
    glEnable(GL_TEXTURE_ENV);

}


Sorry for the long post; hopefully you all can help me solve this rather obnoxious issue. Thanks.
Advertisement
Lovely, this little piece didn't get posted.

Here is how I have set up OpenGL
void initGL(){    glClearColor( 0, 0, 0, 1 );    glMatrixMode( GL_PROJECTION );        glPushMatrix();    glLoadIdentity();    glOrtho( 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0.0f, -1.0f, 2.0f );    glMatrixMode( GL_MODELVIEW );	glPushMatrix();    glLoadIdentity();    glEnable(GL_TEXTURE_2D);    glEnable(GL_BLEND);    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);    glFrontFace(GL_CW);    glEnable(GL_ALPHA_TEST);    glEnable(GL_TEXTURE_ENV);}


Again, thanks.
Try changing the values of the alpha func... this may help

gl.glAlphaFunc ( GL.GL_GREATER, 0.2f ) ;
You may change this values till you remove the background.

Also... don't forget to sort your objects so they are draw in the right order (the dragons)
I tried doing glAlphaFunc(GL_GREATER, 0.4f);

Here is what I found:
The alpha objects still darken
When the objects would normally really lighten up they actually disappear

Can you explain what you mean by

"You may change this values till you remove the background."

I understood that glAlphaFunc simply doesn't draw alpha below the given threshold?

Oh -- changing the drawing order so that the Dragons are drawn before the UI causes none of the alpha (aka primitives) in the UI to be drawn.

Any help is appreciated -- thanks.

This topic is closed to new replies.

Advertisement