【问题标题】:Internal Texture Format内部纹理格式
【发布时间】:2013-06-05 10:00:20
【问题描述】:

在使用 OpenGL ES 2.0 的 Android 上,我尝试使用不同的内部纹理格式执行某些性能测试。 最初,我有很多 RGBA 纹理 (png),我想使用 OpenGL 以不同的格式(例如 RGB 和 LUMINANCE)在内部加载和存储这些纹理。我像这样使用 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);

这很好用,但是如果我将第一个 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 必须匹配格式。纹理图像处理期间不支持格式之间的转换。 type 可以用作指定所需精度的提示,但 GL 实现可以选择以它选择的任何内部分辨率存储纹理数组。

我从中得到的信息是,如果您想存储不同于原始格式的纹理,您必须自己进行转换。

【问题讨论】:

  • 我试图找到解决方案几个星期......没有机会...... BitmapFactory.decodeXXXXX 正在预乘 alpa groups.google.com/forum/?fromgroups#!topic/android-developers/… ...唯一的方法是构建自己的加载器。 .. 我现在正在使用 jni 和 libpng
  • 感谢您的回复,但我不认为预乘 alpha 是这里的问题。我的图像没有任何(半)透明像素。
  • from khronos.org/opengles/sdk/docs/man/xhtml/glTexImage2D.xml : format Specifies the format of the texel data. Must match internalformat. The following symbolic values are accepted: GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE, and GL_LUMINANCE_ALPHA. RGB 和 LUMINANCE 是连接的,如果是这样,为什么不使用香奈儿作为 LUMINANCE?
  • 啊,谢谢你的链接。奇怪我忽略了这一点:internalformat must match format. No conversion between formats is supported during texture image processing. type may be used as a hint to specify how much precision is desired, but a GL implementation may choose to store the texture array at any internal resolution it chooses. 所以基本上只能存储它,所以如果我的纹理已经是 RGB/亮度格式(或在 GL 调用之前转换)。

标签: android opengl-es-2.0


【解决方案1】:

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

vec3 Color_RGB = texture2D(sampler2d, texCoordinate);
gl_FragColor = vec4(Color_RGB, 1.0);

但是,对于 GL_RGBA,它应该是这样的:

vec4 Color_RGBA = texture2D(sampler2d, texCoordinate);
gl_FragColor = Color_RGBA;

而且,正如已经讨论过的,如果您的 PNG 文件没有透明度,则只能将 Android Bitmap 类用于纹理。这篇文章解释说: http://software.intel.com/en-us/articles/porting-opengl-games-to-android-on-intel-atom-processors-part-1

【讨论】:

  • 我可能错了,但我认为这不是真的。 vec3 Color_RGB = texture2D(sampler2d, texCoordinate); 无法编译,因为 texture2D(...) 总是返回 vec4。将 vec3 更改为 vec4 确实可以编译,但会导致完全黑色的纹理,因此它可能根本没有加载。如果您阅读我的编辑,这并不奇怪。另一方面,手动将位图像素数据转换为 RGB,然后将其加载为 RGB 就像一种魅力,无需在着色器代码中进行任何调整。在这一点上,我不关心预乘 alpha 的问题。不过提供的链接很有帮助:)。
  • 是的,texture2D() 总是返回一个 vec4,我的错。但是将 vec3 更改为 vec4 将使 alpha 部分在默认情况下始终为 0.0,这将使您显示黑色,除非您将其设置为 1.0。我不确定手动转换位图是什么意思,但是任何转换都应该在片段着色器中完成,因为它比 Java 快得多。
  • 我忘了说我也设置了alpha为1.0,否则我会得到一个透明的纹理。通过手动转换,我的意思是从 Bitmap 类中读取像素 (RGBA) 数据,例如仅将 RGB 值写入缓冲区 - 并在这种情况下将该缓冲区用于 texImage2D,internalFormat 和格式参数设置为 RGB。这适用于仅使用gl_FragColor = texture2D(texture, texcoordinate);。现在纹理在内部存储为 RGB。我需要在加载时进行这种转换,而不是在片段着色器中进行,因为在说 LUMINANCE 上,texture2D(..) 似乎比 RGBA 更快。
猜你喜欢
  • 2012-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多