cocos2d-x --内存优化之使用16位纹理/NPOT
前端之家收集整理的这篇文章主要介绍了
cocos2d-x --内存优化之使用16位纹理/NPOT,
前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
图片文件大小和纹理内存占用是两码事。假设他们是帐篷。图片文件就相当于帐篷被装在行李箱。但是,如果你想要使用帐篷的话,它必须被撑起来,被“膨胀”。
图片文件和纹理的关系与此类似。图片文件大多是压缩过的,它们被使用的话必须先解压缩,然后才能会GPU所处理,变成我们熟知的纹理。一个2048*2048的png图片,采用32位颜色深度编码,那么它在磁盘上占用空间只有2MB。但是,如果变成纹理,它将消耗16MB的内存!
当然,减少纹理占用内存大小是有办法滴。
使用16-bit纹理
最快速地减少纹理内存占用的办法就是把它们作为16位颜色深度的纹理来加载。cocos2d默认的纹理像素格式是32位颜色深度。如果把颜色深度减半,那么内存消耗也就可以减少一半。并且这还会带来渲染效率的提升,大约提高10%。
@H_
404_44@
你可以使用CCTexture2D对象的类方法setDefaultAlphaPixelFormat来更改默认的纹理像素格式,代码如下:
- [CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGB5A1];
- [[CCTextureCache sharedTextureCache] addImage:@"ui.png"];
@H_
404_44@
这里有个问题:首先,纹理像素格式的改变会影响后面加载的所有纹理。因此,如果你想后面加载纹理使用不同的像素格式的话,必须再调用此方法,并且重新设置一遍像素格式。
@H_
404_44@
其次,如果你的CCTexture2D设置的像素格式与图片本身的像素格式不匹配的话,就会导致显示严重失真。比如颜色不对,或者透明度不对等等。
@H_
404_44@
@H_
404_44@
CCSize s = CCDirector::sharedDirector()->getWinSize(); CCLayerColor *background = CCLayerColor::create(ccc4(128,128,255),s.width,s.height); addChild(background,-1); // RGBA 8888 image (32-bit) CCTexture2D::setDefaultAlphaPixelFormat(kCCTexture2DPixelFormat_RGBA8888); CCSprite *sprite1 = CCSprite::create("Images/test-rgba1.png"); sprite1->setPosition(ccp(1*s.width/7,s.height/2+32)); addChild(sprite1,0); // remove texture from texture manager CCTextureCache::sharedTextureCache()->removeTexture(sprite1->getTexture()); // RGBA 4444 image (16-bit) CCTexture2D::setDefaultAlphaPixelFormat(kCCTexture2DPixelFormat_RGBA4444); CCSprite *sprite2 = CCSprite::create("Images/test-rgba1.png"); sprite2->setPosition(ccp(2*s.width/7,s.height/2-32)); addChild(sprite2,sans-serif; word-wrap:break-word"> CCTextureCache::sharedTextureCache()->removeTexture(sprite2->getTexture()); // RGB5A1 image (16-bit) CCTexture2D::setDefaultAlphaPixelFormat(kCCTexture2DPixelFormat_RGB5A1); CCSprite *sprite3 = CCSprite::create("Images/test-rgba1.png"); sprite3->setPosition(ccp(3*s.width/7,sans-serif; word-wrap:break-word"> addChild(sprite3,sans-serif; word-wrap:break-word"> CCTextureCache::sharedTextureCache()->removeTexture(sprite3->getTexture()); // RGB888 image CCTexture2D::setDefaultAlphaPixelFormat(kCCTexture2DPixelFormat_RGB888); CCSprite *sprite4 = CCSprite::create("Images/test-rgba1.png"); sprite4->setPosition(ccp(4*s.width/7,sans-serif; word-wrap:break-word"> addChild(sprite4,sans-serif; word-wrap:break-word"> CCTextureCache::sharedTextureCache()->removeTexture(sprite4->getTexture()); // RGB565 image (16-bit) CCTexture2D::setDefaultAlphaPixelFormat(kCCTexture2DPixelFormat_RGB565); CCSprite *sprite5 = CCSprite::create("Images/test-rgba1.png"); sprite5->setPosition(ccp(5*s.width/7,sans-serif; word-wrap:break-word"> addChild(sprite5,sans-serif; word-wrap:break-word"> CCTextureCache::sharedTextureCache()->removeTexture(sprite5->getTexture()); // A8 image (8-bit) CCTexture2D::setDefaultAlphaPixelFormat(kCCTexture2DPixelFormat_A8); CCSprite *sprite6 = CCSprite::create("Images/test-rgba1.png"); sprite6->setPosition(ccp(6*s.width/7,sans-serif; word-wrap:break-word"> addChild(sprite6,sans-serif; word-wrap:break-word"> CCTextureCache::sharedTextureCache()->removeTexture(sprite6->getTexture());
有哪些比较有用的纹理像素格式呢?
- generate 32-bit textures: kCCTexture2DPixelFormat_RGBA8888 (default)
- generate 16-bit textures: kCCTexture2DPixelFormat_RGBA4444
- generate 16-bit textures: kCCTexture2DPixelFormat_RGB5A1
- generate 16-bit textures: kCCTexture2DPixelFormat_RGB565 (no alpha)
RGBA8888是默认的格式。对于16位的纹理来说,使用RGB565可以获得最佳颜色质量,因为16位全部用来显示颜色:总共有65536总颜色值。但是,这里有个缺点,除非图片是矩形的,并且没有透明像素。所以RBG565格式比较适合背景图片和一些矩形的用户控件。
RBG5A1格式使用一位颜色来表示alpha通道,因此图片可以拥有透明区域。只是,1位似乎有点不够用,它只能表示32768种可用颜色值。而且图片要么只能全部是透明像素,或者全部是不透明的像素。因为一位的alpha通道的缘故,所以没有中间值。但是你可以使用fade in/out动作来改变纹理的opacity属性。
如果你的图片包含有半透明的区域,那么RBGA4444格式很有用。它允许每一个像素值有127个alpha值,因此透明效率与RGBA8888格式的纹理差别不是很大。但是,由于颜色总量减少至4096,所以,RBGA4444是16位图片格式里面颜色质量最差的。
现在,你可以得到16位纹理的不足之处了:它由于颜色总量的减少,有一些图片显示起来可能会失真,而且可能会产生“梯度”。
使16位纹理看起来更棒
@H_
404_44@
TP有一个特性叫做“抖动”,它可以使得原本由于颜色数量减少而产生的失真问题得到改善。(TP里面有很多抖动算法,关于这些算法,读者可以参考我翻译的另一篇文章)。
@H_
404_44@
特别是在拥有Retina显示的像素密度下,你几乎看不出16位与32位的纹理之间的显示差别。当然,前提是你需要采用“抖动”算法。