ThatsGobbles's picture

Problems with understanding blending

Hi all, I'm having some trouble getting the effect I want in OpenTK with multiple textures. I have two (and eventually more) circular PNG images with alpha transparency, and I'm loading them as textures via the following code, which I saw as an example on a different forum post:

        public static bool CreateTexture(Bitmap img, bool generateMipmaps, out int textureID) {
            GL.GenTextures(1, out textureID);
            GL.BindTexture(TextureTarget.Texture2D, textureID);
            try {
                BitmapData data = img.LockBits(
                    new System.Drawing.Rectangle(0, 0, img.Width, img.Height),
                    ImageLockMode.ReadOnly,
                    System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba,
                    data.Width, data.Height,
                    0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
                img.UnlockBits(data);
            }
            catch (System.Exception e) {
                System.Console.WriteLine("Unable to convert texture.");
                System.Console.WriteLine(e);
                return false;
            }
 
            if(!generateMipmaps) {
                // We haven't uploaded mipmaps, so disable mipmapping (otherwise the texture will not appear).
                // On newer video cards, we can use GL.GenerateMipmaps() or GL.Ext.GenerateMipmaps() to create
                // mipmaps automatically. In that case, use TextureMinFilter.LinearMipmapLinear to enable them.
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
            }
            else {
                // Generate and enable mipmaps.
                GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear);
            }
 
            return true;
        }

However, when I try and draw the two textures out over each other, I'm getting weird issues with alpha transparency. As an example, here's my two sprite images (note the transparent BG):

http://twitpic.com/3lpqpr

I want to draw them like this:

http://twitpic.com/3lps0t

However, I'm getting this:

http://twitpic.com/3lpsft

If it's any help, here's my OnRenderFrame method:

        protected override void OnRenderFrame(FrameEventArgs e) {
            base.OnRenderFrame(e);
 
            GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
            GL.MatrixMode(MatrixMode.Modelview);
 
            GL.Enable(EnableCap.Texture2D);
            GL.Enable(EnableCap.Blend);
            GL.Enable(EnableCap.DepthTest);
            GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
 
            // Draw texture.
            GL.PushMatrix();
            float scale;
            Vector2 disp;
            Helpers.ScaleToFit(texW, texH, Width, Height, out scale, out disp);
 
            GL.BindTexture(TextureTarget.Texture2D, textTexHandle);
            GL.LoadIdentity();
            GL.Translate(disp.X, disp.Y, 0);
            GL.Scale(scale, scale, 0);
 
            GL.Begin(BeginMode.Quads);
                GL.TexCoord2(0, 1); GL.Vertex3(    0, HEIGHT, 0);
                GL.TexCoord2(1, 1); GL.Vertex3(WIDTH, HEIGHT, 0);
                GL.TexCoord2(1, 0); GL.Vertex3(WIDTH,      0, 0);
                GL.TexCoord2(0, 0); GL.Vertex3(    0,      0, 0);
            GL.End();
 
            GL.BindTexture(TextureTarget.Texture2D, texHandle);
            GL.LoadIdentity();
            GL.Translate(disp.X, disp.Y, 0);
            GL.Scale(scale, scale, 0);
 
            GL.Translate(transH, transV, 0);
 
            GL.Begin(BeginMode.Quads);
                GL.TexCoord2(0, 1); GL.Vertex3(   0, texH, 0);
                GL.TexCoord2(1, 1); GL.Vertex3(texW, texH, 0);
                GL.TexCoord2(1, 0); GL.Vertex3(texW,    0, 0);
                GL.TexCoord2(0, 0); GL.Vertex3(   0,    0, 0);
            GL.End();
 
            GL.PopMatrix();
 
            SwapBuffers();
        }

Thanks!


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
ThatsGobbles's picture

Anyone? I'm guessing that it has to do with the blending functions I'm using (SrcAlpha and OneMinusSrcAlpha), but I took that straight from the OpenGL Programming Guide. Not exactly sure what it could be.

the Fiddler's picture

Sanity check: use GetPixel to verify that your System.Drawing.Bitmap actually has alpha values once it's loaded in memory. The blending mode looks correct.

ThatsGobbles's picture

GetPixel does confirm that the pixels are transparent. The outer (0, 0) corner of the textures have alpha == 0. I'm thinking maybe it possibly might have to do with GL.Clear() or me missing a GL.Enable() somewhere? I'm setting GL.ClearColor in my OnLoad() to a solid black, and calling GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit) at the start of each OnRenderFrame().

c2woody's picture

The ClearColor shouldn't matter here. Also the initialization code looks fine to me, too.

What is generateMipmaps? Does the effect change if you force it one way or the other?

A few things to try:
use different z-values for the quads, as enabled depth testing creates strange effects for z-equal faces. Also see if GL.Disable(EnableCap.DepthTest); changes the effect then.

Assure that you don't overwrite some blending-related things, like put this somewhere in the drawing code:

                    GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int)All.Modulate);
                    GL.TexEnv(TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvColor, new Color4(0, 0, 0, 0));

and check a few options that may interfere the testing (use GL.Disable(EnableCap.Lighting); for example).

ThatsGobbles's picture

Thanks a ton woody, I tried your suggestions in order, and disabling depth testing did the trick!

As an aside, I generateMipmaps is a boolean I use to either generate/not generate the mipmap chain when creating a texture. Forcing it either way didn't change anything while I was testing it out.

c2woody's picture

Just be sure you have a *really* good reason to use any sort of blending because it almost always works completely different from what you expect. I'm just utilizing it to overlay a sort of cut-out image as last stage in the rendering process, with similar parameters you're using (thus depth testing is not relevant).

ThatsGobbles's picture

I think I may have understood the purpose of blending then, in that case. I was under the impression that enabling blending was needed to allow transparency? Or am I mistaken?

c2woody's picture

Yes but before being too happy about OpenGL having "some sort of transparency" be sure to read a lot about what it can do and what not. There are a lot of problems (like z-order relevance) that may render an approach useless.

ThatsGobbles's picture

I'll do that. Thanks Woody and Fiddler for the help. I guess I still have a lot to learn!

c2woody's picture

Hope you'll post nice pictures/examples of your experiments ;)