Issues with GLUtils.texImage2D and Alpha in Textures
Asked Answered
V

6

6

I'm successfully generating my textures using GLUtils.texImage2D, but when I use the textures generated I get problems with my alpha: they are darker than wanted.

after having checked several things I finally got the the conclusions that the problem comes from GLUtils.texImage2D(GL10.GL_TEXTURE_2D, level, bmp, 0);

I created a second function that uses gl.glTexImage2D(GL10.GL_TEXTURE_2D, level, GL10.GL_RGBA, width, height, 0, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, pixels2);

but it is costly in processing to create pixels2 which is a bytebuffer in which I have to recopy the bytes while changing the values from the bitmap ARGB to texture RGBA.

Has anybody noticed that ? and if so how did you solve this...

jason


Thank you for your answer, I'm already using

gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);

and I'm getting this problem

my problem is that the alpha generated by GLUtils isn't the one of the texture, its darker.

the difference is like looking at a color in the sun and in the shade (if that makes any sence).

I already tried gl.gltextimage2d but the creating the buffer takes too long, unless there is a tool to convert a bitmap to a byte buffer that I don't know of...

Varipapa answered 13/10, 2010 at 7:48 Comment(0)
W
4

The alpha channel is the poor mistreated stepchild of a huge number of programmers is all I can say... but the upload works fairly efficient if you do that:

  • Estimate your largest texture (like 1024x1024) and create an int array of that size (1024*1024) that you store in some static variable or somewhere where you can access it so that you don't need to recreate that array (allocation time is precious here)

  • then do this:

    bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
    gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, width, height, 
         0, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, IntBuffer.wrap(pixels));
    

I am sorry not having found a different solution... the original problem is, that the implementor of the GLUtils.texImage2D function has mistreated the alpha channel somehow resulting in black borders when the image is displayed larger than it is (the bilinear filter calculates the color between four pixels and when the rgb values of the pixels with transparent alphas have been mangled (like set to black), the result is, that there's some kind of a "color bleeding" happening over the transparent border that is forming there. Very ugly. Maybe it was done to improve the compression ratio as the RGB values in alpha transparent areas in PSDs contain a lot of junk that when eliminated yield a lot of room of improvement for compression algorithms)

Edit: Sadly, this approach was only working for grey images correctly as the red and blue channel is swapped when fetching the pixels from the bitmap. At least on MY device. I am not sure how correctly this is for other devices, but in my case, this here did the trick:

for (int i=0;i<pixels.length;i+=1) {
    int argb = pixels[i];
    pixels[i] = argb&0xff00ff00 | ((argb&0xff)<<16) | ((argb>>16)&0xff);
}
Wrapping answered 27/9, 2011 at 6:23 Comment(0)
F
5

GLUtils.texImage2D generates a premultiplied-alpha texture. In this generated texture, all pixels are multiplied by alpha value, so you don't need to multiply alpha value once again. Let's try

gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);

Factory answered 20/11, 2010 at 12:39 Comment(0)
W
4

The alpha channel is the poor mistreated stepchild of a huge number of programmers is all I can say... but the upload works fairly efficient if you do that:

  • Estimate your largest texture (like 1024x1024) and create an int array of that size (1024*1024) that you store in some static variable or somewhere where you can access it so that you don't need to recreate that array (allocation time is precious here)

  • then do this:

    bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
    gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, width, height, 
         0, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, IntBuffer.wrap(pixels));
    

I am sorry not having found a different solution... the original problem is, that the implementor of the GLUtils.texImage2D function has mistreated the alpha channel somehow resulting in black borders when the image is displayed larger than it is (the bilinear filter calculates the color between four pixels and when the rgb values of the pixels with transparent alphas have been mangled (like set to black), the result is, that there's some kind of a "color bleeding" happening over the transparent border that is forming there. Very ugly. Maybe it was done to improve the compression ratio as the RGB values in alpha transparent areas in PSDs contain a lot of junk that when eliminated yield a lot of room of improvement for compression algorithms)

Edit: Sadly, this approach was only working for grey images correctly as the red and blue channel is swapped when fetching the pixels from the bitmap. At least on MY device. I am not sure how correctly this is for other devices, but in my case, this here did the trick:

for (int i=0;i<pixels.length;i+=1) {
    int argb = pixels[i];
    pixels[i] = argb&0xff00ff00 | ((argb&0xff)<<16) | ((argb>>16)&0xff);
}
Wrapping answered 27/9, 2011 at 6:23 Comment(0)
H
3

Solution is found here. It is related as is stated by others with premultiplied alpha.

In the surfaceView Constructor

    setEGLConfigChooser(8, 8, 8, 8, 0, 0); 
    getHolder().setFormat(PixelFormat.RGBA_8888); 

In the View.Renderer onSurfaceCreated

    gl.glEnable(GL10.GL_BLEND); 
    gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA); 
Heavenward answered 6/11, 2013 at 11:3 Comment(0)
N
1

Android Bitmap stores images loaded from PNG with premultiplied colors. GLUtils.texImage2D also uses colors premultiplied by alpha, so you can't get original colours this way.

In order to load PNG images without RGB channels being premultiplied I use 3rd party PNGDecoder and load texture with glTexImage2D. You can get PNGDecoder library to decode PNG from here: http://twl.l33tlabs.org/#downloads

Naphthyl answered 31/8, 2012 at 7:3 Comment(0)
A
1

Android's BitmapFactory.decode() premultiplies alpha by default on loading. So if you don't want to load premultiplied bitmaps, use Bitmap.Options with inPremultiplied set to true when loading the bitmap for texture:

//kotlin
val options = BitmapFactory.Options()
options.inPremultiplied = false

val bitmap = BitmapFactory.decodeStream(inputStream, null, options)

Then pass this bitmap to GLUtils.texImage2D


P.S. Nice video for understanding premultiplied alpha:

https://www.youtube.com/watch?v=wVkLeaWQOlQ

Arthritis answered 16/12, 2022 at 18:26 Comment(0)
G
0

There is an issues in GLUtils with premultiplied alpha. The only workaround that I can propose is to use:

gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA)

In case you need other blend functions you will have to use gl.glTexImage2D.

Gravamen answered 13/10, 2010 at 9:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.