优化 OpenGL ES / Cocos2d 纹理的秘诀
我得到了大约 30 个 PNG 32 位格式的纹理。所有纹理的大小相同(比 iPad 屏幕宽)。尺寸不是正方形,宽度和高度都不是 2 的幂。相同的纹理适用于 iPhone 版本的游戏。
在游戏中,假定这些纹理用于动画(每个纹理都是动画的一帧)。当然,30 个纹理(每个纹理使用 4MB)的动画速度并不是很快,而且内存消耗也远未达到可接受的水平。
因此,作为 OpenGL ES 和 Cocos2d 的新手,我正在寻找如何优化这些特定纹理和一般纹理的秘诀。
关于我应该处理的纹理的附加信息:所有纹理都具有相同的渐变背景(海面)和不同的区域(波浪)。每个波浪都有些独特,波浪几乎占据了所有纹理。纹理从 Flash 导出(它们最初是矢量图像)。
I am given about 30 textures in PNG 32bit format. All textures are of equal size (wider than iPad screen). Size is not square and neither width not height is a power of 2. The same textures are meant to be used for iPhone version of the game.
In the game these textures are assumed to be used for an animation (each texture is a frame of the animation). Of course, 30 textures using 4MB each are not very fast to animate and memory consumption is nowhere near an acceptable level.
So, being novice in the OpenGL ES and Cocos2d, I am seeking for recipes how I can optimize these particular textures and textures in general.
Additional info about textures I should deal with: all textures have the same gradient background (surface of a sea) and areas that different (waves). Each wave is somewhat unique and waves occupy almost all the texture. Textures are exported from Flash (they are vector images initially).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
第一个建议:改变设计。如果不是你的,必要时使用钝器。这很难很好地发挥作用。
您必须在制作动画时频繁加载和卸载纹理,以控制内存消耗。这将限制动画可实现的帧速率。我怀疑在 iPad 和第四代设备上最多只能达到 30-40 fps,在第一代到第三代设备上可能慢得令人发指。
您可以做的最佳优化是不使用 Flash 导出的全屏纹理。基本上,Flash 所做的就是为您制作所有内容的动画,然后为每个动画帧输出全屏图像。 对于移动设备上的任何动画来说,这是最糟糕的解决方案。
相反,使用单个图像和 cocos2d 动作在 cocos2d 中重新创建所有动画,以组成相同的动画或足够接近的动画。这是更多的编码工作,但它的性能会好得多。可能有像 LevelHelper 这样的工具可以帮助您,但我不确定它们是否可以向您显示动画的实时预览。还有一个可以导入Flash时间线动画的工具,但我不能说它的效果如何,或者它是否有效。
使用 Texture Packer 从单个图像创建纹理图集,以节省内存并进一步加快渲染速度,特别是与 CCSpriteBatchNode 结合使用。另外,Texture Packer 允许您尝试各种纹理格式,如果您想支持非 Retina 设备,它将导出 SD 分辨率图像。
因为另一个好的优化是尽可能减少颜色位深度。如果从 32 位变为 16 位(RGBA4444 或 RGBA5551 或 RGB565,具体取决于您需要哪种透明度),您已经将内存消耗减少了一半,并且渲染速度也有所提高。
如果可能,请使用其中一种 PVR 压缩格式,特别是对于始终移动的精灵,因为移动精灵几乎不可能注意到图像质量下降。
但是,由于您提到了渐变,因此减少的颜色位深度对渐变的影响最大。如果是简单的渐变,您可以将渐变背景替换为 CCLayerGradient 保存背景图像的内存。
最后,您也许可以使用较小的图像并将其放大。特别是对于透明图像,放大图像会使其看起来模糊,这一事实实际上是有益的。
总结:
First advice: change the design. If it's not yours, use blunt force if necessary. This is hardly going to work reasonably well.
You will have to frequently load and unload textures while animating to keep the memory consumption in check. This will limit the achievable framerate of the animation. I suspect it will be at best 30-40 fps on iPad and 4th generation devices, probably abhorrently slow on 1st to 3rd generation devices.
The best optimization you can do is to not use the Flash exported fullscreen textures. Basically what Flash does is animate everything for you, and then output a fullscreen image for each animation frame. This is the worst possible solution for animating anything for mobile devices.
Instead, recreate all of the animations within cocos2d using individual images and cocos2d actions to compose the same animation or one that's close enough. It's more coding work, but it'll perform a lot better. There may be tools like LevelHelper which can assist you but I'm not sure if they can show you a realtime preview of the animations. There's also a tool that can import Flash timeline animations but I can't say how well it works, or whether it's working at all.
Use Texture Packer to create texture atlases from individual images to conserve memory and speed up rendering even more, in particular in conjunction with CCSpriteBatchNode. Plus Texture Packer allows you to experiment with the various texture formats, and it will export SD resolution images should you want to support non-Retina devices.
Because another good optimization is to reduce the color bit depth as much as possible. If you go from 32-bit to 16-bit (RGBA4444 or RGBA5551 or RGB565 depending on what kind of transparency you need) you already cut down your memory consumption in half, and rendering speed increases a bit as well.
If possible use one of the PVR compressed formats, in particular for sprites which are always moving because the degraded image quality will be almost impossible to notice with moving sprites.
However, since you mention gradients those will be affected the most by a reduced color bit depth. If it's a simple gradient you can replace the gradient background with CCLayerGradient to save the memory of the background image.
Finally you may be able to use smaller images and scale them up. Especially for transparent images the fact that scaling the image up will make it look blurred can actually be beneficial.
To summarize:
1) 使用 PVR 纹理而不是 PNG。 PVR 提供一系列格式和质量,所有这些格式的加载速度都比 PNG 快,而且压缩变体占用的内存也更少。
2) 如果可能的话,将动画帧合并到单个精灵表中,这样效率更高。 Cocos 内置了对精灵表的支持(它称之为纹理图集)。但这不适用于全屏框架,因为图集的最大尺寸约为 1024x1024。
3) 为了让您的生活更轻松,请使用精灵表生成工具,它可以自动创建精灵表并将纹理转换为 PVR。 TexturePacker 和 Zwoptex< /a> 都是不错的选择。
如果可以的话,LearnCocos2D 关于将动画重构为单独片段的建议是个好主意。
如果您由于时间或技术原因无法做到这一点,我编写了一个基于 OpenGL PVR 帧的视频播放器,它可以通过一次一帧将它们流式传输到内存中来非常有效地播放一系列全屏图像。它不使用 Cocos2D,只是一个独立的 UIView,因此当您的应用程序在加载 Cocos 控制器视图之前加载时,您可以在它自己的视图控制器中显示它。
您可以在这里获取:https://github.com/nicklockwood/GLView
- 它包括文档和示例。要记住的主要事情是,在转换为 PVR 之前,您需要将图像帧的大小调整为二次方的大小。但不用担心,当你玩它们时,你总是可以将它们拉伸回原来的比例,这样就不会被注意到。
1) Use PVR textures instead of PNGs. PVRs offer a range of formats and qualities, all of which load faster than PNGs, and the compressed variants use up less memory as well.
2) Combine your animation frames into a single sprite sheet if possible, which is way more efficient. Cocos has built-in support for sprite sheets (it calls them Texture Atlases). This won't work for full-screen frames though because atlases have a maximum size of around 1024x1024.
3) To make your life easier, use a sprite sheet generation tool that can automatically create your sprite sheets and convert your textures to PVR. TexturePacker and Zwoptex are both good options.
LearnCocos2D's advice about refactoring your animation into separate pieces is a good idea if you can.
If you can't do this due to time or technical reasons, I've written an OpenGL PVR frame-based video player that can play a sequence of full-screen images like this very efficiently by streaming them into memory one frame at a time. It doesn't use Cocos2D and is just a standalone UIView, so you could display it in it's own view controller when your app loads prior to loading your Cocos director view.
You can get it here: https://github.com/nicklockwood/GLView
- it includes documentation and examples. The main thing to bear in mind is that you'll need to resize your image frames to be power-of-two squares before converting to PVR. But don't worry, you can always stretch them back to their original proportions when you play them so it won't be noticable.