【问题标题】:Black artifacts with open gl es 2.0 texture rendering on Certain devices在某些设备上使用 open gl es 2.0 纹理渲染的黑色伪影
【发布时间】:2014-05-10 16:50:45
【问题描述】:

在某些设备上渲染纹理时(仅确认 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

【问题讨论】:

  • 我想如果您将 NULL 传递给 glTexImage2D (...) 然后尝试从中生成 mipmap,您将得到的不仅仅是简单的黑线。整个基础图像将是不确定的,因此从基础图像生成 mipmap 也是没有意义的。

标签: android opengl-es bitmap texture-mapping


【解决方案1】:

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

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

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

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

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

您想了解的所有功能都在此处列出。

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

我建议从一个简单的纹理开始,它没有 MipMaps,只有一层。看看你能不能做到这一点。如果这样可以解决问题,那么就开始使用 MipMaps。

至于最初的问题,使用glTexImage2D 加载纹理数据或使用glTexSubImage2D 更新纹理数据并没有完全不同。 glTexImage2D 用于指定纹理(即:纹理的宽度/高度,每个 MipMap 级别不同),而 glTexSubImage2D 用于更新 已由glTexImage2D 指定的全部或部分纹理。在第二种情况下,您只是用新的纹素更新它。

【讨论】:

  • 感谢您的解释和建议。我对 opengl 很陌生,所以 gltexsubimage2d 的使用对我来说是新的。我已经删除了中间映射,因为我不需要它。 (我的位图没有缩放,我知道你在缩放图像时使用它,如果你缩小图像,避免opengl es在内存中有一个大的位图?)无论如何,即使没有中间映射,问题仍然是相同的。我开始认为这是特定于设备的。位图在几乎所有设备(三星 s4、htc x one、nexus 5、旧设备......只有 android 4.1 上的 s3 mini......)上都能正确呈现。
  • 我已经在我的原始帖子中添加了一个插图(只能粘贴链接,因为需要 10 个声望才能允许插入图像!!)也许有人会认出这个神器。我注意到在相机视图发生变化时出现暗区。也就是说,场景的视图被冻结,黑点不会闪烁/移动。
猜你喜欢
  • 1970-01-01
  • 2016-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多