Blending / Transparency Problems

Started by Molt, October 13, 2011, 12:51:12

Previous topic - Next topic

Molt

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

Molt

Still unsolved.
Here's some code I use (I use TextureHandler.java and a modified version of Texture.java from the Space Invaders Sample):
// 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();
}

// 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);
}

// This is executed before every "drawing phase"
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

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

broumbroum

Quote from: Molt on October 13, 2011, 12:51:12
...
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).

Molt

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

Fool Running

QuoteBufferedImage 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

Molt

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

Molt

I added this block:
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

Fool Running

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