在某些设备上打开gl es 2.0纹理渲染的黑色文物

时间:2014-05-09 18:44:47

标签: android opengl-es bitmap texture-mapping

在某些设备上渲染纹理时(仅确认了galaxy s3 mini),我在纹理上出现了暗区闪烁:

Black Artifacts on Android in OpenGL ES 2

我不允许评论这个帖子(信用不足),但我想澄清解决这个问题的作者:

您能否再解释一下如何使用glTexImage2D()glTexSubImage2D()来解决这个问题?

在代码中我得到了这些行来加载位图: (如您所见,我使用texImage2D加载位图,关于gltexImage2D的Android文档仅提供属性类型但没有解释)

...
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;

final Bitmap bitmap = BitmapFactory.decodeResource(
    context.getResources(), resourceId, options);

if (bitmap == null) {
    if (LoggerConfig.ON) {
        Log.w(TAG, "Resource ID " + resourceId + " could not be decoded.");
    }

    glDeleteTextures(1, textureObjectIds, 0);
    return 0;
} 

glBindTexture(GL_TEXTURE_2D, textureObjectIds[0]);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);

glGenerateMipmap(GL_TEXTURE_2D);
...

编辑:

尝试按照顶部的链接实现解决方案,但没有运气,同样的闪烁效果, 加载位图的新代码:

ByteBuffer byteBuffer = ByteBuffer.allocateDirect(bitmap.getWidth() * bitmap.getHeight() * 4);
    byteBuffer.order(ByteOrder.BIG_ENDIAN);
    IntBuffer ib = byteBuffer.asIntBuffer();

    int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];
    bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
    for(int i=0; i<pixels.length; i++){
        ib.put(pixels[i] << 8 | pixels[i] >>> 24);
    }

    bitmap.recycle();

    byteBuffer.position(0);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap.getWidth(), bitmap.getHeight(), 0, GL_RGBA,      GL_UNSIGNED_BYTE, null);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.getWidth(), bitmap.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, byteBuffer);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );

奇怪行为的图示,请参见图像中间右侧的黑色区域:

(我需要10个声誉才能张贴图片?!?!?)

https://dl.dropboxusercontent.com/u/61092317/blackflickering.jpg

1 个答案:

答案 0 :(得分:0)

您引用的另一个问题中的问题似乎是这样:作者在最初加载纹理时指定了MipMaps,并且MipMaps无法正常工作。他可能没有正确使用glTexImage2d

他得到的神器是:当纹理单元试图从一个MipMap级别移动到另一个MipMap级别时,那里没有信息,而是渲染了一个空白(显然是黑色)纹理。所以,他的MipMap中至少有一个级别被加载了。

我不确定该作者是否真正妥善解决了他的问题。 OpenGL可以非常具体地说明如何将纹理加载到其中,即使代码中的最小错误也可能导致问题。问题可能只发生在某些平台上,因此您会得到设备出现问题的印象,但它仍然可能是代码。

最好的起点是红皮书:http://www.glprogramming.com/red/chapter09.html

然后:http://www.opengl.org/sdk/docs/man3/xhtml/glGenerateMipmap.xml

您想了解的所有功能都在那里列出。

您的问题中没有回答一些细节。你手动创建自己的MipMaps吗?您是否希望OpenGL自动生成MipMaps?

我建议从一个简单的纹理开始,它具有 no MipMaps,只有一个级别。看看你是否可以做到这一点。如果这可以解决问题,那么就开始使用MipMaps。

对于原始问题,使用glTexImage2D加载纹理数据或使用glTexSubImage2D更新纹理数据之间没有完全不同。 glTexImage2D用于指定纹理(即:纹理的宽度/高度,每个MipMap级别不同),而glTexSubImage2D用于更新已由glTexImage2D指定的全部或部分纹理。在第二个例子中,您只需使用新的纹素进行更新。