Android 内部纹理格式

Android 内部纹理格式,android,opengl-es-2.0,Android,Opengl Es 2.0,在使用OpenGL ES 2.0的Android上,我尝试使用不同的内部纹理格式执行某些性能测试。 最初我有很多RGBA纹理png,我想用OpenGL以不同的格式在内部加载和存储,例如RGB和亮度。我使用glTexImage2D加载纹理,如下所示: Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),resourceId); ... int size = bitmap.getRowBytes() * bitmap

在使用OpenGL ES 2.0的Android上,我尝试使用不同的内部纹理格式执行某些性能测试。 最初我有很多RGBA纹理png,我想用OpenGL以不同的格式在内部加载和存储,例如RGB和亮度。我使用glTexImage2D加载纹理,如下所示:

Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),resourceId);
...
int size = bitmap.getRowBytes() * bitmap.getHeight();
ByteBuffer b = ByteBuffer.allocate(size);
bitmap.copyPixelsToBuffer(b);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, bitmap.getWidth(),    
                    bitmap.getHeight(), 0, GLES20.GL_RGBA, 
                    GLES20.GL_UNSIGNED_BYTE, b);
vec3 Color_RGB = texture2D(sampler2d, texCoordinate);
gl_FragColor = vec4(Color_RGB, 1.0);
vec4 Color_RGBA = texture2D(sampler2d, texCoordinate);
gl_FragColor = Color_RGBA;
但是,如果我将第一个GLES20.GL_RGBA internalFormat参数更改为其他任何参数GLES20.GL_RGB或GLES20.GL_LUMINANCE,则我的纹理将显示为全黑色。将第二个GLES20.GL_RGBA更改为相同的值将显示一些内容,但显然不正确,因为原始数据是RGBA

我想它可能与着色器代码有关-可能是texture2D。。返回不同的值,因为纹理的内部格式不同。我的着色器代码很简单:

gl_FragColor = texture2D(texture, fragment_texture_coordinate);
我也试着改变这一点,但还没有成功。所以我想也许glTex2DImage根本不起作用,因为我认为我不是这方面的专家

我做错了什么

编辑: 我忽略了texImage2D上的这个小细节。看来:

internalformat必须与格式匹配。纹理图像处理期间不支持格式之间的转换。类型可以用作指定所需精度的提示,但GL实现可以选择以其选择的任何内部分辨率存储纹理阵列


我从中得出的结论是,如果你想存储不同于原始格式的纹理,你必须自己转换

必须编写片段着色器,以与您提供给glTexImage2D的格式一致。对于GL_RGB,它应该强制alpha为1.0,如下所示:

Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),resourceId);
...
int size = bitmap.getRowBytes() * bitmap.getHeight();
ByteBuffer b = ByteBuffer.allocate(size);
bitmap.copyPixelsToBuffer(b);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, bitmap.getWidth(),    
                    bitmap.getHeight(), 0, GLES20.GL_RGBA, 
                    GLES20.GL_UNSIGNED_BYTE, b);
vec3 Color_RGB = texture2D(sampler2d, texCoordinate);
gl_FragColor = vec4(Color_RGB, 1.0);
vec4 Color_RGBA = texture2D(sampler2d, texCoordinate);
gl_FragColor = Color_RGBA;
但是,对于GL_RGBA,它应该如下所示:

Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),resourceId);
...
int size = bitmap.getRowBytes() * bitmap.getHeight();
ByteBuffer b = ByteBuffer.allocate(size);
bitmap.copyPixelsToBuffer(b);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, bitmap.getWidth(),    
                    bitmap.getHeight(), 0, GLES20.GL_RGBA, 
                    GLES20.GL_UNSIGNED_BYTE, b);
vec3 Color_RGB = texture2D(sampler2d, texCoordinate);
gl_FragColor = vec4(Color_RGB, 1.0);
vec4 Color_RGBA = texture2D(sampler2d, texCoordinate);
gl_FragColor = Color_RGBA;
而且,如前所述,如果PNG文件没有透明度,则只能对纹理使用Android位图类。这篇文章解释说:

我花了几周时间试图找到解决方案。。。没有机会。。。BitmapFactory.decodeXXXXX正在预乘alpa。。。唯一的方法是建立自己的加载器。。。我现在将jni与libpng结合使用,谢谢您的回复,但我认为预乘alpha不是这里的问题。我的图像没有任何半透明像素。from:format指定texel数据的格式。必须匹配内部格式。接受以下符号值:GL_ALPHA、GL_RGB、GL_RGBA、GL_亮度和GL_亮度_ALPHA。RGB和亮度是否连接?如果是,为什么不使用香奈儿作为亮度?啊,谢谢链接。奇怪的是,我忽略了这一点:内部格式必须与格式匹配。纹理图像处理期间不支持格式之间的转换。类型可以用作指定所需精度的提示,但GL实现可以选择以其选择的任何内部分辨率存储纹理阵列。因此,基本上,只有当我的纹理已经是RGB/亮度格式或在GL调用之前已转换时,才可能存储它。我可能错了,但我认为这不是真的。vec3 Color_RGB=纹理2dSampler2D,tex坐标;由于texture2D。。。始终返回一个vec4。将vec3更改为vec4确实会编译,但会导致完全黑色的纹理,因此可能根本不会加载。如果你读了我的编辑,也没那么奇怪。另一方面,手动将位图像素数据转换为RGB,然后将其加载为RGB,就像一个魔咒,而无需调整着色器代码中的任何内容。在这一点上,我并不关心预乘阿尔法的问题。提供的链接很有用:。是的,texture2D总是返回vec4,我的错误。但将vec3更改为vec4将使alpha部分在默认情况下始终为0.0,这将显示黑色,除非将其设置为1.0。我不确定手动转换位图是什么意思,但任何转换都应该在片段着色器中完成,因为它比Java快得多。我忘了提到我还将alpha设置为1.0,否则我将获得透明纹理。对于手动转换,我的意思是从位图类读取像素RGBA数据,例如仅将RGB值写入缓冲区,并将该缓冲区用于texImage2D,在这种情况下,internalFormat和format参数设置为RGB。这仅适用于使用gl_FragColor=texture2Dtexture,texcoordinate;。现在,纹理在内部存储为RGB。我需要在加载时进行此转换,而不是像texture2D一样在片段着色器中。。在所述亮度上似乎比RGBA更快。