Hello Guest

Blending / Transparency Problems

  • 7 Replies
  • 14770 Views
Blending / Transparency Problems
« on: October 13, 2011, 12:51:12 »
Hi everyone

I tried to draw a background and a cursor (both images). The background should be opaque and the cursor should have onla full transparent and full opaque pixels.
When I enable blending, it gets rendered 50% transparent on opaque pixels and transparent on transparent pixels.
When I disable blending, it gets rendered 100% opaque on opaque pixels and opaque and black on transparent pixels. -.-
I was experimenting with the glBlendFunc(), but I didn't get what I'm looking for.
I also Googled and searched in this forum, but I didn't get rid of my problem.
Has anyone an idea what I'm doing wrong?

Thanks in advance
Molt
« Last Edit: October 13, 2011, 12:53:56 by Molt »

Re: Blending / Transparency Problems
« Reply #1 on: October 13, 2011, 18:13:42 »
Still unsolved.
Here's some code I use (I use TextureHandler.java and a modified version of Texture.java from the Space Invaders Sample):
Code: [Select]
// Added in Texture.java
// Where the picture actually gets drawn
public void drawQuad(int x, int y, double factorX, double factorY)
{
drawQuad(x, y, 0, factorX, factorY);
}

public void drawQuad(int x, int y, int z, double factorX, double factorY)
{
bind();
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex3f(x, y, z);
glTexCoord2f(0, getHeight());
glVertex3f(x, y + (int)Math.round(getImageHeight() * factorY), z);
glTexCoord2f(getWidth(), getHeight());
glVertex3f(x + (int)Math.round(getImageWidth() * factorX), y + (int)Math.round(getImageHeight() * factorY), z);
glTexCoord2f(getWidth(), 0);
glVertex3f(x + (int)Math.round(getImageWidth() * factorX), y, z);
glEnd();
}
Code: [Select]
// initialize the whole thing
public void initGL()
{
glShadeModel(GL_SMOOTH);
glEnable(GL_TEXTURE_2D);
glEnable(GL_ALPHA);
glEnable(GL_BLEND);
glEnable(GL_DEPTH);
glDepthFunc(GL_EQUAL);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0f);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}
Code: [Select]
// This is executed before every "drawing phase"
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
Code: [Select]
Texture cursor = renderer.getTex("gui/cursor.png");
cursor.drawQuad(100, 100, -1, 1, 1);

Hope this helps and anyone knows what to do...

Greetings
Molt

Re: Blending / Transparency Problems
« Reply #2 on: October 13, 2011, 20:04:10 »
...
When I enable blending, it gets rendered 50% transparent on opaque pixels and transparent on transparent pixels....
What do you set as current blending color ? should be white glColori(1,1,1,1) where you seem to have an alpha-blended glColorf(1f,1f,1f,.5f).

Re: Blending / Transparency Problems
« Reply #3 on: October 14, 2011, 11:27:54 »
I didn't set anything, I'm using the glClearColor.
When I add glColor4d(1,1,1,1), nothing happens, but when I change it to glColor4d(1,1,1,0.5), the pictures get more transparent.
There must be something that halves the alpha value...
Here's the whole TextureLoader:
Code: [Select]
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.IOException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.util.HashMap;
import java.util.Hashtable;
import javax.swing.ImageIcon;
import org.lwjgl.BufferUtils;
import static org.lwjgl.opengl.GL11.*;


public class TextureLoader
{
    public TextureLoader()
{
        glAlphaColorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[] {8,8,8,8}, true, false, ComponentColorModel.TRANSLUCENT, DataBuffer.TYPE_BYTE);
        glColorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[] {8,8,8,0}, false, false, ComponentColorModel.OPAQUE, DataBuffer.TYPE_BYTE);
    }

    private int createTextureID()
{
glGenTextures(textureIDBuffer);
return textureIDBuffer.get(0);
    }

