繁体   English   中英

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

[英]How to use high-quality rendering for an Android resource bitmap loaded into an OpenGL texture?

我对OpenGL知之甚少,所以请保持温和。

该应用程序需要加载位图(来自资源),调整其大小,并在OpenGL纹理中使用它。 我有一个可行的实现,但是在Wildfire S上有一个不好的绑定问题。所以我改变了实现并修复了绑定问题(通过切换到ARGB_8888),但这打破了Galaxy Nexus和Nexus One的功能。

我看到三个视觉呈现:

  1. 位图(平滑的24位渐变)正确显示,没有条带。

  2. 渐变显示,但有明显的条带

  3. 纹理显示为平白色,没有位图(或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。

如何构建一个显示位图而不会在所有设备上显示条带的方法,并且没有任何设备显示大白框?

OpenGL.org有关于该错误的说法:

GL_INVALID_VALUE ,0x0501:当value参数不是该函数的leval值时给定。 这仅针对当地问题; 如果规范在某些情况下允许该值,并且其他参数或状态决定了这些情况,那么GL_INVALID_OPERATION就是结果。

第一步是找到导致问题的确切opengl调用。 您将不得不进行试验和错误,以查看哪一行引发了该错误。 如果您设置程序流程如下:

glSomeCallA()
glGetError() //returns 0
glSomeCallB()
glGetError() //returns 0
glSomeCallC()  
glGetError() //returns 0x501

然后你就会知道glSomeCallC是导致错误的操作。 如果查看该特定调用的手册页,它将枚举可能导致特定错误发生的所有内容。

在你的情况下我会猜测错误将在glTexImage调用之后只是为了节省你一些时间,尽管我并不积极。

如果你看一下glTexImage手册页 ,它会在底部列出所有可能导致无效值错误的内容。 我的猜测是你的纹理大于GL_MAX_TEXTURE_SIZE。 您可以通过检查glGetIntegerv(GL_MAX_TEXTURE_SIZE);来确认这一点glGetIntegerv(GL_MAX_TEXTURE_SIZE);

getBitmap1

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

getBitmap2

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

问题:是原始的位图资源方块吗? 如果不是,您的缩放代码将改变可能导致伪像的宽高比。

编辑:那么如何缩放位图并保留位深度? 最简单的解决方案是将带有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();

另一个编辑:看看这个问题 ,了解如何处理它。

彩色条带解决了ooooooooooyyyyyyyeaaaaaaaaa

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

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

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

2)这是一个艰难的部分,并进行了大量的搜索,并最终工作*方法Bitmap.createScaledBitmap用于缩放位图也缩小了图像到RGB565格式后缩放我有带状图像(解决这个问题的旧方法是使用至少一个png中的透明像素,但没有像jpg或bmp这样的其他格式工作)所以在这里我创建了一个方法CreateScaledBitmap,用于在生成的比例位图中使用原始位图配置缩放位图(实际上我是通过logicnet.dk从帖子复制方法在java中翻译)

    BitmapFactory.Options myOptions = new BitmapFactory.Options();
    myOptions.inDither = true;
    myOptions.inScaled = false;
    myOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//important
    //myOptions.inDither = false;
    myOptions.inPurgeable = true;
    Bitmap tempImage =  
    BitmapFactory.decodeResource(getResources(),R.drawable.defaultart, myOptions);//important

    //this is important part new scale method created by someone else
    tempImage = CreateScaledBitmap(tempImage,300,300,false);

    ImageView v = (ImageView)findViewById(R.id.imageView1);
    v.setImageBitmap(tempImage);

// 功能

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;

}

如果我错了,请纠正我。 还要评论它是否适合您。

我很高兴我解决了它,希望它适合你。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM