我试图创建压缩纹理的图集,但我似乎无法让它工作。这是一段代码:
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
}
我只使用两个尺寸相同的小KTX纹理进行测试,您可以从代码中看到我尝试在x轴上将第二个附加到第一个旁边。
我的KTX解析工作正常,因为我可以渲染单个纹理,但是一旦我尝试批处理(就在我使用glCompressedTexSubImage2d时),屏幕上什么都没有。
如果我用PNG替换压缩纹理并将glCompressedTexImage2d和glCompressedTexSubImage2d与非压缩版本交换,那么所有这些都可以正常工作......
我找不到任何信息的一件事是地图集中纹理的x和y位置。我该如何抵消它们?因此,如果第一个纹理的宽度为60像素,我是否只将第二个纹理定位在61?
我在网上看到了一些人们计算x和y位置的代码,如下所示:
x &= ~3;
y &= ~3;
这是我需要做的,为什么?我已经尝试过但它似乎没有用。
另外,我在带有Vivante GPU的ARM i.mx6 Quad上尝试上述代码,我从网上看到的内容中得到怀疑glCompressedTexSubImage2d可能无法在此主板上运行。
任何人都可以帮帮我吗?
答案 0 :(得分:1)
您传递给glCompressedTexSubImage2D()
的格式必须与用于相应glCompressedTexImage2D()
的格式相同。从ES 2.0规范:
此命令不提供图像格式转换,因此如果格式与正在修改的纹理图像的内部格式不匹配,则会产生INVALID_OPERATION错误。
因此,要匹配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);
关于尺寸和偏移:
glCompressedTexImage2D()
的最后一个参数传递,但它似乎是真的。至少我在规范中找不到任何允许它的东西。但在这种情况下,我不认为将指针传递给第一个子图像的数据是可以的。那将是不够的数据,它将读取超出内存的末尾。您可能必须分配并传递&#34;数据&#34;这足以覆盖整个地图集纹理。您可以将其设置为任何内容(例如将其归零),因为您无论如何都要替换它。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;
然后设置子图像:
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;
}
如果您可以确保原始纹理图像的大小是4的倍数,那么整个过程会变得稍微简单一些。然后您可以跳过将大小/位置四舍五入为4的倍数。
答案 1 :(得分:0)
毕竟,这是让你想要在墙上撞到头的错误之一。董事会实际上并不支持GL_COMPRESSED_RGBA8_ETC2_EAC
。
我从标题中复制了它,但它没有在设备中查询支持的格式。我可以使用DXT5
格式使用此代码。