【问题标题】:Android Opengl-es loading a non-power of 2 textureAndroid Opengl-es 加载非 2 次幂纹理
【发布时间】:2011-04-18 16:10:27
【问题描述】:

我有一个我在 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。

【问题讨论】:

    标签: android opengl-es bitmap textures


    【解决方案1】:

    我认为,如果您尝试创建具有 2 个轴大小的位图,然后添加您的位图,它应该可以正常工作。也许像

    Bitmap.createBitmap(notPowerOf2Bitmap, offx, offy, xsize, ysize, bitmapFlag)
    

    除此之外,我会说通过 Photoshop 过程受苦。你有多少张照片?

    【讨论】:

    • 不是太多,只是我们希望以后可以更改它们,如果调整大小做得很好,它会更容易!这个方法说它需要一个 nonPOTBitmap 的子集,这是否意味着如果子集位图小于指定的 xSize 和 ySize 它会有空白边缘?还是会拉伸它? (我会尝试,但遗憾的是不在我的编码电脑上)。
    • 位图不应该拉伸,除非它们被扔到 createScaledBitmap 方法中。剩余空间将为空。
    • 抱歉,回复延迟,我一直在做其他事情,但是我开始实际实现这一点,但通过这种方法不起作用。您不能将位图分成比源文件更大的位图...我现在有点不知所措。
    • 嗯...当时我唯一能想到的就是创建一个位图,为其分配一个画布并将未缩放的位图绘制到画布上,然后使用新的位图。它的资源有点重,但这是我能想到的唯一其他事情......
    • 等等,哪个有效?上面的书面解决方案还是评论中的解决方案?上面的书面解决方案是否被修改?这已被接受。
    【解决方案2】:

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

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

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

    【讨论】:

    • 正如我的问题所述,您如何在 android 中制作您采样的包装纹理?最好的方法是什么?
    • 查看 glTexSubimage2D 的文档。
    【解决方案3】:

    我为这个问题采用了 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, //
      };
      

    作为矩阵(显然这是用于将图像加载到 2 个三角形的正方形),按面积与裁剪的比率返回因子,例如。

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

    当然,请务必准确计算,否则可能会渗入不需要的部分,否则您会剪掉一些真实图像。显然,这个数组是动态计算的,而不是像我在这里演示的那样硬编码。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        您可以使用 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;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-07-07
          • 1970-01-01
          • 2016-07-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多