OpenGL纹理尺寸限制。为特定的Android设备提供替代资源。

3

我在我的Android应用程序中添加了4组图形资源,如下:

  • ldpi
  • mdpi
  • hdpi
  • xhdpi

现在,在我的xhdpi文件夹中,我最大的资产是2560 x 1838,因为我在这里针对大屏幕(例如从XHDPI文件夹获取其资源的Google Nexus 10平板电脑)。到目前为止,我在测试的设备上都可以工作(Google Nexus 10、三星Galaxy S3、S4和S5、Nexus 4和5等等...)

我最近听说有用户在HTC One X+手机上运行时遇到了问题(我相信除了我在此谈论的问题之外还有其他原因,所以我已经打开了一个单独的问题来处理其他问题)。

根据 this,这款手机的最大纹理尺寸为2048x2048,但又根据this,此手机从XHDPI文件夹获取资源。所以,它无法显示来自此图集(包含6个分别为1280*612的背景)的纹理。 现在我知道两种解决方法:
  • 减小背景的大小。排除此选项,因为这会影响较大屏幕设备(例如nexus 10)的质量。

  • 分成2个图集不想这样做,因为希望将所有背景都放在一个图集中以优化加载速度(并且只是为了保持整洁)

还有其他选项吗?我能否在xhdpi的子文件夹中提供另一个符合1X +限制的文件夹?如果可以,如何让设备从那里获取资源?

我是盲目地进行此操作,因为我没有1X +来测试它,但从我所读的资料中,我相信拥有大于2048 x 2048的资源将会在这个设备上引起问题。

这是我的应用纹理的代码:

public static int LoadTexture(GLSurfaceView view, Bitmap imgTex){

    //Array for texture
    int textures[] = new int[1];
    try {
        //texture name
        GLES20.glGenTextures(1, textures, 0);
        //Bind textures
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
        //Set parameters for texture
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);

        //Apply texture
        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, imgTex, 0);

        //clamp texture
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE);

    } catch (Exception e){

    }
    //Increase texture count
    textureCount++;
    //Return texture
    return textures[0];
}
1个回答

2
如果您不确定纹理加载是否有效,可以执行所有相同的操作,只需使用 GL_PROXY_TEXTURE_2D(或1D、3D等)而非 GL_TEXTURE_2D 来检查加载是否对给定纹理大小和参数有效。OpenGL 尝试执行此加载,并且如果加载失败或存在纹理参数的其他问题,则将所有纹理状态设置为0。然后,如果纹理加载失败(例如,由于图像太大),请让您的程序加载较小的缩放纹理。

编辑:我使用的是 iOS,我的 gl.h 不包括 GL_PROXY_TEXTURE_*,并且我在 OpenGL ES3 规范中找不到任何参考资料,因此我不确定这是否适用于 OpenGL。

另外,获取您的最大纹理大小(每个维度,例如宽度、高度或深度),并使用适当的图像大小进行加载:

glGetIntegerv( GL_MAX_TEXTURE_SIZE, &size );

之后,请检查您的图片以确保它正常工作。
GLuint name;
int width = 10000;  // really bad width
int height = 512;
GLint size;

glGenTextures( 1, &name );
glBindTexture( GL_TEXTURE_2D, name );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,  width, height, 0,
             GL_RGBA, GL_UNSIGNED_BYTE, 0);

GLenum error = glGetError();
if( error ) {
    printf("Failed!");
}
else {
    printf("Succeeded!");
}

嗨@MtRoad,我没有设备可以测试这个(好吧,没有一个展示问题的设备),但是我已经进行了快速的谷歌搜索,我找不到任何关于如何使用GL_PROXY_TEXTURE_*D的例子。您可以编辑您的答案并提供一个例子吗?谢谢。我将编辑我的问题以包含我的纹理代码。 - Zippy
是的,我刚刚实现了检查功能,并在一个故意过大的纹理上进行了测试,它成功地返回了“Invalid_value”错误,所以这部分代码可以检测到纹理过大的情况。然而,问题是-接下来该怎么办呢?一旦失败了,我该如何让代码从其他资源文件夹中加载一个较小版本的纹理呢?我找不到相关信息! - Zippy
在低分辨率的显示器上使用超高质量的纹理是没有意义的,因此您可以将纹理质量分类为低、中、好、高,而不是ldpi、mdpi、hdpi和xhdpi。然后在每个文件夹中保留最佳和所有较低质量的图像(在ldpi中为低, 在mdpi中为低/中,在hdpi中为低/中/好等),然后根据GL_MAX_TEXTURE_SIZE选择最佳纹理。或者,您可以在上传到OpenGL之前自行降低纹理的分辨率。 - pyj
是的,我已经基本上明白了,LDPI中的低质量,然后是MDPI中的高质量,然后是HDPI中的更高质量,最后在XHDPI中的最高质量,但是当我加载资源时,设备会自动选择从哪个文件夹获取其资源。我的问题是如何强制它从另一个文件夹中获取。如果您看到我问题中的链接,X1+被列为XHDPI,这意味着它将从XHDPI文件夹中获取其资源-与我的超高分辨率Nexus 10平板电脑相同。 - Zippy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接