0

我有一种将纹理加载到 OpenGL 中的方法:

bool AndroidGraphicsManager::setTexture(
    UINT& id, UCHAR* image, UINT width, UINT height,
    bool wrapURepeat, bool wrapVRepeat, bool useMipmaps)
{
    glGenTextures(1, &id);
    glBindTexture(GL_TEXTURE_2D, id);
    glTexImage2D(
        GL_TEXTURE_2D, 0, GL_RGBA,
        width, height, 0, GL_RGBA,
        GL_UNSIGNED_BYTE, (GLvoid*) image);
    int minFilter = GL_LINEAR;

    if (useMipmaps) {
        glGenerateMipmap(GL_TEXTURE_2D);
        minFilter = GL_NEAREST_MIPMAP_NEAREST;
    }
    glTexParameteri(GL_TEXTURE_2D,
        GL_TEXTURE_MIN_FILTER, minFilter);
    glTexParameteri(
        GL_TEXTURE_2D,
        GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    int wrap_u = wrapURepeat ?
        GL_REPEAT : GL_CLAMP_TO_EDGE;
    int wrap_v = wrapVRepeat ?
        GL_REPEAT : GL_CLAMP_TO_EDGE;
    glTexParameteri(
        GL_TEXTURE_2D,
        GL_TEXTURE_WRAP_S, wrap_u);
    glTexParameteri(
        GL_TEXTURE_2D,
        GL_TEXTURE_WRAP_T, wrap_v);
    glBindTexture(GL_TEXTURE_2D, 0);
    return !checkGLError("Loading texture.");
}

这工作正常。我使用 libpng 加载纹理。这给了我一系列无符号字符。然后我将此数组传递给我上面指定的方法。图片是 32 位的,所以我假设在 UCHAR 数组中每个 UCHAR 包含单一颜色分量,四个 UCHAR 组成一个像素。我想尝试使用 16 位纹理。我将 GL_UNSIGNED_BYTE 更改为 GL_UNSIGNED_SHORT_4_4_4_4。但显然这还不够,因为它给了我这样的结果: 在此处输入图像描述 我还需要更改什么才能正确显示 16 位纹理?

[编辑]正如@DatenWolf 建议的那样,我尝试使用此代码:

glTexImage2D(
    GL_TEXTURE_2D, 0, GL_RGBA4,
    width, height, 0, GL_RGBA,
    GL_UNSIGNED_SHORT_4_4_4_4, (GLvoid*) image);

我在我的引擎的 Linux 版本上使用它,但结果与之前的 android 屏幕截图完全相同。那么可以安全地假设问题出在 libpng 及其生成我的 UCHAR 数组的方式上吗?

[EDIT2]所以我终于设法将 32 位纹理压缩到 16 位。我所需要的只是对 32 位纹理数据的简单迭代和一些位移操作,将 32 位压缩为 16 位。

void* rgba8888ToRgba4444(void* in, int size) {
    int pixelCount = size / 4;
    ULONG* input = static_cast<ULONG*>(in);
    USHORT* output = new USHORT[pixelCount];
    for (int i = 0; i < pixelCount; i++) {
        ULONG pixel = input[i];
        // Unpack the source data as 8 bit values
        UINT r = pixel & 0xff;
        UINT g = (pixel >> 8) & 0xff;
        UINT b = (pixel >> 16) & 0xff;
        UINT a = (pixel >> 24) & 0xff;
        // Convert to 4 bit vales
        r >>= 4; g >>= 4; b >>= 4; a >>= 4;
        output[i] = r << 12 | g << 8 | b << 4 | a;
    }
    return static_cast<void*>(output);
}

我认为对于移动设备,这会带来性能提升,但不幸的是我没有看到 Galaxy SIII 的性能提升。 在此处输入图像描述

4

2 回答 2

1

但显然这还不够

您更改的标记告诉 OpenGL 传递给它的数组中数据的格式。所以你也必须调整它。然而 OpenGL 可以将它转换成它想要的任何内部格式,因为你没有强制它转换成特定的格式。这就是内部格式参数的用途(它独立于外部数据类型工作)。因此,如果您想在内部获得 16 位分辨率,则必须将内部格式参数更改为GL_RGBA4. 数据可能保留为每像素 8 位的格式。所以在你的情况下

glTexImage2D(
    GL_TEXTURE_2D, 0, GL_RGBA4,
    width, height, 0, GL_RGBA,
    …, (GLvoid*) image);

类型参数必须与数据的布局相匹配。如果您最初每个像素有 8 位,那么 GL_UNSIGNED_BYTE。但是,如果它是在 ushorts nibbles 中预打包的 RGBA,那么 GL_UNSIGNED_SHORT_4_4_4_4

于 2013-05-15T05:56:33.400 回答
1

最好的事情可能是使用像魔鬼这样的图像库来处理这种事情。

但是,如果您想转换从 libpbg 获得的图像数据,您可以执行类似于以下代码的操作。

请记住,在执行此操作时,您以大小换取速度。

struct Color {
unsigned char r:4;
unsigned char g:4;
unsigned char b:4;
unsigned char a:4;
};

float factor = 16 / 255;

Color colors[imgWidth*imgHeight];

for(int i = 0; i < imgWidth*imgHeight; ++i)
{
    colors[i].r = image[i*4]*factor;
    colors[i].g = image[i*4+1]*factor;
    colors[i].b = image[i*4+2]*factor;
    colors[i].a = image[i*4+3]*factor;
}
于 2013-05-15T08:26:27.263 回答