C++ OpenGL中的压缩纹理批处理

C++ OpenGL中的压缩纹理批处理,c++,opengl,opengl-es,C++,Opengl,Opengl Es,我正试图创建一个压缩纹理的图集,但我似乎无法让它工作。以下是一段代码片段: void Texture::addImageToAtlas(ImageProperties* imageProperties) { generateTexture(); // delete and regenerate an empty texture bindTexture(); // bind it atlasProperties.push_back(imageProper

我正试图创建一个压缩纹理的图集,但我似乎无法让它工作。以下是一段代码片段:

void Texture::addImageToAtlas(ImageProperties* imageProperties)
{   
    generateTexture();  // delete and regenerate an empty texture
    bindTexture();      // bind it

    atlasProperties.push_back(imageProperties);

    width = height = 0;
    for (int i=0; i < atlasProperties.size(); i++)
    {
        width += atlasProperties[i]->width;
        height = atlasProperties[i]->height;
    }

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    // glCompressedTexImage2D MUST be called with valid data for the 'pixels'
    // parameter. Won't work if you use zero/null.
    glCompressedTexImage2D(GL_TEXTURE_2D, 0, 
        GL_COMPRESSED_RGBA8_ETC2_EAC,
        width,
        height,
        0,
        (GLsizei)(ceilf(width/4.f) * ceilf(height/4.f) * 16.f),
        atlasProperties[0]->pixels);

    // Recreate the whole atlas by adding all the textures we have appended 
    // to our vector so far
    int x, y = 0;
    for (int i=0; i < atlasProperties.size(); i++)
    {
        glCompressedTexSubImage2D(GL_TEXTURE_2D,
            0,
            x,
            y,
            atlasProperties[i]->width,
            atlasProperties[i]->height,
            GL_RGBA,
            (GLsizei)(ceilf(atlasProperties[i]->width/4.f) * ceilf(atlasProperties[i]->height/4.f) * 16.f),
        atlasProperties[i]->pixels);

        x += atlasProperties[i]->width;
    }

    unbindTexture();  // unbind the texture
}
这就是我需要做的吗?为什么?我试过了,但似乎不起作用

此外,我正在使用Vivante GPU的ARM I.mx6四块机上尝试上述代码,从我在线阅读的内容中,我怀疑GLCompressedExSubImage2D可能不适用于此电路板


谁能帮帮我吗

传递给
glCompressedTexSubImage2D()
的格式必须与对应的
glCompressedTexImage2D()
使用的格式相同。从ES 2.0规范:

此命令不提供图像格式转换,因此,如果格式与正在修改的纹理图像的内部格式不匹配,将导致无效的_操作错误

因此,要匹配
glCompressedTexImage2D()
调用,
glCompressedTexSubImage2D()
调用需要:

glCompressedTexSubImage2D(GL_TEXTURE_2D,
    0, x, y, atlasProperties[i]->width, atlasProperties[i]->height,
    GL_COMPRESSED_RGBA8_ETC2_EAC,
    (GLsizei)(ceilf(atlasProperties[i]->width/4.f) *
              ceilf(atlasProperties[i]->height/4.f) * 16.f),
    atlasProperties[i]->pixels);
至于尺寸和偏移量:

  • 只有当所有子图像的高度相同时,确定总体大小的逻辑才会起作用。或者更准确地说,因为高度设置为最后一个子图像的高度,如果没有其他高度大于最后一个子图像的高度。为了使其更加健壮,您可能希望使用所有子图像的最大高度
  • 我很惊讶,您不能将null作为
    glCompressedTexImage2D()
    的最后一个参数传递,但这似乎是真的。至少我在规范中找不到任何允许它的东西。但是在这种情况下,我认为简单地将指针传递到第一个子图像的数据是不合适的。这将是不够的数据,它将读取超过内存的末尾。您可能需要分配和传递足够大的“数据”,以覆盖整个atlas纹理。您可能会将其设置为任何值(例如,归零),因为您无论如何都要替换它
  • 按照我阅读ETC2定义(包括在ES 3.0规范中)的方式,纹理的宽度/高度严格来说不必是4的倍数。但是,
    glCompressedTexSubImage2D()
    的位置必须是4的倍数,以及宽度/高度,除非它们延伸到纹理的边缘。这意味着您必须使每个子图像(最后一个子图像除外)的宽度为4的倍数。在这一点上,您最好使用4的倍数表示所有内容
基于此,我认为尺寸的确定应如下所示:

width = height = 0;
for (int i = 0; i < atlasProperties.size(); i++)
{
    width += (atlasProperties[i]->width + 3) & ~3;
    if (atlasProperties[i]->height > height)
    {
        height = atlasProperties[i]->height;
    }
}
height = (height + 3) & ~3;

uint8_t* dummyData = new uint8_t[width * height];
memset(dummyData, 0, width * height);
glCompressedTexImage2D(GL_TEXTURE_2D, 0, 
    GL_COMPRESSED_RGBA8_ETC2_EAC,
    width, height, 0,
    width * height,
    dummyData);
delete[] dummyData;
width=height=0;
对于(int i=0;i宽度+3)和~3;
if(AtlasProperty[i]->高度>高度)
{
高度=地图集属性[i]->高度;
}
}
高度=(高度+3)和~3;
uint8_t*dummyData=新uint8_t[宽度*高度];
memset(dummyData,0,宽*高);
GLCompressedEximage2D(GL_纹理_2D,0,
GL_压缩_RGBA8_ETC2_EAC,
宽度,高度,0,
宽*高,
Dummy数据);
删除数据;
然后设置子图像:

int xPos = 0;
for (int i = 0; i < atlasProperties.size(); i++)
{
    int w = (atlasProperties[i]->width + 3) & ~3;
    int h = (atlasProperties[i]->height + 3) & ~3;
    glCompressedTexSubImage2D(GL_TEXTURE_2D,
        0, xPos, 0, w, h,
        GL_COMPRESSED_RGBA8_ETC2_EAC,
        w * h,
        atlasProperties[i]->pixels);
    xPos += w;
}
intxpos=0;
对于(int i=0;i宽度+3)和~3;
int h=(地图集属性[i]->高度+3)和~3;
GLCompressedExSubImage2D(GL_纹理_2D,
0,xPos,0,w,h,
GL_压缩_RGBA8_ETC2_EAC,
w*h,
AtlasProperty[i]->像素);
xPos+=w;
}

如果可以确保原始纹理图像的大小已经是4的倍数,那么整个过程将变得稍微简单一些。然后你可以跳过将大小/位置四舍五入到4的倍数。

毕竟,这是让你想把头撞到墙上的错误之一<代码>GL_COMPRESSED_RGBA8_ETC2_EAC实际上在板上不受支持


我从标题中复制了它,但它没有查询设备支持的格式。我可以使用
DXT5
格式来处理此代码。

不应该是
height=max(height,atlasProperties[I]->height)
int xPos = 0;
for (int i = 0; i < atlasProperties.size(); i++)
{
    int w = (atlasProperties[i]->width + 3) & ~3;
    int h = (atlasProperties[i]->height + 3) & ~3;
    glCompressedTexSubImage2D(GL_TEXTURE_2D,
        0, xPos, 0, w, h,
        GL_COMPRESSED_RGBA8_ETC2_EAC,
        w * h,
        atlasProperties[i]->pixels);
    xPos += w;
}