public Texture getTex(String path)
{
return getTexture("../../resources/graphic/" + path);
}

    public Texture getTexture(String path)
{
        Texture tex = table.get(path);
        if(tex == null)
{
            tex = getTexture(path, GL_TEXTURE_2D, GL_RGBA, GL_LINEAR, GL_LINEAR);
table.put(path,tex);
        }
        return tex;
    }

    public Texture getTexture(String path, int target, int dstPixelFormat, int minFilter, int magFilter)
{
        int srcPixelFormat;
        int textureID = createTextureID();
        Texture texture = new Texture(target,textureID);
        glBindTexture(target, textureID);
        BufferedImage bufferedImage = loadImage(path);
        texture.setWidth(bufferedImage.getWidth());
        texture.setHeight(bufferedImage.getHeight());
        if(bufferedImage.getColorModel().hasAlpha())
{
            srcPixelFormat = GL_RGBA;
        }
else
{
            srcPixelFormat = GL_RGB;
        }
        ByteBuffer textureBuffer = convertImageData(bufferedImage,texture);
        if(target == GL_TEXTURE_2D)
{
            glTexParameteri(target, GL_TEXTURE_MIN_FILTER, minFilter);
            glTexParameteri(target, GL_TEXTURE_MAG_FILTER, magFilter);
        }
        glTexImage2D(target, 0, dstPixelFormat, get2Fold(bufferedImage.getWidth()), get2Fold(bufferedImage.getHeight()), 0, srcPixelFormat, GL_UNSIGNED_BYTE, textureBuffer);
        return texture;
    }

    private static int get2Fold(int fold)
{
        int ret = 2;
        while (ret < fold)
{
            ret *= 2;
        }
        return ret;
    }

    private ByteBuffer convertImageData(BufferedImage bufferedImage,Texture texture)
{
        ByteBuffer imageBuffer;
        WritableRaster raster;
        BufferedImage texImage;
        int texWidth = 2;
        int texHeight = 2;
        while(texWidth < bufferedImage.getWidth())
{
            texWidth *= 2;
        }
        while(texHeight < bufferedImage.getHeight())
{
            texHeight *= 2;
        }
        texture.setTextureHeight(texHeight);
        texture.setTextureWidth(texWidth);
        if(bufferedImage.getColorModel().hasAlpha())
{
            raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, texWidth, texHeight, 4, null);
            texImage = new BufferedImage(glAlphaColorModel, raster, false, new Hashtable());
        }
else
{
            raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, texWidth, texHeight, 3, null);
            texImage = new BufferedImage(glColorModel, raster, false, new Hashtable());
        }
        Graphics g = texImage.getGraphics();
        g.setColor(new Color(0f, 0f, 0f, 0f));
        g.fillRect(0, 0, texWidth, texHeight);
        g.drawImage(bufferedImage, 0, 0, null);
        byte[] data = ((DataBufferByte) texImage.getRaster().getDataBuffer()).getData();
        imageBuffer = ByteBuffer.allocateDirect(data.length);
        imageBuffer.order(ByteOrder.nativeOrder());
        imageBuffer.put(data, 0, data.length);
        imageBuffer.flip();
        return imageBuffer;
    }

    private BufferedImage loadImage(String ref)
{
try
{
Image img = new ImageIcon(ref).getImage();
BufferedImage bufferedImage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_RGB);
Graphics g = bufferedImage.getGraphics();
g.drawImage(img, 0, 0, null);
g.dispose();
return bufferedImage;
}
catch(Exception e)
{
return new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
}
    }

private HashMap<String, Texture> table = new HashMap<String, Texture>();
    private ColorModel glAlphaColorModel;
    private ColorModel glColorModel;
    private IntBuffer textureIDBuffer = BufferUtils.createIntBuffer(1);
}
The Texture:
Code: [Select]
import static org.lwjgl.opengl.GL11.*;

