我尝试使用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
选项是否诚实。
谢谢!
答案 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_RED
,GL_GREEN
,GL_BLUE
,GL_ALPHA
,GL_ZERO
和GL_ONE
。如果GL_TEXTURE_SWIZZLE_R
为GL_RED
,则r的值将从获取的texel的第一个通道获取。如果GL_TEXTURE_SWIZZLE_R
为GL_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;
}