Cocos2dx

Cocos2dx——纹理使用

理论要点

要点一:

文件格式与像素格式的区别:文件格式是图像为了存储信息而使用的对信息的特殊编码方式,大都经过了压缩,它存储在磁盘或内存中,但是并不能被GPU所识别(jpg,png…),这些图片格式当被游戏读入后,还需要经过CPU解压成像素格式,如:RGBA8888,再传送到GPU端进行使用。
而像素格式是能被GPU所识别的,能被快速寻址并采样。

要点二:

图片本身大小和其所占内存大小是两码事。这就好比一个zip压缩包使用时要解压还原数据,这个zip文件就好比图片本身,而解压后的文件就好比图片所占内存大小。纹理本身大小主要看我们选用什么样的压缩格式和压缩比,而所占内存大小就只由两个因素决定:
1. 图片的像素点个数(分辨率)
2. 单位像素占用的字节数(像素格式)。

即纹理内存大小 = 纹理长度 * 纹理宽度 * 单位像素占用的字节数,如:一张1136x640的RGBA8888的png图片占用的内存为 1136x640x4 = 2.8M左右。

cocos2dx之如何优化内存使用(高级篇)

一、内存优化原则

为了优化应用内存,你应该知道是什么消耗了你应用的大部分内存,答案就是Texture(纹理)!它几乎占据了90%的应用内存。那么我们应该尽力去减小我们应用的纹理内存使用,否则我们的应用进程可能会被系统杀死。

为了减少内存警告,这里我们给出两个普遍的关于cocos2dx游戏内存优化的指导原则。

1)了解瓶颈,然后解决掉

什么样的纹理消耗了大部分应用的内存呢?或者说这些纹理消耗了多少内存呢?你不用去手工计算或者猜测。

这里我们正好有一个工具。它就是 Allocations & Leaks,在xcode中你长按Run按钮并且选择Profile去启动这两个工具。这里我们有个截图:

cocos2dx之如何优化内存使用

你可以使用Allocation工具去计算你应用的内存使用情况并且可以查看内存泄露情况。

我所理解的cocos2dx - 帧缓冲

GroupCommand

分组绘制在cocos2dx上主要有2个用途,一个是RenderTexture,它是一个node的子类,用于把场景绘制到纹理而不是屏幕上,也可以把缓冲区上的颜色,深度和模版值保存到Renderbuffer上,供多个帧缓冲之间共享。

另一个用途就是实现裁剪,例如ClippingNode,它能在绘制命令上加特殊绘制状态,如模版测试。

GroupCommand流程

Begin:开始组绘制,会先在绘制栈上新开一个绘制组,把id放入绘制组的id,Render会从id栈取顶的id来获取绘制组,这样绘制命令就会加入到新的绘制组里,这在GroupCommand的init里实现。因为ui树和绘制分开了,所以begin的时机不是ui遍历到该元素的时机,而是Renderer在开始绘制GroupCommand的时机。

visit:加入绘制命令到该组

end:该组所有需要绘制的命令都遍历后,从Render上移除id和该组对应的RenderQueue,还要还原一些状态。

GroupCommand限制

Cocos2dx v3.x渲染管线流程

cocos2dx v3渲染流程做了很大的升级,具体的提升和新的特性大概有以下几点:

  •   场景的遍历和渲染分离开来,在遍历节点的时候会把绘图命令放入一个队列,并不会实际调用OpenGL渲染API;
  •   视锥体几何裁剪,摄像机视野外的对象将会自动从当前帧中移除,并不会进行渲染;
  •   执行OpenGL绘图命令的将会移动到一个独立的线程,更好地利用现在移动平台的多核CPU;
  •   自动合并批次
  •   基于节点的定制化渲染

Cocos2dx v3.x渲染管线流程

我所理解的cocos2dx - 精灵

用sprite绘制一个矩形区域

精灵可以绘制一张纹理或者上面的一个矩形区域,最终会关联一个texture2d对象和上面的一个区域。createWithTexture不使用TextureCache创建纹理,所以需要额外的小心它的生命周期。

精灵可以通过setTexture来修改关联的纹理,用SpriteFrame来高效播放精灵动画。

V3F_C4B_T2F_Quad结构体

所有对sprite绘制属性的修改最终都是表现为对一个V3F_C4B_T2F_Quad结构体变量quad的修改。此结构拥有4个v3f_c4b_t2f顶点属性(坐标vec3,颜色color4B和纹理坐标tex2F)。opengl es不支持多边形图元,所以一个quad图元实际会分为2个三角形。对于图元修改,我们只需要修改每一个顶点的相关数据即可。

使用QuadCommand进行绘制

Cocos2dx 小技巧——三种缓存类介绍

在介绍三个缓存时,我们要先理清一个问题:什么是纹理?通俗的解释呢,纹理就是图片的意思啦。当一张图片被加载到内存后,它是以纹理的形式存在的。从这里可以看出,纹理其实就是一块内存!这块内存中存放的是按照指定的像素格式填充的图片像素信息。

下面进入正题:

1、TextureCache

TextureCache纹理缓存是最底层也是最有效的纹理缓存。它到底有什么用呢?我先描述一个现象吧:假设游戏中有个界面用到的图片非常多,,第一次点进这界面时速度非常慢(因为要加载绘制很多图片),可第二次点击却一下子就进去了。这是为什么呢?原来Cocos2dx的渲染机制是可以重复使用同一份纹理在不同的场合进行绘制,从而达到重复使用,降低内存和GPU运算资源的消耗与开销。举个例子:创建一个精灵

