glTexImage2D的android位图像素格式

时间:2016-01-10 13:25:45

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

我尝试使用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选项是否诚实。

谢谢!

2 个答案:

答案 0 :(得分: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);
    }

}

答案 1 :(得分:2)

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

自OpenGL ES 3.0开始,您可以使用纹理变形参数交换颜色通道。参见glTexParameter

  

GL_TEXTURE_SWIZZLE_R

     

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

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

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