Jump to content

  • Log In with Google      Sign In   
  • Create Account


SDL openGL PNG transparency?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
11 replies to this topic

#1 OmarShehata   Members   -  Reputation: 198

Like
0Likes
Like

Posted 28 February 2012 - 10:27 PM

Ok so I've been fiddling with this for a while, and while I came across some cool effects, I still haven't managed to achieve what I'm trying to do.

Basically, I just want to have my PNG's transparency enabled.

This is what I have set in an attempt to make it work:

SDL_SetAlpha(surface,0,0);
glEnable (GL_BLEND);
    glBlendFunc(GL_ONE, GL_ONE);

But this just makes the images overlap like this: (Where anything black is considered transparent)

Posted Image

The rectangle doesn't have any transparent parts in its original PNG, while the blue character has transparency around the sides.

I also tried:

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

Which was suggested here: http://www.opengl.org/sdk/docs/man/xhtml/glBlendFunc.xml

But that just gives black in transparent areas:

Posted Image

Any help on getting them to be transparent without overlapping like in the top image would be appreciated, thanks!

Sponsor:

#2 Servant of the Lord   Crossbones+   -  Reputation: 16681

Like
1Likes
Like

Posted 28 February 2012 - 11:24 PM

Shouldn't it be SDL_SetAlpha(surface, SDL_SRCALPHA, 0)? (Note: I have never used SDL with OpenGL)
Otherwise, you're saying you want to ignore the SDL_Surface's alpha, and use a per-surface alpha (the third perimeter) instead of the per-pixel alpha.

Use that with (I think?), glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA).

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.

[Fly with me on Twitter] [Google+] [My broken website]

All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.                                                                                                                                                       [Need free cloud storage? I personally like DropBox]

Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal


#3 OmarShehata   Members   -  Reputation: 198

Like
0Likes
Like

Posted 29 February 2012 - 09:33 AM

Hmm, that does make sense actually, thanks for the tip!

Unfortunately I still get the same effect as the second one.

#4 Brother Bob   Moderators   -  Reputation: 7740

Like
1Likes
Like

Posted 29 February 2012 - 09:45 AM

Looks like depth testing. First sprite is drawn and fills the depth buffer; the second sprite is drawn at the same Z and thus fails the depth test in parts where the sprites overlap.

This is the classical problem with transparency; your objects have to be drawn in back-to-front order, because that blending function is drawing order dependent and the back-to-front order is the only way to achieve the correct transparency effect. Of course, if you draw the two sprites a the same Z, then both effectively overlap the other, and none of the drawing orders are sufficient.

Disable the depth test to eliminate the overlap problem though, but you have to ensure that layers are drawn in the correct order (for example; background, sprites, and finally the foreground) to achieve correct transparency though.

#5 OmarShehata   Members   -  Reputation: 198

Like
0Likes
Like

Posted 29 February 2012 - 10:30 PM

Thanks for that note Brother Bob!

Ok, so I've disabled depth test first using glDepthFunc(GL_NEVER); then tried glDisable(GL_DEPTH_TEST);

Are these function equivalent or do they do different things?

Now my sprites get drawn in the order I draw them, with the first one drawn appearing at the back. Ok, seems good.

Still doesn't work. I try using alpha test, which is supposed to simply not draw the transparent pixels:

glEnable(GL_ALPHA_TEST) ;
glAlphaFunc(GL_GREATER, 0.1f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//After loading image:
SDL_SetAlpha(surface,SDL_SRCALPHA,0);
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
//I bind the texture
glColor4f(1,1,1,1);
//I start drawing the square

And again, no alpha, in fact, the image is rendered very strangely.

Posted Image

Original image on the right, how it's rendered on the left (and you can see there's still no transparency)

Now if I set the blendFunc to GL_ONE,GL_ONE the red parts of the image become translucent while the white is solid.

I feel pretty lost here. I'd like to do some in depth debugging, but I'm not sure how to go about that.

Is there any chance that the image I'm loading is getting loaded without transparency? Can I ensure that there are transparent pixels? Why doesn't the ALPHA_TEST work? Whether I add it or remove it, it doesn't seem to have any effect.

I really appreciate the help so far, and thank you for your time!

#6 Brother Bob   Moderators   -  Reputation: 7740

Like
1Likes
Like

Posted 01 March 2012 - 05:50 AM

Ok, so I've disabled depth test first using glDepthFunc(GL_NEVER); then tried glDisable(GL_DEPTH_TEST);

