Android:OpenGL纹理在某些设备上变为白色

时间:2016-03-25 09:02:21

标签: android opengl-es

在我的应用程序中,我使用GLSurfaceView显示二维背景图像,该图像根据显示的内容而变化。该图像用作在与电话屏幕具有相同宽高比的简单矩形上渲染的纹理。当背景改变时,它呈现α混合过渡效果。如果设备不支持Open GL ES 2.0,则使用静态图像。 (附加信息:图像/纹理不是正方形,不是2的幂的大小)

有些客户报告某些设备(例如LG E455)的背景变白,导致应用程序无法使用,因为顶部显示的文字也是白色。我一直在寻找问题的解决方案,但找不到任何东西。

因为我在没有广告的情况下免费提供应用程序(我认为广告不符合应用程序)而且我没有获得外部资金,所以我不能购买有问题的设备(LG E455) - 如它是一个旧设备 - 仅用于调试这个问题。

我使用以下代码加载纹理:

int getTexture(GL10 gl, int index) {
    if (BackgroundRenderer.this.textures[index] == 0) {
        gl.glGenTextures(1, BackgroundRenderer.this.textures, index);
        gl.glBindTexture(GL10.GL_TEXTURE_2D, BackgroundRenderer.this.textures[index]);

        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

        Bitmap bitmap = ResourceStore.getBackgroundBitmap(index);

        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
    }

    return BackgroundRenderer.this.textures[index];
}

版本检查和初始化:

private static boolean supportsOpenGLES2(Context context) {
    ActivityManager activityManager = (ActivityManager)
            context.getSystemService(Context.ACTIVITY_SERVICE);
    ConfigurationInfo configurationInfo =
            activityManager.getDeviceConfigurationInfo();
    return configurationInfo.reqGlEsVersion >= 0x20000;
}

public BackgroundManager(Context context, ViewPager eventSource) {
    this.context = context;
    supportsRendering = BackgroundManager.supportsOpenGLES2(context);
    eventSource.setTag(id.TAG_BACKGROUND_MANAGER, this);

    if (this.supportsRendering) {
        this.backgroundSurfaceView = new GLSurfaceView(context);
        this.backgroundSurfaceView.setFocusable(false);
        this.backgroundSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
        eventSource.addOnPageChangeListener(BackgroundManager.getRenderer());
        this.backgroundSurfaceView.setRenderer(BackgroundManager.getRenderer());
        this.backgroundSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
    } else {
        this.backgroundStillView = new View(context);
    }
}

如果您需要更多代码,请告诉我。

我考虑过一些可能的解决方案:

a)解决问题(不知道如何......)

b)在设备不支持的情况下禁用花哨效果,但问题是,如何检测呈现是否会提前工作?该设备通过了我的Open GL 2.0版本检查。

c)转移到另一个渲染解决方案而不是OpenGL,因为我觉得这对我的目的来说太过分了。有什么建议吗?

注意:Android 'white box' textures OpenGL ES 1.0 on some devices中提出的解决方案不适用,因为我使用了不同的API,并且设备确实按照http://specdevice.com/showspec.php?id=02c2-cba8-ffff-ffffebe99653支持扩展(虽然我不确定信息是否正确/可信的)

感谢您的建议!

1 个答案:

答案 0 :(得分:2)

这里的问题是某些设备不支持非二次幂纹理。这就是为什么有些设备只显示白色纹理。

要解决这个问题,最好在生成纹理时始终使用2的幂位图。

两个位图的位图是位图,其宽度/高度是2的幂(256,512,1024等)。目前的情况是,你通过ResourceStore重新加载你的位图,我怀疑这个工具会创建一个PO2位图。

要解决此问题,请按以下步骤操作:

  1. 正常执行
  2. 时创建位图
  3. 查找位图的尺寸(比方说,例如,500x800)
  4. 创建一个新的位图,该位图是PO2且大于原始位图(在本例中为512x1024)
  5. 将原始位图复制到此新位图上,保留原始位图大小,以便新位图的右侧和底部都有空白区域。
  6. 调整纹理坐标 - 而不是1代表x coord,使用500/512,而不是1代表y coord,使用800 / 1024.这样可以防止显示那些丑陋的白角。
  7. 这是一个代码示例:

    public void getTexture(GL10 gl, int index) {
        if (BackgroundRenderer.this.textures[index] == 0) {
            //calls to gl.glGenTextures, gl.glBindTexture etc
    
            Bitmap originalBitmap = ResourceStore.getBackgroundBitmap(index);
    
           int po2W = 1;
           int po2H = 1;
    
           while (po2W < originalBitmap.getWidth())
              po2W *= 2;
    
           while (po2H < originalBitmap.getHeight())
              po2H *= 2;
    
           Bitmap po2Bitmap = Bitmap.createBitmap(po2W, po2H, Config.ARGB_8888);
    
           Canvas canvas = new Canvas(po2Bitmap);
           canvas.drawBitmap(originalBitmap, 0, 0, myPaint);
    
           GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, po2Bitmap, 0);
    
           // these ratios need to be used for setting the texture coordinates!
           mWidthRatio = (float)orignalBitmap.getWidth() / (float)po2Bitmap.getWidth();
           mHeightRatio = (float)orignalBitmap.getHeight() / (float)po2Bitmap.getHeight();
        }
    
        return BackgroundRenderer.this.textures[index];
    }
    

    现在,您需要重新定义纹理坐标:

    float textureData[] = {
             0,           0,             // top left
             0,           mHeightRatio,  // bottom left
             mWidthRatio, mHeightRatio,  // bottom right
             mWidthRatio, 0              // top right
    };
    

    现在你应该好好去。

    如果有任何问题,请告诉我。