public class Texture
{
public Texture(int target, int textureID)
{
this.target = target;
this.textureID = textureID;
}

public void drawQuad(int x, int y)
{
drawQuad(x, y, 0);
}

public void drawQuad(int x, int y, int z)
{
bind();
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex3f(x, y, z);
glTexCoord2f(0, getHeight());
glVertex3f(x, y + getImageHeight(), z);
glTexCoord2f(getWidth(), getHeight());
glVertex3f(x + getImageWidth(), y + getImageHeight(), z);
glTexCoord2f(getWidth(), 0);
glVertex3f(x + getImageWidth(), y, z);
glEnd();
}

public void drawQuadSize(int x, int y, int width, int height)
{
drawQuadSize(x, y, 0, width, height);
}

public void drawQuadSize(int x, int y, int z, int width, int height)
{
bind();
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex3f(x, y, z);
glTexCoord2f(0, getHeight());
glVertex3f(x, y + height, z);
glTexCoord2f(getWidth(), getHeight());
glVertex3f(x + width, y + height, z);
glTexCoord2f(getWidth(), 0);
glVertex3f(x + width, y, z);
glEnd();
}

public void bind()
{
glBindTexture(target, textureID);
}

public void setHeight(int height)
{
this.height = height;
setHeight();
}

public void setWidth(int width)
{
this.width = width;
setWidth();
}

public int getImageHeight()
{
return height;
}

public int getImageWidth()
{
return width;
}

public float getHeight()
{
return heightRatio;
}

public float getWidth()
{
return widthRatio;
}

public void setTextureHeight(int texHeight)
{
this.texHeight = texHeight;
setHeight();
}

public void setTextureWidth(int texWidth)
{
this.texWidth = texWidth;
setWidth();
}

private void setHeight()
{
if (texHeight != 0)
{
heightRatio = ((float) height) / texHeight;
}
}

private void setWidth()
{
if (texWidth != 0)
{
widthRatio = ((float) width) / texWidth;
}
}

private int target;
private int textureID;
private int height;
private int width;
private int texWidth;
private int texHeight;
private float widthRatio;
private float heightRatio;
}
Where the cursor gets drawn:
Code: [Select]
Texture cursor = cultrix.renderer.getTex("gui/cursor.png");
cursor.drawQuad(mouseX, mouseY);
The cursor image can be loaded, gets displayed at the right coordinates, just transparent -.-
I attached the cursor image so u can be 100% sure the image is not transparent.

Greetings
Molt

Re: Blending / Transparency Problems
« Reply #4 on: October 14, 2011, 12:59:11 »
Quote
BufferedImage bufferedImage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_RGB);
It looks like you are loading your .png into a buffered image that has no alpha value. My guess is that your resulting image doesn't have alpha (i.e. you don't get to this line of code: srcPixelFormat = GL_RGBA;).

Then your blending mode (glBlendFunc(GL_SRC_ALPHA, GL_ONE)) is causing your fully opaque texture to have a weird alpha blending (which makes it look strange).
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

Re: Blending / Transparency Problems
« Reply #5 on: October 14, 2011, 13:36:52 »
Your guess was right, it always returned false for hasAlpha() method.
I changed the ImageType to TYPE_INT_ARGB, and it returns true now, but the cursor is still half-transparent. -.-
And when I disable blending, the transparent part is black again.

Greetings
Molt

Re: Blending / Transparency Problems
« Reply #6 on: October 15, 2011, 10:42:20 »
I added this block:
Code: [Select]
glBegin(GL_QUADS);
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
glVertex2f(0, 0);
glVertex2f(0, 100);
glVertex2f(100, 100);
glVertex2f(100, 0);

glColor4f(0.0f, 1.0f, 0.0f, 0.5f);
glVertex2f(100, 0);
glVertex2f(100, 100);
glVertex2f(200, 100);
glVertex2f(200, 0);

glColor4f(0.0f, 0.0f, 1.0f, 0.0f);
glVertex2f(200, 0);
glVertex2f(200, 100);
glVertex2f(300, 100);
glVertex2f(300, 0);
glEnd();

The first and the second have both a transparency of 50%, the third is invisible (as it should be).
So it's not a problem with the TextureLoader or the Texture class, and the alpha value doesn't get multiplied, but there seems to be an alpha limit... any ideas?

Greetings
Molt

Re: Blending / Transparency Problems
« Reply #7 on: October 17, 2011, 12:53:54 »
Did you change your blending mode (usually glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) works as a good starting point)?
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D