【问题标题】:Loading Texture in Android OpenglEs 2.0 result in no color at all在 Android OpenglEs 2.0 中加载纹理根本没有颜色
【发布时间】:2015-09-16 05:17:46
【问题描述】:

我之前有我的工作方法,但是我看到有一些东西没有优化。我试图上传带有 RGB_565 或 ARGB_4_4_4_4 配色方案的纹理,但我使用的是第一个字节和最后一个字节的 3 个字节。事实上,如果我使用 RGB_565,我只需要 2 个字节(5+6+5 位),第二个字节也是如此。所以我做了我的修改,但现在它不起作用,而且肯定是我忘记或做错了。

如果您想比较,您可以找到函数中注释掉的旧代码。 任何帮助将不胜感激。

这是代码:

///
//  Load texture from InputStream
//
private int loadTexture(InputStream is) {
    int[] textureId = new int[1];
    Bitmap reversedBitmap, bitmap;

    BitmapFactory.Options opts = new BitmapFactory.Options();
    opts.inPreferredConfig = Bitmap.Config.RGB_565;
    reversedBitmap = BitmapFactory.decodeStream(is, null, opts);
    //reversedBitmap = BitmapFactory.decodeStream(is);

    if (reversedBitmap == null) {
        throw new RuntimeException("Texture.loadTexture: depuracion");
    }

    int width = reversedBitmap.getWidth();
    int height = reversedBitmap.getHeight();

    Matrix flip = new Matrix();
    flip.postScale(1f, -1f);
    bitmap = Bitmap.createBitmap(reversedBitmap, 0, 0, width, height, flip, true);

    reversedBitmap.recycle();

    // int bitmapFormat = bitmap.getConfig() == Bitmap.Config.ARGB_8888 ? GLES20.GL_RGBA : GLES20.GL_RGB;

    int bitmapFormat = bitmap.getConfig() == Bitmap.Config.ARGB_4444 ? GLES20.GL_RGBA4 : GLES20.GL_RGB565;

    byte[] buffer = null;
    /*
    if (bitmapFormat == GLES20.GL_RGB) {
        buffer = new byte[width * height * 3];
    } else if (bitmapFormat == GLES20.GL_RGBA) {
        buffer = new byte[width * height * 4];
    }
    */
    if (bitmapFormat == GLES20.GL_RGB565) {
        buffer = new byte[width * height * 2];
    } else if (bitmapFormat == GLES20.GL_RGBA4) {
        buffer = new byte[width * height * 2];
    }

    int[] pixelArray;
    pixelArray = new int[width * height];
    bitmap.getPixels(pixelArray, 0, width, 0, 0, width, height);

    for (int y = 0; y < height; y++) {

        for (int x = 0; x < width; x++) {
/*
            int pixel = pixelArray[x + y * width];

            if (bitmapFormat == GLES20.GL_RGB) {
                buffer[(y * width + x) * 3 + 0] = (byte) ((pixel >> 16) & 0xFF);
                buffer[(y * width + x) * 3 + 1] = (byte) ((pixel >> 8) & 0xFF);
                buffer[(y * width + x) * 3 + 2] = (byte) ((pixel >> 0) & 0xFF);
            } else if (bitmapFormat == GLES20.GL_RGBA) {
                buffer[(y * width + x) * 4 + 0] = (byte) ((pixel >> 16) & 0xFF);
                buffer[(y * width + x) * 4 + 1] = (byte) ((pixel >> 8) & 0xFF);
                buffer[(y * width + x) * 4 + 2] = (byte) ((pixel >> 0) & 0xFF);

                // ALPHA CHANNEL
                buffer[(y * width + x) * 4 + 3] = (byte) ((pixel >> 24) & 0xFF);
            }
*/
            int pixel = pixelArray[x + y * width];

            if (bitmapFormat == GLES20.GL_RGB565) {
                /*
                buffer[(y * width + x) * 3 + 0] = (byte) ((pixel >> 11) & 0x1F); // color rojo empieza en el bit 11 y se debe hacer and logico con 1F pues ocupa 5 caracteres
                buffer[(y * width + x) * 3 + 1] = (byte) ((pixel >> 5) & 0x3F);
                buffer[(y * width + x) * 3 + 2] = (byte) ((pixel >> 0) & 0x1F);
                */
                byte red = (byte) ((pixel >> 11) & 0x1F);
                byte green = (byte) ((pixel >> 5) & 0x3F);
                byte blue = (byte) ((pixel >> 0) & 0x1F);

                // desplazamos red tres dígitos a la izquierda que es lo que queda libre del byte al ser red de 5 bits
                byte first_byte = (byte) (red << 3);
                // desplazamos tres bits a la derecha y aplicamos la máscara con and lógico
                byte auxiliar_green_first_byte = (byte) ((green >> 3) & 0x7); // máscara 7 => 0000000111
                // ya podemos calcular el primer byte
                first_byte = (byte) (first_byte | auxiliar_green_first_byte);
                // creamos un nuevo auxiliar para manejar la parte baja de green
                // desplazamos la parte baja de green cinco bits y hacemos un and lógico con la máscara E0 para dejar hueco a blue
                byte auxiliar_green_second_byte = (byte) ((green << 5) & 0xE0); // máscara E0 => 11100000
                // ya podemos calcular el segundo byte = auxiliar_green_second_byte | blue;
                byte second_byte = (byte) (auxiliar_green_second_byte | blue);

                // almacenamos los resultados del pixel
                buffer[(y * width + x) * 2 + 0] = first_byte;
                buffer[(y * width + x) * 2 + 1] = second_byte;


            } else if (bitmapFormat == GLES20.GL_RGBA4) {
                /*
                buffer[(y * width + x) * 4 + 0] = (byte) ((pixel >> 16) & 0xFF);
                buffer[(y * width + x) * 4 + 1] = (byte) ((pixel >> 8) & 0xFF);
                buffer[(y * width + x) * 4 + 2] = (byte) ((pixel >> 0) & 0xFF);

                // ALPHA CHANNEL
                buffer[(y * width + x) * 4 + 3] = (byte) ((pixel >> 24) & 0xFF);
                */
                byte red = (byte) ((pixel >> 8) & 0xF);
                byte green = (byte) ((pixel >> 4) & 0xF);
                byte blue = (byte) ((pixel >> 0) & 0xF);

                byte alpha = (byte) ((pixel >> 12) & 0xF);

                // movemos red 4 bits a la izquierda y aplicamos máscara 11110000
                byte first_byte = (byte) ((red << 4) & 0xF0);

                // tras haber desplazado red procedemos a calcular definitivamente fist_byte con red or green
                first_byte = (byte) (first_byte | green); // green ya está desplazado en los 4 últimos bits, no hace falta manipularlo

                // movemos blue 4 bits a la izquierda y aplicamos máscara 11110000
                byte second_byte = (byte) ((blue << 4) & 0xF0);
                // tras haber desplazado blue procedemos a calcular definitivamente second byte con la operación nuevo blue OR LOGICO alpha
                second_byte = (byte) (second_byte | alpha); // alpha ya está desplazado en los 4 últimos bits, no hace falta manipularlo

                buffer[(y * width + x) * 2 + 0] = first_byte;
                buffer[(y * width + x) * 2 + 1] = second_byte;
            }
        }


    }
    ByteBuffer byteBuffer = null;
    /*
    if (bitmapFormat == GLES20.GL_RGB) { // 3 bytes, 1 por canal
        byteBuffer = ByteBuffer.allocateDirect(width * height * 3);
    } else if (bitmapFormat == GLES20.GL_RGBA4) { // 4 bytes, 1 por canal
        byteBuffer = ByteBuffer.allocateDirect(width * height * 4);
    }
    */
    if (bitmapFormat == GLES20.GL_RGB565) { // 3 bytes, 1 por canal
        byteBuffer = ByteBuffer.allocateDirect(width * height * 2);
    } else if (bitmapFormat == GLES20.GL_RGBA4) { // 4 bytes, 1 por canal
        byteBuffer = ByteBuffer.allocateDirect(width * height * 2);
    }
    byteBuffer.put(buffer).position(0);

    GLES20.glGenTextures(1, textureId, 0);

    this.m_TextureID = textureId[0];

    bind();

    setFilters(this.m_MinifyFilter, this.m_MagnifyFilter);
    // GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR );
    // GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR );
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);


    /*

    GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, bitmapFormat, width, height, 0,
                bitmapFormat, GLES20.GL_UNSIGNED_BYTE, byteBuffer);
     */

    if (bitmapFormat == GLES20.GL_RGB565) {
        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, bitmapFormat, width, height, 0,
                bitmapFormat, GLES20.GL_UNSIGNED_SHORT_5_6_5, byteBuffer);
    } else if (bitmapFormat == GLES20.GL_RGBA4) {
        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, bitmapFormat, width, height, 0,
                bitmapFormat, GLES20.GL_UNSIGNED_SHORT_4_4_4_4, byteBuffer);
    }

    // this.textureId = textureId[0];
    pixelArray = null; // Para que el recolector libere el tamaño del array de la imagen en memoria

    if ((m_MinifyFilter == GLES20.GL_LINEAR_MIPMAP_LINEAR) ||
            (m_MinifyFilter == GLES20.GL_LINEAR_MIPMAP_NEAREST) ||
            (m_MinifyFilter == GLES20.GL_NEAREST_MIPMAP_LINEAR) ||
            (m_MinifyFilter == GLES20.GL_NEAREST_MIPMAP_NEAREST)) {

        GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);
    }

    unbind();
    bitmap.recycle();
    try {
        is.close();
    } catch (IOException e) {
        Log.e("Texture.loadTexture: ", " error closing inputStream");
    }
    return textureId[0];
}

