簡體   English   中英

在 Android OpenglEs 2.0 中加載紋理導致根本沒有顏色

[英]Loading Texture in Android OpenglEs 2.0 result in no color at all

我之前有我的工作方法,但我看到有一些沒有優化的地方。 我試圖上傳帶有 RGB_565 或 ARGB_4_4_4_4 配色方案的紋理,但我在第一個使用了 3 個字節,在最后一個使用了 4 個字節。 事實上,如果我使用 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 的建議交換了第一個和第二個字節。

GLES20.GL_RGB565GLES20.GL_RGBA4不是傳遞給glTexImage2D 的有效值:

internalformat指定紋理的內部格式。 必須是以下符號常量之一:GL_ALPHA、GL_LUMINANCE、GL_LUMINANCE_ALPHA、GL_RGB、GL_RGBA。

當上傳使用glTexImage2D的RGB 565的質感,你應該通過GLES20.GL_RGB格式internalformat,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 時指定渲染緩沖區的內部格式

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM