读取 ATI 压缩纹理时出现问题

Problems reading ATI compressed textures

我正在尝试在我的 android 应用程序中使用压缩纹理。我在加载纹理时遇到问题,纹理似乎 "cut-off" 在对象的右侧。

为了压缩纹理,我使用的是 ATI 的 "TheCompressonator"。 为了进行测试,我使用的是 Nexus 5。

我怀疑问题出在我的 "calculated" 纹理大小上,但找不到此压缩格式的任何参考资料/规范。

有谁知道如何正确阅读这种文件格式?

这是来自 nexus 的屏幕截图:

这是它应该看起来的样子(不要介意黑色物体纹理,它的图像丢失了)

这是我的代码片段。

final int[] textureObjectIds = new int[1];

glGenTextures(1, textureObjectIds, 0);

if(textureObjectIds[0] == 0){
    logTextureHelper(Log.WARN, "Could not generate a new OpenGL texture object");
    return 0;
}

final InputStream bitmap = context.getResources().openRawResource(resourceId);
byte[] buffer;
ByteBuffer bf;

try {
    buffer = new byte[bitmap.available()];
    bitmap.read(buffer);

    int offset = 0; // 64 bit = header, 15 bit = metadata
    bf = ByteBuffer.wrap(buffer, offset, buffer.length-offset);
    bf.order(ByteOrder.LITTLE_ENDIAN);

    int height = bf.getInt(16);
    int width = bf.getInt(12);


    int size = ((height + 3) / 4) * ((width + 3) / 4) * 16;
    Log.d("TextureHelper","Buffer size: "+width+" "+height+" "+size);

    glBindTexture(GL_TEXTURE_2D, textureObjectIds[0]);

    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
    glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
    glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);


    GLES20.glCompressedTexImage2D(GL_TEXTURE_2D, 0,ATC_RGBA_EXPLICIT_ALPHA_AMD, width, height, 0, size, bf);
    Log.d("TextureHelper","Buffer size: "+bf.capacity()+"   : "+buffer.length+" error:"+GLES20.glGetError());

    glBindTexture(GL_TEXTURE_2D, 0); //unbind texture

} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

return textureObjectIds[0];

编辑:解决方案

buffer = new byte[bitmap.available()];
            bitmap.read(buffer);

            int offset = 128; // 64 bit = header, 15 bit = metadata
            bf = ByteBuffer.wrap(buffer, offset, buffer.length-offset);
            bf.order(ByteOrder.LITTLE_ENDIAN);

            int height = bf.getInt(16);
            int width = bf.getInt(12);


            int size = ((height + 3) / 4) * ((width + 3) / 4) * 16;
            Log.d("TextureHelper","Buffer size: "+width+" "+height+" "+size);


            bf.compact();///////SOLUTION!
            bf.position(0);


            glBindTexture(GL_TEXTURE_2D, textureObjectIds[0]);

            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
            glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
            glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);


            GLES20.glCompressedTexImage2D(GL_TEXTURE_2D, 0,ATC_RGBA_EXPLICIT_ALPHA_AMD, width, height, 0, size, bf);
            Log.d("TextureHelper","Buffer size: "+bf.capacity()+"   : "+buffer.length+" error:"+GLES20.glGetError());

            glBindTexture(GL_TEXTURE_2D, 0); //unbind texture

注意:需要在0位置有数据,如果只是偏移position(128)会抛出无效指针异常。

您的尺寸计算看起来是正确的,但您上传的 header 作为图像数据。 从 header 中提取宽度和高度后,将字节缓冲区偏移适当的量以跳过 header 并开始指向图像数据。

有几种方法可以做到这一点,但像这样的方法可以作为一个例子(可以优化以删除第二个字节缓冲区)。另外,我不确定你使用的是什么纹理格式,但我们假设你的 header 是,哦,124 字节长。

// assumption that buffer[] is the fully loaded contents of the file
byte[] buffer = ... // load entire file from input stream

// read the header
ByteBuffer bfHeader = ByteBuffer.wrap(buffer);
bfHeader.order(ByteOrder.LITTLE_ENDIAN);

int height = bfHeader.getInt(16);
int width = bfHeader.getInt(12);

// offset to image data
int headerSize = 124; // (replace with correct header size)
ByteBuffer bfData = ByteBuffer.wrap(buffer, headerSize, buffer.length-headerSize);
bfData.order(ByteOrder.LITTLE_ENDIAN);

// load image data
int size = ((height + 3) / 4) * ((width + 3) / 4) * 16;
glBindTexture(GL_TEXTURE_2D, textureObjectIds[0]);
GLES20.glCompressedTexImage2D(GL_TEXTURE_2D, 0,ATC_RGBA_EXPLICIT_ALPHA_AMD, width, height, 0, size, bfData);