【问题标题】:android bitmap pixel format for glTexImage2DglTexImage2D的android位图像素格式
【发布时间】:2016-01-10 13:25:45
【问题描述】:

我正在尝试通过 Bitmap 类从 Java 加载纹理以与 NDK OpenGL 一起使用。它可以工作,但我遇到了像素格式的问题。

首先,在 Java 中,我从 assets 文件夹中加载一个位图,如下所示:

Bitmap bitmap = BitmapFactory.decodeStream(amgr.open(path));
return bitmap.copy(Bitmap.Config.ARGB_8888, false);

位图配置没有 RGBA 通道顺序选项。

[JNI 事情发生在这里]

使用 GLES 1,然后我像这样缓冲纹理:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// `pixels` is the pixel buffer I produced earlier.

如您所见,像素格式存在问题。 glTexImage2D 没有 ARGB 选项,但 Java Bitmap 类没有在 RGBA 中创建缓冲区的选项。所以我最终得到了混乱的颜色通道。顺便说一句,我确实需要 Alpha 通道。

问题是:如何最有效地从 Java 位图类生成 RGBA8888 格式的像素缓冲区,或者,如何加载 ARGB8888 格式的 GL 纹理?

除了手动逐像素交换字节之外,肯定还有其他方法吗?

我目前正在这样做:

void pxl::swap_channels_ARGB_to_RGBA(void *pixBuf, const int len)
{
    jint *pixels = (jint *)pixBuf;

    for(int i = 0; i < len; i++)
    {
        jint pixel = pixels[i];

        jint a = (pixel >> 24) & 0xFF;
        jint r = (pixel >> 16) & 0xFF;
        jint g = (pixel >>  8) & 0xFF;
        jint b = (pixel >>  0) & 0xFF;

        pixels[i] = (jint)(a | (r << 24 ) | (g << 16) | (b << 8));
    }
}

或者可能还有另一个错误?老实说,我不确定glTexImage2D 选项。

谢谢!

【问题讨论】:

  • 是否需要在 JNI 端进行 glTexImage2D 调用?或者,您可以使用 GLUtils.texImage2D 在 Java 端上传它,然后将纹理 id 作为 int 传递给 JNI。
  • 谢谢,但是是的,我正在尝试将所有 GL 内容保留在 C++ 中。它适用于手动交换,只是好奇是否有更优雅的解决方案。
  • 我也很好奇,因为source code for GLUtils 不做任何交换,但它可以工作。它通过将 Bitmap 对象作为作业对象传递给 JNI 并调用 getPixels() 来工作。检查 util_texImage2D 函数。
  • 您能否展示在传递给 JNI 之前如何从位图中提取数据?你使用 getPixels() 还是 copyPixelsToBuffer()?

标签: android opengl-es bitmap java-native-interface textures


【解决方案1】:

此问题在 OpenGL ES 1.1 中无法解决,但在 OpenGL ES 3.0 中或通过 OpenGL 扩展 EXT_texture_swizzle 可以解决:

从 OpenGL ES 3.0 开始,您可以使用纹理混合参数来交换颜色通道。见glTexParameter:

GL_TEXTURE_SWIZZLE_R

设置将在纹理元素的 r 组件返回到着色器之前应用到它的 swizzle。参数的有效值为GL_REDGL_GREENGL_BLUEGL_ALPHAGL_ZEROGL_ONE。如果GL_TEXTURE_SWIZZLE_RGL_RED,则 r 的值将从获取的纹素的第一个通道中获取。如果GL_TEXTURE_SWIZZLE_RGL_GREEN,r 的值将从获取的纹素的第二个通道中获取。 ...

这意味着当您为纹理对象设置以下纹理参数时,查找纹理时颜色通道将被交换:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_GREEN);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_BLUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ALPHA);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED);


规范中的相关部分可以在OpenGL ES 3.0.5 Specification; 3.8.14 Texture State; page 162找到。

要检查 OpenGL 扩展是否有效,可以使用glGetString(GL_EXTENSIONS),它会返回以空格分隔的受支持扩展列表。



一个完全不同的解决方案是使用Canvas 进行转换。在画布上绘制Bitmap,然后使用画布保存的目标位图。
我在 GitHub 上找到了这个解决方案:fix android 2.3 can't decode bitmap in rgba8888 format

public static Bitmap convert(Bitmap bitmap, Bitmap.Config config) {
    Bitmap convertedBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), config);
    Canvas canvas          = new Canvas(convertedBitmap);
    Paint  paint           = new Paint();
    paint.setColor(Color.BLACK);
    canvas.drawBitmap(bitmap, 0, 0, paint);
    return convertedBitmap;
}

【讨论】:

    【解决方案2】:

    我认为没有办法做到这一点,但你可以用这个来优化你的算法

    void pxl::swap_channels_ARGB_to_RGBA(void *pixBuf, const int len) {
        jint *pixels = (jint *)pixBuf;
    
        for(int i = 0; i < len; i++) {
            unsigned int aux = (int)pixels[i];
            pixels[i] = (aux << 8) | (aux >> 24);
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-05
      • 2015-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多