编辑 1:

我正在编辑,因为我看到将 rgb888 纹理转换为 rgb565 纹理的结果非常糟糕。我按照@samgak 建议的方法,一切看起来都正常,但颜色非常失真。我正在上传两个捕获,第一个是 rgb888 并且看起来不错,就像它应该做的那样。第二个是带畸变的转换。这种转变正常吗?如果是,我将不得不将纹理保持为完整的 rgb888 格式

精心绘制的框架:

立方体是碰撞系统的边界体

解决了。问题是我以错误的字节顺序(无字节序/大字节序)获取字节缓冲区,并按照@samgak 的建议交换了第一个和第二个字节。

【问题讨论】:

    标签: java android optimization opengl-es textures


    【解决方案1】:

    GLES20.GL_RGB565GLES20.GL_RGBA4 不是传递给 glTexImage2D 的有效值:

    internalformat 指定纹理的内部格式。必须是以下符号常量之一:GL_ALPHA、GL_LUMINANCE、GL_LUMINANCE_ALPHA、GL_RGB、GL_RGBA。

    当使用 glTexImage2D 上传 RGB 565 纹理时,您应该为 formatinternalformat 传递 GLES20.GL_RGB,为 type 传递 GLES20.GL_UNSIGNED_SHORT_5_6_5 >。同样对于 RGBA 4444 纹理,传递 GLES20.GL_RGBAGLES20.GL_UNSIGNED_SHORT_4_4_4_4

    例如:

    GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGB, width, height, 0,
        GLES20.GL_RGB, GLES20.GL_UNSIGNED_SHORT_5_6_5, byteBuffer);
    

    GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0,
        GLES20.GL_RGBA, GLES20.GL_UNSIGNED_SHORT_4_4_4_4, byteBuffer);
    

    GLES20.GL_RGB565GLES20.GL_RGBA4 用于在调用 glRenderbufferStorage 时指定渲染缓冲区的内部格式

    【讨论】:

    • 谢谢!你的帖子太有用了!无论如何,你能看看我改变颜色的方式以及我是如何做逻辑的吗?我要求这个是因为现在,在听从你的建议后,我的纹理有蓝色调
    • 对于565转换,试试这个:byte red = (byte) ((pixel >> 19) & 0x1F);字节绿色 = (字节) ((像素 >> 10) & 0x3F);字节蓝色 = (字节) ((像素 >> 0) & 0x1F);无论位图格式如何,Bitmap.getPixels() 都会返回 ARGB8888。但是 Bitmap.copyPixelsFromBuffer() 以内部格式返回
    • 非常感谢@samgak 的帮助。它工作得更好,但不幸的是我一定做错了什么,或者转换正在使纹理产生某种失真。我编辑了帖子以添加两张图片。你能告诉我你认为这种行为是否正常吗?
    • 不正常,你的颜色转换有问题。尝试交换第一个和第二个字节。
    • 另外,考虑在 GLUtils 类中使用 texImage2D 函数:developer.android.com/reference/android/opengl/GLUtils.html
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-23
    • 1970-01-01
    相关资源
    最近更新 更多