Android Opengl-es加载非2次纹理的力量

时间:2011-04-18 16:10:28

标签: android opengl-es bitmap textures

我有一个应用程序,我一直在android中使用它,它使用opengl-es。

目前我从位图加载纹理如下:

//Load up and flip the texture - then dispose the temp
    Bitmap temp = BitmapFactory.decodeResource(Deflecticon.getContext().getResources(), resourceID);
    Bitmap bmp = Bitmap.createBitmap(temp, 0, 0, temp.getWidth(), temp.getHeight(), flip, true);
    temp.recycle();

    //Bind the texture in memory
    gl.glBindTexture(GL10.GL_TEXTURE_2D, id);

    //Set the parameters of the texture.
    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);

    //On to the GPU
    GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0);

显而易见的问题是我使用的纹理必须是2的强度。目前我正在预编辑photoshop中的纹理是2的幂并且只有空边框。然而,这有点乏味,我希望能够像它们一样加载它们。认识到它们不是2的力量并将它们加载到纹理中。

我知道我可以缩放位图以成为2大小的力量并简单地拉伸纹理但是我不希望拉伸纹理,并且在某些情况下可能想要将几个纹理放入一个“地图集”。

我知道我可以使用glTexSubImage2D()将纹理粘贴到我想要的原点所需的数据中。这很棒!

但是我不知道在Android中如何初始化没有数据的纹理?

在这个问题previously asked中,建议是在没有数据的情况下调用glTexImage2D()然后填充它。

但是在android中调用“GLUtils.texImage2D(GL10.GL_TEXTURE_2D,0,bmp,0)”时;你没有指定宽度/高度。它从我假设的位图读取。

最好的方法是什么?我是否可以创建一个仅2个大小的正确幂的新位图空白并且没有填充任何数据并使用它来初始化纹理然后使用subImage粘贴到它中?或者我应该以某种方式将新的位图以某种方式复制到我想要的像素(不确定是否可以轻松完成)到这个新的位图(离开边框)然后使用它?

编辑:澄清我正在使用opengl。

5 个答案:

答案 0 :(得分:4)

我认为如果你尝试使用2轴大小的功能创建一个位图然后添加你的位图它应该工作得很好。也许像是

Bitmap.createBitmap(notPowerOf2Bitmap, offx, offy, xsize, ysize, bitmapFlag)
除此之外,我会说通过photoshop程序受苦。你有多少张照片?

答案 1 :(得分:2)

某些GLES平台支持非二次幂(NPOT)位图,但您必须检查是否存在相应的扩展名。但请注意,至少在PowerVR SGX上,即使支持NPOT,仍然存在一些其他相当随意的限制;例如,您的纹理宽度必须是2的倍数(如果不是2的幂)。此外,许多GPU上的NPOT渲染往往会慢一些。

你可以做的一件事就是创建一个两个大小的包装器纹理,然后使用glTexSubimage2D上传纹理以仅覆盖其中的一部分,然后相应地调整纹理坐标。这方面的明显缺点是在这种情况下你不能使用纹理包装。如果你绝对必须支持包装,你可以在调用glTexImage2D之前将纹理缩放到最接近的二次幂大小,尽管这通常会引入采样伪像并使事情变得模糊,特别是如果你想要做像素精确的2D工作

如果你不需要支持包装,你可以考虑的另一件事是制作一个“纹理图集”,在其中你将所有纹理压缩成几个大纹理,并让你的多边形映射到一些纹理图谱的一部分。生成MIPmaps时必须小心,但除此之外,它通常会提供非常好的性能优势,并且可以更有效地使用纹理内存,因为您不会在填充或缩放的图像上浪费太多。

答案 2 :(得分:2)

我已经为此问题采用了2种解决方案。如果有必要,我可以更具体,但从概念上讲,你可以: -

  1. 使图像的幂为2,裁剪部分用100%alpha通道填充并加载启用了Alpha的图像。

  2. 调整纹理矢量/缓冲区,使其不加载该部分。所以不要使用默认的

    float texture[] = { 
        0.0f, 1.0f, //
        1.0f, 1.0f, //
        0.0f, 0.0f, //
        1.0f, 0.0f, //
    };
    
  3. 作为矩阵(显然这是用于将图像加载到2个三角形的正方形),按比例回归到裁剪的区域,例如。

        float texture[] = { 
            0.0f, 0.75f, //
            0.9f, 0.75f, //
            0.0f, 0.0f, //
            0.9f, 0.0f, //
         };
    

    当然,准确地说你的数学或不想要的位可能会流血,或者你会删除一些真实的图像。显然,这个数组是动态计算的,而不像我在这里演示的那样硬编码。

答案 3 :(得分:0)

呃,为什么不创建两个位图。在你正在做的时加载第一个,然后使用createBitmapScaled将该位图转换为2的幂。性能方面我不知道它是否是最快的方法,但它的工作原理。

答案 4 :(得分:0)

你可以使用GLES20.glTexImage2D()来创建具有指定宽度和高度的空纹理。示例代码是

public static int genTexture(int texWidth, int texHeight) {
    int[] textureIds = new int[1];
    GLES20.glGenTextures(1, textureIds, 0);
    assertNoError();
    int textureId = textureIds[0];
    texWidth = Utils.nextPowerOf2(texWidth);
    texHeight = Utils.nextPowerOf2(texHeight);

    GLES20.glBindTexture(GL11.GL_TEXTURE_2D, textureId);
    GLES20.glTexParameteri(
            GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(
            GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
            GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
            GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);

    GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA,
            texWidth, texHeight, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);

    return textureId;
}
相关问题