Reputation: 19344
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...
Upvotes: 6
Views: 7159
Reputation: 1954
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
Upvotes: 1
Reputation: 4575
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);
Upvotes: 3
Reputation: 5364
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
Upvotes: 1
Reputation: 102
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);
}
Upvotes: 4
Reputation: 51
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);
Upvotes: 5
Reputation: 2905
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
.
Upvotes: 0