之前我有我的工作方法,但我看到有些东西没有优化。我试图使用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格式
精心绘制的框架:
多维数据集是碰撞系统的绑定卷
解决。问题是我以错误的字节顺序获取bytebuffer(无字节/大端)并将第一个和第二个字节交换为@samgak建议。
答案 0 :(得分:2)
GLES20.GL_RGB565
和GLES20.GL_RGBA4
不是传递给glTexImage2D的有效值:
internalformat 指定纹理的内部格式。必须是以下符号常量之一:GL_ALPHA,GL_LUMINANCE,GL_LUMINANCE_ALPHA,GL_RGB,GL_RGBA。
使用glTexImage2D上传RGB 565纹理时,您应该为格式和 internalformat 传递GLES20.GL_RGB
,为传递GLES20.GL_UNSIGNED_SHORT_5_6_5
输入的。同样,对于RGBA 4444纹理,请传递GLES20.GL_RGBA
和GLES20.GL_UNSIGNED_SHORT_4_4_4_4
e.g:
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_RGB565
和GLES20.GL_RGBA4
用于在调用glRenderbufferStorage