1

我对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。

如何构建一种方法来显示位图而不在所有设备上进行条带化,并且没有任何设备显示大白框?

4

3 回答 3

1

OpenGL.org对这个错误有这样的说法:

GL_INVALID_VALUE​, 0x0501:当值参数不是该函数的 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);

于 2012-04-25T20:03:41.257 回答
1

获取位图1

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

获取位图2

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

问题:原始的Bitmap Resource是正方形的吗?如果不是,您的缩放代码将更改可能导致伪影的纵横比。

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

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

于 2012-04-25T20:05:21.547 回答
1

色带解决了ooooooooooyyyyyyyeaaaaaaaaaa

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

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;

}

如果我错了,请纠正我。如果它对你有用,也可以评论。

我很高兴我解决了它,希望它对你有用。

于 2012-04-26T18:03:00.217 回答