auto sp = Sprite::create("image.png");//精灵图片是image.png  

第一次使用image.png这图片有两个步骤,一个是先将图片加载进TextureCache缓存中,下一步是绘制图片,从而将其显示在场景中。

第二次使用image.png时,因为之前image.png已经被放入TextureCache中,所以这里只需从缓存中找到这张图片,然后将其绘制出来就可以。

cocos2dx创建sprite的多种方法

精灵(sprite)在所有游戏中都很重要,每个游戏都有这样的情景:一个舞台,上面站着一个某种形式的主角,那主角就是精灵。Sprite 很容易被创建,它有一些可以被配置的属性,比如:位置,旋转角度,缩放比例,透明度,颜色 等等。

方法一

最常用,也是最简单的一种方法

CCSprite *bg=CCSprite::create("sprite/background.jpg",CCRectMake(0,0,480,320));
    bg-> setAnchorPoint(ccp(0,0));
    bg-> setPosition(CCPointZero);
    addChild(bg);

方法二

利用纹理创建sprite

CCImage *image=new CCImage();
    image-> initWithImageFile("sprite/plant.png");
    CCTexture2D *texture=new CCTexture2D();
    texture-> autorelease();
    texture-> initWithImage(image);

我所理解的cocos2dx - 纹理(下)

纹理的缓存管理

纹理的声明周期:Texture2D在加载纹理后会把纹理上传到gpu内存里,发生在initWithMinpmaps(),而Texture2D实例被销毁的时候,会去申请删掉对应的纹理对象。有时候,为了避免一个纹理只是暂时不用,而后又会被使用到,又得从磁盘重新加载上来,应该选择性缓存一些纹理。所以一般不直接创建Texture2D对象,而是用TextureCache

textureCache管理纹理:负责纹理的创建缓存和删除。几乎所有ui元素需要的纹理都是通过此创建的。它为每一个纹理的texture2d对象创建一个索引值,后续需要用到时直接返回一个对象指针。一般是文件路径称为索引键,也能手动设置。它还有一个有用的功能就是adddImageAsync方法异步加载纹理。

场景过度中的资源管理:

1.基于引用计数的资源管理:每个观察对自己需要的资源引用+1,切换时对上一个场景资源-1,为0的就会释放掉。

2.更好的场景过渡资源管理:cache和1方法的结合,manager负责逻辑上的资源引用计数,内部实现关于短暂资源的加载和缓存

我所理解的cocos2dx - 纹理(上)

3d图形渲染最重要就是把纹理贴到物体表面,这过程主要发生在着色器工作阶段,使用光栅化阶段插值计算得出纹理坐标从纹理中采样,然后对片段着色,可以处理丰富特效,光照阴影等。

光栅化

作用是将2d图元转为帧缓冲的整数坐标的片段,每个片段包括颜色深度和模版值。首先确认视窗上哪些整数位置的片段会被图元覆盖,然后对图元进行插值计算。这些信息会被送入后续的阶段进行处理,最后结果用于更新帧缓冲上的该位置信息。片段的颜色由片段着色器决定,光栅化会生成一些易变变量。

多重采样:高分辨率信号以低分辨率表示无法准确运算出3d图形坐标时导致的图形混叠,具体就是锯齿的产生。多重采样就是解决这问题,它是通过以采样点为中心位置,对附近进行采样,共同决定这个点的颜色。多重采样的数据存储在帧缓冲额外的多重采样缓冲区。cocos2dx默认没有开多重采样,要手动设置CCEAGLView为yes开启,并且只能初始化的时候开启。

纹理坐标:纹理以左下角为原点,一个顶点在纹理中坐标通常使用uv,长宽是纹理的长宽,这是给客户端程序使用的。片段着色器使用坐标st,范围为0-1,这一规化过程在光栅化阶段完成。

cocos2dx纹理优化

为什么要谈纹理的问题,游戏的画面无时无刻不充斥着图像,通俗意义上一款精致的游戏都有着非常精美的画面,这样往往能给玩家带来更好的游戏体验,这一点也是对于游戏制作者来说所尽力追求的,但是无奈有CPU和GPU的限制,手持设备上的硬件资源就更窘迫一些了,如何处理好图片资源,往往能给游戏提供更大的扩展空间,从画面上给游戏加分。

就我个人的经历来说,手机上图片资源处理主要是围绕两个点来周旋的,一个是图片占用的内存,图片加载后生成的纹理会存储在GPU中,而纹理的像素格式就决定了在GPU中的内存,占用的内存小来保证了游戏的机型支持,在低端机上也能运行游戏;另一个非常重要的点就是图片的加载速度,速度太慢会导致CPU占用太大,游戏会显得比较卡,这一点非常影响用户体验。对于我们来说需要处理的就是在这两者与游戏画面之间找到自己的平衡点,采用适合自己游戏的图片资源处理方式,下面来慢慢介绍图片部分的基础知识,后面会再更新-x底层是如何加载和处理图片的一些文章,分享自己的一些看法。

像素格式

(以下为texturepacker支持的打包格式)

像素格式 描述
同步内容
--电子创新网--
粤ICP备12070055号