如何对加载到OpenGL纹理中的Android资源位图使用高质量渲染?

如何对加载到OpenGL纹理中的Android资源位图使用高质量渲染?,android,opengl-es,Android,Opengl Es,我对OpenGL知之甚少,所以请温柔一点 应用程序需要(从参考资料中)加载位图,调整其大小,并在OpenGL纹理中使用它。我有一个可以工作的实现,但是Wildfire S上有一个坏的绑定问题。所以我更改了实现并修复了绑定问题(通过切换到ARGB_8888),但这破坏了Galaxy Nexus和Nexus One上的功能 我看到三个视觉演示: 位图(平滑的24位渐变)正确显示,没有带状 梯度显示,但有明显的带状 纹理显示为纯白色,无位图(或logcat中的问题) 下面是加载位图方法的两个版本,以及

我对OpenGL知之甚少,所以请温柔一点

应用程序需要(从参考资料中)加载位图,调整其大小,并在OpenGL纹理中使用它。我有一个可以工作的实现,但是Wildfire S上有一个坏的绑定问题。所以我更改了实现并修复了绑定问题(通过切换到ARGB_8888),但这破坏了Galaxy Nexus和Nexus One上的功能

我看到三个视觉演示:

  • 位图(平滑的24位渐变)正确显示,没有带状

  • 梯度显示,但有明显的带状

  • 纹理显示为纯白色,无位图(或logcat中的问题)

  • 下面是加载位图方法的两个版本,以及每个版本的结果说明:

        // White on Galaxy Nexus. White on Nexus One. Renders correct image (no banding) on Wildfire S
        private Bitmap getBitmap1() {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inPreferredConfig = Bitmap.Config.ARGB_8888;
            options.outWidth = getTextureSize();
            options.outHeight = getTextureSize();
            final Bitmap bmp;
            bmp = BitmapFactory.decodeResource(getResources(), bitmapResourceId, options);
            return bmp;
        }
    
        // Renders correctly (no banding) on Galaxy Nexus. Renders on Nexus One and Wildfire S but with obvious banding.
        private Bitmap getBitmap2() {
            int textureSize = getTextureSize();
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inPreferredConfig = Bitmap.Config.ARGB_8888;
            options.outWidth = getTextureSize();
            options.outHeight = getTextureSize();
            final Bitmap bmp;
            bmp = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), bitmapResourceId, options), textureSize, textureSize, true);
            return bmp;
        }
    
    getTextureSize()返回1024

    我如何构建一个方法来显示位图,而不在所有设备上绑定,并且不在任何设备上显示一个大的白色框?

    关于该错误有这样的说法:

    GL\u无效值
    ​, 0x0501:值参数不是leval时给定 该函数的值。这只适用于局部问题;如果 等级库允许在某些情况下使用该值和其他参数 或状态指示这些情况,则GL_INVALID_操作为 结果相反

    第一步是找到导致问题的opengl调用。您必须进行反复试验,以查看哪一行抛出了该错误。如果按如下方式设置程序流:

    glSomeCallA()
    glGetError() //returns 0
    glSomeCallB()
    glGetError() //returns 0
    glSomeCallC()  
    glGetError() //returns 0x501
    
    然后您将知道
    glSomeCallC
    是导致错误的操作。如果查看该特定调用的手册页,它将枚举可能导致特定错误发生的所有内容

    在您的情况下,我猜错误将发生在glTexImage调用之后,只是为了节省您一些时间,尽管我不是肯定的


    如果查看,它将在底部列出所有可能导致无效值错误的内容。我猜你的纹理比GL_MAX_纹理尺寸大。您可以通过检查
    glGetIntegerv(GL\u MAX\u TEXTURE\u SIZE)来确认这一点

    获取位图1

    outHeight和outheidth与injustbounds一起使用。不能使用它们加载缩放位图。因此,您看到白色纹理的原因是位图不是二的幂

    getBitmap2

    您应该保留对decodeResource返回的位图的引用,以便以后可以回收它。 同时使用
    options.inScaled=false
    加载位图的未缩放版本。还要注意,如果原始位图不包含alpha通道(),createScaledBitmap可能会将位图的深度更改为RGB_565

    问题: 原始位图是否为方形?如果没有,缩放代码将更改纵横比,这可能会导致工件

    编辑: 那么如何缩放位图并保留位深度呢? 最简单的解决方案是将带有alpha通道的位图传递到createScaledBitmap。 您也可以这样缩放自己:

                        Bitmap newBitmap = Bitmap.createBitmap(1024, 1024, Bitmap.Config.ARGB_8888);
                        Canvas canvas = new Canvas(newBitmap);
                        final int width = src.getWidth();
                        final int height = src.getHeight();
                        final float sx = 1024  / (float)width;
                        final float sy = 1024 / (float)height;
                        Matrix m = new Matrix();
                        m.setScale(sx, sy);
                        canvas.drawBitmap(src,m,null );
                        src.recycle();
    
    另一编辑:
    看看这个,看看如何处理这个问题。

    色带解决了ooooooooyyyyyyyaaaaaaaaaaaaaa

    我分两个阶段解决了色带问题

    1) *当我们使用BitmapFactory解码资源时,它会解码RGB565中显示色带的资源,而不是使用ARGB_8888,因此我使用BitmapFactory.Options将解码选项设置为ARGB_8888

    第二个问题是,每当我缩放位图时,它就会再次被绑定

    2) 这是一个艰难的部分,经过了大量的搜索,终于成功了 *用于缩放位图的方法Bitmap.createScaledBitmap在缩放我得到的带状图像后也将图像缩减为RGB565格式(解决此问题的旧方法是在png中使用至少一个透明像素,但没有其他格式(如jpg或bmp)工作)因此,我在这里创建了一个方法CreateScaledBitmap,以使用生成的缩放位图中的原始位图配置来缩放位图(实际上,我从logicnet.dk的文章中复制了该方法,并用java翻译)

    //功能

    public static Bitmap CreateScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)
    {
        Matrix m = new Matrix();
        m.setScale(dstWidth  / (float)src.getWidth(), dstHeight / (float)src.getHeight());
        Bitmap result = Bitmap.createBitmap(dstWidth, dstHeight, src.getConfig());
        Canvas canvas = new Canvas(result);
        //using (var canvas = new Canvas(result))
        {
            Paint paint = new Paint();
            paint.setFilterBitmap(filter);
            canvas.drawBitmap(src, m, paint);
        }
        return result;
    
    }
    
    如果我错了,请纠正我。 如果它对你有用,也要发表评论


    我很高兴我解决了它,希望它能为您工作。

    对于白色的手机,您能否尝试在程序流中插入GLGETRERROR调用,看看它是否返回任何内容?如果返回值不为零,则表示存在某种问题的错误代码。不正确的opengl api使用不一定会在logcat中看到任何问题,除非您检查错误代码,否则它会自动失败。谢谢Tim。错误代码是1281.0。那么,如何使用RGB_8888创建缩放版本?切换到888后,两部较小的手机上的条纹消失了,因此获得高质量渲染的关键似乎是使用888。我想我可以手动将位图缩放到1024x1024,然后在不缩放的情况下加载它。嗯,原来的位图不是正方形的,虽然我只是尝试了一个缩放版本,1024x1024,我得到了相同的结果(缩放代码不存在)。不幸的是,我想我现在更困惑了。我似乎有两个选择。a) 使用大小为1024x1024但不可缩放的位图(保留为888),或b)加载位图并缩放它,同时保持888格式(不知道如何执行)。因此,您使用getBitmap1和32位方形位图以及选项。inScaled=false,纹理仍然是带状或白色?您需要确保的是:32位的纹理,即pot。此外,您的EGLSurface需要为32位。调用setEGLConfigChooser(8,8,8,8,16,0)以确保。我已将位图大小调整为1024x1024,并按照建议设置ConfigChooser。我还使用isScaled=false。纹理显示在所有设备上,但在两个较小的设备上都有严重的带状(Galaxy Nexus ok,看起来很棒)。纹理正适合t
    public static Bitmap CreateScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)
    {
        Matrix m = new Matrix();
        m.setScale(dstWidth  / (float)src.getWidth(), dstHeight / (float)src.getHeight());
        Bitmap result = Bitmap.createBitmap(dstWidth, dstHeight, src.getConfig());
        Canvas canvas = new Canvas(result);
        //using (var canvas = new Canvas(result))
        {
            Paint paint = new Paint();
            paint.setFilterBitmap(filter);
            canvas.drawBitmap(src, m, paint);
        }
        return result;
    
    }