The two are not the same. The first is only a comparison function that determines what to draw and what is occluded. The latter disables the depth buffer mechanism entirely. The main difference is that, if you only set depth function, then the depth buffer is still filled with the Z-values of whatever you draw.

Do you really need the depth buffer at all? Drawing the layers in a back-to-front order seems to be more than enough, and there appears to be no need for a depth buffer in the first place.

Is there any chance that the image I'm loading is getting loaded without transparency? Can I ensure that there are transparent pixels? Why doesn't the ALPHA_TEST work? Whether I add it or remove it, it doesn't seem to have any effect.

Looks like your image is loaded either without an alpha channel or as a fully opaque image. Are you sure that the image is saved with a proper alpha channel in the first place?

#7 OmarShehata   Members   -  Reputation: 198

Like
0Likes
Like

Posted 01 March 2012 - 07:01 AM

Do you really need the depth buffer at all? Drawing the layers in a back-to-front order seems to be more than enough, and there appears to be no need for a depth buffer in the first place.


Yeah, I was trying to disable the depth buffer entirely and handle the depths myself.

Looks like your image is loaded either without an alpha channel or as a fully opaque image. Are you sure that the image is saved with a proper alpha channel in the first place?


That's what I'm starting to doubt, the actual image. How can I be sure that is has the proper alpha channels and all that? Is there something I need to adjust with SDL when loading the image? (Like maybe how I need to change the format of the image to 32 bit if the screen is 32 bit)

This is the actual image:

Posted Image

I do think this could be it. Because I kept playing around with
glAlphaFunc(GL_GREATER, 0.1f);

And setting it to any values from 0.1 to 1 doesn't have any effect, setting it to 0 makes nothing get drawn. So the function itself is working I think.

#8 Brother Bob   Moderators   -  Reputation: 7740

Like
0Likes
Like

Posted 01 March 2012 - 07:47 AM

I need to see more of the relevant code. The image itself has a correct alpha channel so the problem is not there at least. How do you draw the sprites? Using SDL, or using OpenGL as a texture, or something else? How do you load the images and/or textures?

#9 OmarShehata   Members   -  Reputation: 198

Like
0Likes
Like

Posted 01 March 2012 - 07:57 AM

I need to see more of the relevant code. The image itself has a correct alpha channel so the problem is not there at least. How do you draw the sprites? Using SDL, or using OpenGL as a texture, or something else? How do you load the images and/or textures?


I'm importing the graphic as an SDL_Surface, then rendering it as an openGL texture. I've got a GLShapes class which has all my drawing code, although it's a quite messy because of all the experimentation I've been doing over the past few days:

#include "Main.h"
using namespace std;
class GLshapes {
public:
void DrawBox(float X,float Y,int width,int height, float angle,string FilePath,float Z){
	glDisable(GL_DEPTH_TEST);
	glDepthFunc(GL_NEVER); //Remvoes depth sorting
   // glEnable (GL_DEPTH_TEST); //Adds depth sorting
	// Set the OpenGL state after creating the context with SDL_SetVideoMod

glEnable( GL_TEXTURE_2D ); // Need this to display a texture

////
if(Z == 1){
	 glEnable(GL_ALPHA_TEST) ;
glAlphaFunc(GL_GREATER, 0.1f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
//////
	glLoadIdentity();
	// Load the OpenGL texture
	GLuint texture; // Texture object handle
	SDL_Surface *surface; // Gives us the information to make the texture
	if ( (surface = IMG_Load(FilePath.c_str()) )) {
		// Check that the image's width is a power of 2
		if ( (surface->w & (surface->w - 1)) != 0 ) {
		   // printf("warning: image.bmp's width is not a power of 2\n");
		}
		// Also check if the height is a power of 2
		if ( (surface->h & (surface->h - 1)) != 0 ) {
			//printf("warning: image.bmp's height is not a power of 2\n");
		}
		//surface = SDL_DisplayFormat(surface);
		// Have OpenGL generate a texture object handle for us
		SDL_SetAlpha(surface,SDL_SRCALPHA,0);
		/*SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );*/

		glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);

		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, 3, (surface->w), surface->h, 0,
					 GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels );


	}
	// Free the SDL_Surface only if it was successfully created
	if ( surface ) {
		SDL_FreeSurface( surface );
	}
	// Clear the screen before drawing
	  // Bind the texture to which subsequent calls refer to
	//glBindTexture( GL_TEXTURE_2D, texture );
glColor4f(1,1,1,1);
	glTranslatef(X,Y,0);
	glRotatef(angle,0,0,1.0);
	glScalef(1.0, -1.0, 1.0);
	glBegin( GL_QUADS );

		// Top-left vertex (corner)
		glTexCoord2i( 0.0, 0.0 );
		glVertex3f( -width/2, -height/2, 0 );
		// Bottom-left vertex (corner)
		glTexCoord2i( 1.0, 0.0 );
		glVertex3f( -width/2, height/2, 0 );
		// Bottom-right vertex (corner)
		glTexCoord2i( 1.0, 1.0 );
		glVertex3f( width/2, height/2, 0 );
		// Top-right vertex (corner)
		glTexCoord2i( 0.0, 1.0 );
		glVertex3f( width/2, -height/2, 0 );

	glEnd();
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
   glDeleteTextures( 1, &texture );
   glDisable(GL_ALPHA_TEST);

}
};


