SDL openGL PNG transparency?

Started by
10 comments, last by saschaheylik 12 years ago
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)

JoeTest.png

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:

JoeTest2.png

Any help on getting them to be transparent without overlapping like in the top image would be appreciated, thanks!
Advertisement
Shouldn't it be [font=courier new,courier,monospace]SDL_SetAlpha(surface, [color=#ff0000]SDL_SRCALPHA, 0)[/font]? (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.

[color=#333333]Use that with (I think?), [font=courier new,courier,monospace]glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA).[/font]
Hmm, that does make sense actually, thanks for the tip!

Unfortunately I still get the same effect as the second one.
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.
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.

Pic4.png

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!

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?

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:

Joe.png

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.
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 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.
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.

This topic is closed to new replies.

Advertisement