【问题标题】:opengl making many textures power of 2opengl制作许多纹理2的幂
【发布时间】:2012-12-06 06:45:48
【问题描述】:

我有许多 (113) 由搅拌机创建的纹理图像(一个 obj 和一个引用纹理的 mtl 文件)不是 2 的幂。当我尝试使用单个纹理(2 的幂)渲染一个简单对象时,它可以工作很好,但是对于我上面描述的复杂对象,它只绘制几何图形(一切都是白色的,没有纹理)。

这是因为我的纹理尺寸吗?如果是,是否有解决方案可以在运行时制作许多纹理/位图的二次幂? (我不知道尺寸。)

我也怀疑glbindtexture 是否正确使用(我正在使用Android。) 首先,我打电话给glgentextures(<number_of_objects>, textureArray)。然后,在每个对象的循环中,我调用glbindtexture(..._2D, textureArray[i]) 和 GLutils.texImage2D(...)。最后,在绘图的时候,我打电话给glbindtexture(..., textureArray[i]),然后是gldrawarrays

这有什么问题吗? (已编辑)我忘了说,我正在使用 opengl es 1.1,我在某处读到 opengl es 1.1 不支持 NPOT 纹理。

提前致谢。

【问题讨论】:

  • 看起来不错.. 你有任何 GL 错误吗?在哪里..
  • 不,我不知道。对象画得很好,但没有纹理。
  • 顺便说一句,当我绑定一些随机的 POT(二的幂)纹理时,它可以工作。

标签: opengl-es textures


【解决方案1】:

运行此方法检查 OpenGL 驱动程序状态错误:

public void checkGlError(String op) {
    int error;
    while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
            Log.e("ShadingZen", op + ": glError " + error);
            //throw new RuntimeException(op + ": glError " + error);
    }
 }

根据您的测试设备,可能无法使用两种纹理的非幂次方。此代码向您展示如何将它们转换为 ^2 大小(在 android 中):

int calculateUpperPowerOfTwo(int v)
{
    v--;
    v |= v >>> 1;
    v |= v >>> 2;
    v |= v >>> 4;
    v |= v >>> 8;
    v |= v >>> 16;
    v++;
    return v;

}

boolean isPowerOfTwo(int i){
    return ( i & (i - 1)) == 0;
}


boolean loadAsTexture2D(Context context, String id, int resource_id, BitmapTexture.Parameters params){
    _bmps = new Bitmap[1];
    Matrix flip = new Matrix();
    flip.postScale(1f, -1f);

    BitmapFactory.Options opts = new BitmapFactory.Options();
    opts.inScaled = false;
    Bitmap textureBmp = BitmapFactory.decodeResource(context.getResources(), resource_id, opts);

    if(!isPowerOfTwo(textureBmp.getWidth()) || !isPowerOfTwo(textureBmp.getHeight())){
        int target_width = calculateUpperPowerOfTwo(textureBmp.getWidth());
        int target_height = calculateUpperPowerOfTwo(textureBmp.getHeight());

        Log.i("ShadingZen", "Texture id=" + id + " has no power of two dimesions " + textureBmp.getWidth() + "x" + textureBmp.getHeight() + " adjusting to " + target_width + "x" + target_height);

        Bitmap temp =  Bitmap.createBitmap(textureBmp, 0, 0, textureBmp.getWidth(), textureBmp.getHeight(), flip, false);
        _bmps[0] = Bitmap.createScaledBitmap(temp, target_width, target_height, false);
        temp.recycle();
    } else{
        _bmps[0]  = Bitmap.createBitmap(textureBmp, 0, 0, textureBmp.getWidth(), textureBmp.getHeight(), flip, false);
    }

    textureBmp.recycle();
    // At this point _bmp[0] contains a ^2 bitmap

}

查看该课程了解更多信息:https://github.com/TraxNet/ShadingZen/blob/master/library/src/main/java/org/traxnet/shadingzen/core/BitmapTexture.java

【讨论】:

  • 你能简单地说一下这段代码是做什么的吗?我的意思是它拉伸图像或添加点作为边框?
  • 它从 Android 原始资源 id 加载图像,然后检查它是否是两个图像的幂。如果不是,则查找最接近的 2 的幂并重新缩放。阅读链接中的源代码,它可以轻松处理纹理。希望有帮助。
  • 我使用了 checkGLError 函数,我得到了错误 1281。然后我应用了你的代码,没有错误了。但现在它太慢了。 (每 4-5 秒绘制一个场景,然后是黑屏),在我的日志中出现: eglLockWindowSurface: failed to map the memory for fd=*a number* offs=*another number*
  • 此代码只应在加载时应用,然后在绘图循环期间调用 Bindtexture。不应该很慢。
  • 如果加载时间很慢,请在编译时调整纹理大小或使用任何图像修饰应用程序。
【解决方案2】:

当您生成纹理时,要使用非 2 次幂的纹理,您需要启用这些参数

glGenTextures(1, &nID);
glBindTexture(GL_TEXTURE_2D, nID);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); //should probably use these
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); //these let you use NPOT textures
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

【讨论】:

  • 嗯……没用。仍然一切都是白色的,没有纹理
  • 好吧,把它保存在你的代码中,它离你解决问题更近了一步,因为你肯定需要它来处理非 2 纹理的幂。也许粘贴你的代码,这样我们就可以看到实际发生了什么。
  • 使用 TraxNet 帖子解决了加载纹理的问题。现在我在 TraxNet 帖子下面的 cmets 中描述了一个新问题。你有什么想法吗?如果你需要我的代码请告诉。我会尽快发布。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多