Note: if you're wondering, "Z" is just an integer which I was using to toggle the alpha code there for testing.

#10 Brother Bob   Moderators   -  Reputation: 7740

Like
1Likes
Like

Posted 01 March 2012 - 08:01 AM

You're creating an RGB texture, so the texture doesn't even have an alpha channel. Check the third parameter to glTexImage; you're telling OpenGL that you only want three color components, the R, the G and the B channels, and to throw away the alpha channel. Pass GL_RGBA instead to make it an RGBA texture.

But on another note; don't create the texture all the time you draw like that. Create it once when you start the program, and then just save the texture ID and bind it every frame instead.

#11 OmarShehata   Members   -  Reputation: 198

Like
0Likes
Like

Posted 01 March 2012 - 08:27 AM

You're creating an RGB texture, so the texture doesn't even have an alpha channel. Check the third parameter to glTexImage; you're telling OpenGL that you only want three color components, the R, the G and the B channels, and to throw away the alpha channel. Pass GL_RGBA instead to make it an RGBA texture.

But on another note; don't create the texture all the time you draw like that. Create it once when you start the program, and then just save the texture ID and bind it every frame instead.


Oh my god...you, my good, sir, are brilliant! It works!!

Posted Image

It's so beautiful!

You have also saved me *another* great deal of trouble and time, because I knew the way I was adding graphics was lagging immensely, but didn't know why.

I cannot thank you enough Brother Bob!

I guess I should have read the parameters more carefully when implementing the functions.

#12 saschaheylik   Members   -  Reputation: 100

Like
0Likes
Like

Posted 30 March 2012 - 07:41 PM

Hi,

found this through google since I had the same problem. Here's the stand-alone solution for those who are still looking for it.

#include <SDL/SDL.h>
#include <SDL/SDL_opengl.h>
GLuint SDLOAT::Graphics::surfaceToTexture(SDL_Surface* surface)
{
	GLuint texture;   // This is a handle to our texture object
	GLenum texture_format;
	GLint  nOfColors;
	if (surface)
	{
		// Check that the image's width is a power of 2
		if ( (surface->w & (surface->w - 1)) != 0 )
		{
			printf("warning: image width is not a power of 2\n");
		}
		// Also check if the height is a power of 2
		if ( (surface->h & (surface->h - 1)) != 0 )
		{
			printf("warning: image height is not a power of 2\n");
		}
		// get the number of channels in the SDL surface
		nOfColors = surface->format->BytesPerPixel;
		if (nOfColors == 4)	 // contains an alpha channel
		{
			printf("Alpha: yes");
			if (surface->format->Rmask == 0x000000ff)
				texture_format = GL_RGBA;
			else
				texture_format = GL_BGRA;
		}
		else if (nOfColors == 3)	   // no alpha channel
		{
			printf("Alpha: no");
			if (surface->format->Rmask == 0x000000ff)
				texture_format = GL_RGB;
			else
				texture_format = GL_BGR;
		}
		else
		{
			printf("warning: the image is not truecolor..  this will probably break\n");
			// this error should not go unhandled
		}


		//Needed for 2d textures
		glEnable(GL_TEXTURE_2D);

		//Needed for transparency
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glEnable(GL_BLEND);
		glGenTextures( 1, &texture );
		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 );
	}
	else
	{
		printf("SDL could not load image: %s\n", SDL_GetError());
	}
	if ( surface )
	{
		SDL_FreeSurface( surface );
	}
	return texture;
}





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS