纹理中 GLUtils.texImage2D 和 Alpha 的问题

发布于 2024-09-27 05:39:24 字数 723 浏览 2 评论 0 原文

我使用 GLUtils.texImage2D 成功生成了纹理, 但是当我使用生成的纹理时,我的 Alpha 出现了问题:它们比想要的更暗。

在检查了几件事之后,我终于得到了问题来自 GLUtils.texImage2D(GL10.GL_TEXTURE_2D, level, bmp, 0); 的结论。

我创建了第二个函数,它使用 gl.glTexImage2D(GL10.GL_TEXTURE_2D, level, GL10.GL_RGBA, width, height, 0, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, Pixels2);

但创建 Pixel2 是一个字节缓冲区,在将值从位图 ARGB 更改为纹理 RGBA 时,我必须在其中重新复制字节,处理成本很高。

有人注意到了吗?如果是这样,你是如何解决这个问题的...

杰森


谢谢你的回答, 我已经在使用

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

并且遇到了这个问题,

我的问题是 GLUtils 生成的 alpha 不是纹理之一,它更暗。

区别就像在阳光下和阴影下观察颜色一样(如果这有意义的话)。

我已经尝试过 gl.gltextimage2d 但创建缓冲区需要太长时间,除非有一个工具将位图转换为我不知道的字节缓冲区...

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

说好的呢 2024-10-04 05:39:24

GLUtils.texImage2D 生成预乘 alpha 纹理。在这个生成的纹理中,所有像素都乘以 alpha 值,因此您不需要再次乘以 alpha 值。
让我们尝试一下

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

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

独﹏钓一江月 2024-10-04 05:39:24

我只能说,alpha 通道是大量程序员中可怜的、被虐待的继子......但是如果你这样做的话,上传的效率相当高:

  • 估计你最大的纹理(如 1024x1024)并创建一个 int 数组您存储在某个静态变量或可以访问它的地方的大小(1024*1024),这样您就不需要重新创建该数组(分配时间在这里很宝贵)

  • 然后这样做:

    bitmap.getPixels(像素, 0, 宽度, 0, 0, 宽度, 高度);
    gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, 宽度, 高度, 
         0、GL10.GL_RGBA、GL10.GL_UNSIGNED_BYTE、IntBuffer.wrap(像素));
    

我很抱歉没有找到不同的解决方案...最初的问题是,GLUtils.texImage2D 函数的实现者以某种方式错误地处理了 alpha 通道,导致当图像显示得比实际更大(双线性过滤器计算四个像素之间的颜色,并且当具有透明 Alpha 的像素的 RGB 值被破坏(例如设置为黑色)时,结果是,存在某种“颜色”在那里形成的透明边框上发生了“出血”现象。非常丑陋。也许这样做是为了提高压缩比,因为 PSD 中 alpha 透明区域中的 RGB 值包含大量垃圾,消除这些垃圾后会产生很大的改进空间压缩算法)

编辑:遗憾的是,这种方法仅适用于灰色图像,因为从位图中获取像素时会交换红色和蓝色通道。至少在我的设备上是这样。我不确定这对于其他设备来说有多正确,但就我而言,这在这里做到了:

for (int i=0;i<pixels.length;i+=1) {
    int argb = pixels[i];
    pixels[i] = argb&0xff00ff00 | ((argb&0xff)<<16) | ((argb>>16)&0xff);
}

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);
}
埖埖迣鎅 2024-10-04 05:39:24

解决方案可在此处找到。正如其他人所述,它与预乘 alpha 相关。

在 surfaceView 构造函数中

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

在 View.Renderer 中 onSurfaceCreated

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

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); 
够钟 2024-10-04 05:39:24

Android Bitmap 存储从 PNG 加载的具有预乘颜色的图像。 GLUtils.texImage2D 也使用预乘 alpha 的颜色,因此您无法通过这种方式获得原始颜色。

为了在不预乘 RGB 通道的情况下加载 PNG 图像,我使用第 3 方 PNGDecoder 并使用 glTexImage2D 加载纹理。您可以从此处获取用于解码 PNG 的 PNGDecoder 库:http://twl.l33tlabs。 org/#downloads

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

听闻余生 2024-10-04 05:39:24

Android 的 BitmapFactory.decode() 在加载时默认预乘 alpha。
,如果您不想加载预乘位图,请在加载纹理位图时使用 Bitmap.Options 并将 inPremultiplied 设置为 true

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

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

因此 将此位图传递给 GLUtils.texImage2D


PS
了解预乘 Alpha 的精彩视频:

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

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

時窥 2024-10-04 05:39:24

GLUtils 中的预乘 alpha 存在问题。我可以建议的唯一解决方法是使用:

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

如果您需要其他混合函数,则必须使用gl.glTexImage2D

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文