所以我正在使用一堆2048x2048精灵表,这些精简表很快就会占用内存。我正在使用以下方法(通过Ray Wenderlich)来加载纹理:
- (GLuint)setupTexture:(NSString *)fileName
{
CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;
if (!spriteImage)
{
NSLog(@"Failed to load image %@", fileName);
exit(1);
}
size_t width = CGImageGetWidth(spriteImage);
size_t height = CGImageGetHeight(spriteImage);
GLubyte * spriteData = (GLubyte *) calloc(width*height*4, sizeof(GLubyte));
CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4,CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);
CGContextRelease(spriteContext);
GLuint texName;
glGenTextures(1, &texName);
glBindTexture(GL_TEXTURE_2D, texName);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
GLenum err = glGetError();
if (err != GL_NO_ERROR)
NSLog(@"Error uploading texture. glError: 0x%04X", err);
free(spriteData);
return texName;
}
所以我的问题是,如何从CGImage中丢弃alpha信息,然后将图像“缩减”到每像素更少的位,最后告诉OpenGL它呢?
答案 0 :(得分:7)
我使用此代码将CGContextDrawImage
写入的数据转换为RGB565。它使用优化的NEON代码在支持NEON的设备上一次处理8个像素(每个运行armv7代码的iOS设备都有这样的芯片)。你看到的data
指针与你的spriteData
指针相同,我只是懒得重命名。
void *temp = malloc(width * height * 2);
uint32_t *inPixel32 = (uint32_t *)data;
uint16_t *outPixel16 = (uint16_t *)temp;
uint32_t pixelCount = width * height;
#ifdef __ARM_NEON__
for(uint32_t i=0; i<pixelCount; i+=8, inPixel32+=8, outPixel16+=8)
{
uint8x8x4_t rgba = vld4_u8((const uint8_t *)inPixel32);
uint8x8_t r = vshr_n_u8(rgba.val[0], 3);
uint8x8_t g = vshr_n_u8(rgba.val[1], 2);
uint8x8_t b = vshr_n_u8(rgba.val[2], 3);
uint16x8_t r16 = vmovl_u8(r);
uint16x8_t g16 = vmovl_u8(g);
uint16x8_t b16 = vmovl_u8(b);
r16 = vshlq_n_u16(r16, 11);
g16 = vshlq_n_u16(g16, 5);
uint16x8_t rg16 = vorrq_u16(r16, g16);
uint16x8_t result = vorrq_u16(rg16, b16);
vst1q_u16(outPixel16, result);
}
#else
for(uint32_t i=0; i<pixelCount; i++, inPixel32++)
{
uint32_t r = (((*inPixel32 >> 0) & 0xFF) >> 3);
uint32_t g = (((*inPixel32 >> 8) & 0xFF) >> 2);
uint32_t b = (((*inPixel32 >> 16) & 0xFF) >> 3);
*outPixel16++ = (r << 11) | (g << 5) | (b << 0);
}
#endif
free(data);
data = temp;
答案 1 :(得分:3)
我可能建议在这里使用PVRTC压缩纹理,而不是简单地更改颜色空间。这应该比GPU565版本在GPU上使用更少的内存,因为这些纹理保持压缩而不是扩展到未压缩的位图。
在适用于iOS的OpenGL ES编程指南的“Best Practices for Working with Texture Data”部分中,Apple说
纹理压缩通常提供最佳的内存平衡 节约和质量。适用于iOS的OpenGL ES支持PowerVR纹理 通过实现压缩(PVRTC)格式 GL_IMG_texture_compression_pvrtc扩展名。有两个层次 PVRTC压缩,每通道4位,每通道2位,其中 在未压缩的32位上提供8:1和16:1的压缩比 纹理格式分别。压缩的PVRTC纹理仍然提供 一个不错的质量水平,特别是在4位水平。
和
如果您的应用程序无法使用压缩纹理,请考虑使用 低精度像素格式。
表示压缩纹理的内存大小比使用较小颜色空间的内存大小要小。
Apple在他们的PVRTextureLoader示例应用程序中有一个很好的例子,我重复使用了一些代码来加载textured cube sample application中的PVRTC纹理。您可以在PVRTextureLoader中查看“编码图像”构建阶段,了解如何在编译时编写PNG纹理到PVRTC纹理的转换脚本。
答案 2 :(得分:0)
查看internalFormat参数。也许您可以将GL_R3_G3_B2指定为每像素仅使用8位,或者GL_RGB5可能有用。有几个选项可能有用。
有关详细信息,请参阅Texture Internal Formats。