您的位置:

cocosjs渲染过程(原生js动态渲染数据)

cocosjs渲染过程(原生js动态渲染数据)

更新:

本文目录一览:

自学cocos2d js游戏开发应该按什么步骤进行

跟你简要说一下我的自学路,以免你走弯路

背景:

有工作,而且很忙;在不影响工作基础上用业余时间鼓捣(经常会因为工作耽搁学习进度);基本没技术背景(初中qbasic、高中pascal半吊子),大学文科,工作也不是搞代码。因此我感觉我的自学路跟你还是挺契合的。

1

两年前的一天,决定要做独立游戏制作人。选定引擎cocos2d,开始学习objective-c语言;(如果你打算只在iOS平台开发可以学obj-c配合cocos2d或者sprite kit;如果打算跨平台就要用cocos2d-x和c++了;当然unity什么的也不错但是我还没尝试过,一直很向往)

2

我跳过了iOS程序开发(似懂非懂看完了斯坦福那一系列的教学视频),结合当时情况直接选择了cocos2d引擎,这时开始接触 @吴一刀 推荐的博客;我主要看的是子龙山人子龙山人 - 博客园、Ray WenderlichRay Wenderlich、Himi黑米GameDev街区这些博客里最基本的例子,知易那个以我当时的水平还看不懂。

3

尝试开始设计自己的简单游戏,我做打地鼠!当然比教学例子里的打地鼠复杂多了

4

这个过程中发现自己懂的实在是不够,所以又开啃这本书:Learn cocos2d 2 by Steffen Itterheim Andreas Low

5

慢慢的发现需要一些趁手的工具和编辑器,并发展出一套自己构建于cocos2d之上的游戏设计架构。我目前的情况是这样:

关卡编辑我使用plist文件配合自己写的类;

sprite sheet使用TexturePackerTexturePacker;

动画/UI编辑最初自己手写太累,后来选择了cocosbuilder,请注意现在这个软件已经停止维护,转而引导用户使用SpriteBuilderSpriteBuilder(域名都做了自动跳转;SpriteBuilder我木有研究过,建议你研究一下)。

粒子编辑我自己还没实际用到,如果真正需要我感觉cocosbuilder的够我用的。//更新:后来用到了ParticleDesigner和cocosbuilder两个软件的粒子编辑混搭

我当时遇到的一个大麻烦是如何让cocosbuilder、cocos2d版本互相兼容且cocosbuilder无问题。大概情况是这样:cocosbuilder2.1和cocos2d-iphone2.0及2.1版本都不协调怎么办?;What version of Cocosbuilder and Cocos2d-iphone should I choose?

目前我使用的cocosbuilder 2.1版本(渐变层有bug、并且很可惜动画播放完没有触发消息的机制,我只好把每个动画时长都手动记录一下自己处理)

======3月12日更新======

在 @GarfieldKwong 指点下发现这个版本动画播放完是可以触发消息机制的,更高级版本3.x支持的效果应该是在动画中就加入callback的关键帧

新技能get√

具体代码可见下面学习案例的第一个例子里Explosion部分

=====================

cocosbuider的学习可以看两个例子Creating a Game with CocosBuilder;Introduction to CocosBuilder;然后就是多用多尝试。

6

整个学习过程要学会查资料、学会寻求帮助,我主要用的stackoverflow(话说刚刚发现stackoverflow的reputation喜过15,终于可以投票了:)

在学习过程中得到了子龙山人(我认为本尊是这位 @屈光辉 )、LearnCocos2d作者Steffen、 @kubisoft 以及众多网上朋友的帮助,再次表示感谢。

7

硬件及开发者资格:看完c++开始看obj-c,这个过程一直是使用的vmware虚拟机安装的mac系统写程序;然后入手一个最便宜的mac pro、以及iPhone,尝试玩各种游戏;从看c++开始大约过了1年半(已经有非常简陋的游戏demo)才真正购入iOS开发者资格并开始真机测试。

8

尝试过的一些其他工具、各种弯路和坑、以及发散内容:

可以拖拽方式写代码的stencyl Stencyl: Make iPhone, iPad, Android Flash Games without code;

最初学的不是ojc-c而是谭浩强老师的c++程序设计(虽然有人不喜谭老师,但那书是中文的让我对面对对象程序设计有一些初步的概念,再看英文的obj-c不至于太摸不着头脑,反正手头正好有这么一本买了6年没看的c++。。。);

尝试过Tiled Map Editor但自己目前的坑没有用到;

尝试过一点物理引擎和粒子,但自己目前的坑没有用到;现在粒子用到了,做了火焰等效果,也挺美的;但是一定要注意CPU占用优化,内存方面我最低支持4S没遇到大问题

学习音乐制作,这个我小时候学琴一直也喜欢音乐所以有一点点底子,如果没有基础可能上手有门槛;开始用的软件LMMS,但是音源插件在64位系统的问题我一直没解决掉时间精力也不多,所以是暂时停滞了;最近发现Garage Band可能也可以写歌;另外还试过一个很有历史的微软的音乐自动编辑器,很好玩,用来做背景音乐也不错。

入手手绘板学画画(这中间纠结了好久才决定用位图不用矢量图),如果你能找到热爱游戏的美术同学一起搞那最好不过。但是我一直对画画心痒难搔。。。所以入了这个深坑,晒一晒:

转载

z

cocos creator 2.4.0 渲染流程详解(七:ForwardRender)

全文共5000+字,分为8个章节,由本人历时一周整理而来。由于篇幅问题,将本文分为8个章节分开发布。全文 ( 不 ) 详细描述了cocoscreator 引擎的2.40版本中,web平台的js部分引擎的渲染流程。请将文章配合源码一起食用!

由于我尚在学习引擎源码中,文章可能有不正确的部分,所以我会不断更新内容。如有错误或补充,请留言交流!

全部章节链接:

一: 渲染流程中用到的核心类

二 : 渲染流程详解

三: RenderFlow 的运行逻辑

四: Assembler 的作用

五: ModelBatcher 数据合批

六: 材质系统

七: ForwardRender

ForwardRender 继承于 Base, 是与底层渲染最靠近的类型,当上面的流程处理完毕后,会在ForwardRender 的 render() 中处理当前场景的渲染状态,材质,光照,通道,着色器,更新着色器的统一变量。并在 _draw() 中调用 device.draw()方法,进行绘制。

部分重要的继承于 Base 的成员变量:

_device:根据运行平台对应的绘制图形对象 gfx.Device 的实例,用于绘制图形到屏幕,类型定义于 cocos2d\renderer\gfx\index.js。

_programLib : 管理 shader 定义,获取,检查等相关的变量。类型定义于 cocos2d\renderer\core\program-lib.js。

_stage2fn:保存有不同渲染通道的名称与其对应的不同渲染方法。ForwardRender 中设置有 shadowcast, opaque, transparent 三种渲染通道。

_viewPools:单个相机的描述数据类(View) 的对象池。一个View对应一个相机。

_drawItemsPools:渲染数据类的对象池,保存有每个渲染批次需要的model,effect 等数据。

_stageItemsPools:单个渲染通道需要渲染的数据的对象池,本质是对 _drawItemsPools 中的数据按照不同通道进行了分类。

ForwardRender 中定义的成员变量:

_lights:保存所有灯光数据。

_shadowLights:保存所有阴影灯光数据。

类名 ForwardRender 翻译为前向渲染,泛指传统上只有 Opaque 和 Transparent 两个通道的渲染技术。cocos有三个渲染通道,渲染通道方法定义在 _stage2fn 中。

渲染管线具体详解请参考unity官方文档(对的,真要学cocos还得看unity的文档):

内置渲染管线中的渲染路径

相关链接

如何用Cocos引擎打造次世代3D画质‘游戏大观

从Cocos 2d-x 3.0起我们已经可以在游戏中使用3D元素。Cocos引擎推出3D功能的时间不算太迟,我们已经可以看到越来越多的手机上能流畅地渲染3D游戏,而且这些机型正在成为主流。在最近两年我们可以看到,高端手机游戏从2D转到3D的倾向很明显。许多游戏开发商试图在竞争激烈的红海里占有一席之地,那么选择开发3D游戏或许会是一个强有力的竞争手段。

上面的视频是我的下一款游戏作品《Food of the Gods》。这游戏使用了Cocos 2d-x 3.3,视频是从我iPhone上录制的实际运行效果。在这篇文章里我将要介绍我是如何制作它、如何把它跑在cocos引擎上的。对于熟悉cocos官方提供的3D示例游戏 《Fantasy Warrior》的开发者,将会看到以下一些主要不同点:

1. 光照贴图(Light Mapping):你将看到每件物体都有被照亮并且投射阴影。光影效果的质量是由你的3D工具软件决定的,用3D软件能烘焙出复杂的光效,包括直接光照,反射光照,以及阴影。

2. 顶点合并(Vertex Blending):请注意看路、草地和悬崖交接的地方,看不到任何可见的接缝。

3. 透明遮罩(Alpha Masks):灌木如果没有透明遮罩就跟纸片一样。

4. 滤色叠加的公告板(Billboards):增加一些光束和其他环境的效果。

所有的模型都是用一个叫Modo的3D 软件建模制作的,贴图则是使用Photoshop。关于3D模型的制作和贴图的绘制在此就不再赘述,网上已经有很多教程,在此主要介绍下跟Cocos 2d-x有关的部分。

模型网格和贴图(Meshes and Textures)

如下图所示,每个模型的贴图都是由几个256 x 256或者更小的贴图组成的。同时你也会注意到我把所有的小图片都合在了一张贴图上,这是减少GPU绘制次数(draw call)最简单的方法之一。贴图是从 或者网上找的。

为了把这些图片拼接起来,我使用的是Photoshop的补偿滤镜(offset filter)然后在接缝的地方用修复画笔来做一些自然的过渡。为了获得一种油画的视觉效果我会先使用cutout滤镜(注意:cutout滤镜也会使得png格式图片的压缩效果更好),然后在需要的地方绘制一些高光和阴影的效果。我发现如果直接拿照片当贴图的话,当你把它尺寸缩小的时候会出现图像噪点。

另一种方案是为每一个模型网格制作一整张独立的贴图。当网格比较小或者摄像机不是很靠近网格的时候这种方法是可行的。如果你的photoshop技术过硬的话,出来的效果会更好。附带的好处是,因为只使用一张贴图因此只有一次GPU绘制调用。但我不建议采用这种方法来制作第一人称射击游戏(FPS)中的建筑,因为当你走得很靠近建筑物的时候,贴图分辨率过低的问题就会显露出来。我不喜欢用这种整张贴图方法,因为这实在太费时耗力了。这个场景的制作花了我足足四天时间。

光照贴图(Light Maps)

当你做好模型和贴图之后,现在就可以来烘焙光照贴图了。Cocos 2d-x目前还不像Unreal或Unity一样在官方编辑器里提供烘焙光照贴图的功能,但是别失望,大部分的制作3D模型的软件都可以烘焙光照贴图,并且效果比市面上任何游戏引擎的效果还好。首先,在你的3D工具软件里,先给场景打好灯光,照亮场景,然后为每份网格制作第二张UV map。每份网格的表面都必须被映射在0到1范围内的UV 平面上。这听起来好像很复杂且耗时,但在Modo里这是非常简单的。我先后使用 “Atlas map”的UV 工具和“Pack UV”工具,这两个工具会自动将网格展开成一个相当不错的排布图。

这些都完成之后,设置3D工具软件的渲染器为“只渲染烘焙的光照”,然后开始渲染。当然了,如果你想做一些环境光遮罩的效果也是可以的。

你也可以使用一些分辨率较低的光照贴图。有时候这样的效果反而会看起来更好,因为相互混叠的模糊像素会让阴影看起来更柔和。上面的这些建筑都映射到一张512 x 512的光照贴图上。整个场景总共使用了4 张512 x 512的光照贴图。请确保每个小图块之间有一定的空隙,且让你的渲染范围比这些图块的边界多出几个像素。这样可以防止当较低的mip-maps(一种纹理采样)起作用时黑边出现在网格周围的角落里。

最后一点听起来像是3D技术的行话。如果是对Texture Packer熟悉的话,那么其中的“Extrude”值起到的作用就是刚刚我所描述的。对贴图的边缘接缝做一些涂抹处理,这样在精灵之间就不会有那些烦人的缝隙了,那些缝隙在这里会变成多边形边缘的黑边。

如果你想牺牲内存和包大小来提高性能的话,你可以把颜色和光照信息都烘焙到一张贴图上并避免共同使用一张光照贴图。但是这样做的话,同样的像素密度,贴图的大小至少得翻一倍。这完全取决于你个人、以及你游戏的要求。

接下来,添加顶点颜色。我在地形上提供了顶点颜色,这可以让着色器在合成悬崖顶上的草地贴图时,不会有任何可见的接缝。下图中涂成白色的顶点部分可以合成你指定的贴图。在这个例子里实际上我只使用红色通道,当然了根据实际需要你可以使用4个通道(RGBA)去合成不同的贴图。

最后,我把整个场景分成了很多独立的网格(mesh):每个建筑都有自己独立的网格,地形独立一个网格,水也是独立一个。带透明遮罩的贴图也会有一个网格——比如视频中看到的植物叶子和小旗子。我这样做有两个原因,首先,让地形、建筑、水和带透明遮罩的贴图各自使用不同的着色器。其次,我们打算通过不渲染摄像机范围外的对象来减少性能开支。很重要的一点是摄像机会根据网格的包围盒来决定对象是否可见,因此尽量把网格弄成小块,这样包围盒会比较小。

导出

完成了模型和贴图之后,我们需要把每个mesh导出为一个.fbx文件。幸运的是,大多数的3D建模软件都支持这个功能。Autodesk为此格式提供了一个免费SDK。但不幸的是,Modo 701在导出fbx格式时会出现相当多的错误。因此我必须自己写一些脚本来保证第二组贴图坐标和顶点颜色的正确导出。你可以从我个人网站上的“Modo Scripts”部分下载这个导出脚本。搞定fbx之后,你将需要用到Cocos 2d-x自带的fbx-conv.exe命令行工具,它位于Cocos 2d-x根目录的/tools下。

fbx-conv.exe -a your_mesh_name_here.fbx

使用“-a”参数后,工具会同时导出mesh的二进制文件(.c3b)和文本格式文件(.c3t)。文本格式的文件非常的有用,你可以利用它来查看所有的东西是否被正确导出,但千万不要把它放到resource目录下。如果所有的都被正确地导出的话,你将在c3t文件的开头看到以下的内容:

“attributes”: [{

“size”: 3,

“type”: “GL_FLOAT”,

“attribute”: “VERTEX_ATTRIB_POSITION”

}, {

“size”: 3,

“type”: “GL_FLOAT”,

“attribute”: “VERTEX_ATTRIB_NORMAL”

}, {

“size”: 2,

“type”: “GL_FLOAT”,

“attribute”: “VERTEX_ATTRIB_TEX_COORD”

}, {

“size”: 2,

“type”: “GL_FLOAT”,

“attribute”: “VERTEX_ATTRIB_TEX_COORD1″

}]

注意VERTEX_ATTRIB_TEX_COORD1这个属性。如果没有它光照贴图将无法显示。如果你导出了一张带顶点颜色的mesh,你也应该要看到一个类似的属性才行。还有一点很重要,贴图的坐标也必须按正确的顺序才行。我通常采用的是第一个tex_coord是瓦片贴图,最后一个tex_coord是光照贴图。使用Modo的话,uv maps会按照字母顺序排列。

着色器(Shaders)

我花了很长的一段时间来搞懂GLSL和着色器,但正如编程中经常遇到的,有时候一个点通了,其他的就都好理解了。一旦理解了其中的原理,你便会发现着色器真的很简单。如果你不只是想用Cocos 2d-x来把贴图套到模型网格上的话,你需要学会如何写着色器。目前Cocos 2d-x没有Unreal那样好用的着色器可视化编辑器(visual shader editor),所以我们只能自己动手焊代码。

本节我将讲解我为视频中的游戏场景所写的着色器,并说明我做了什么、为什么这样做。如果你对着色器已经非常熟悉了,那么可以快速跳过本节。

首先,先来看一下如何将着色器应用到模型网格上。

这段代码摘自Cocos 2d-x的测试集cpp-tests工程。如果你用不同的着色器来加载大量的meshes,那么最好根据功能来进行,这样可以避免冗余。那么现在我们只关心如下的代码段,来看下这个着色器。

GLProgram* shader =GLProgram::createWithFilenames(“shaders/lightmap1.vert”,”shaders/lightmap2.frag”);

GLProgramState* state = GLProgramState::create(shader);

mesh-setGLProgramState(state);

Texture2D* lightmap =Director::getInstance()-getTextureCache()-addImage(“lightmap.png”);

state-setUniformTexture(“lightmap”,lightmap);

“lightmap1.vert”是顶点着色器(vertex shader)。如果将其应用到网格上,那么每个顶点的每一帧都将执行这个操作。而“lightmap2.frag”是片段着色器(fragment shader),网格上贴图的每个像素的每一帧都将执行这个操作。我不太确定为什么将其命名为“片段着色器”,我一直认为应叫做“像素”着色器(pixel shader)。从这段描述,我们可以很容易理解为什么大量着色器指令会降低帧率,尤其是你用片段着色器的话。

接下来我们详细地分解顶点着色器:

attribute vec4 a_position;

attribute vec2 a_texCoord;

attribute vec2 a_texCoord1;

这些属性是由渲染器提供的。“a_position”是顶点的位置。“a_texCoord” 和 “a_texCoord1”对应你那两个UV坐标。还记得在.cbt文本格式文件中开头部分的“VERTEX_ATTRIB_TEX_COORD”么?这些值与属性对应起来了。你可以在渲染器中获取更多其他的属性,包括顶点法线(vertexnormal)和顶点颜色(vertex color)。请在cocos引擎的CCGLProgram.cpp中查看完整属性列表。

varying vec2 v_texture_coord;

varying vec2 v_texture_coord1;

“varying”值将被传到片段着色器中(fragment shader)。片段着色器所需要的任何变量前都需要添加“varying”限定符。这个例子中,我们仅需要知道这两个贴图的坐标。

void main(void)

{

gl_Position = CC_MVPMatrix * a_position;

v_texture_coord.x = a_texCoord.x;

v_texture_coord.y = (1.0 – a_texCoord.y);

v_texture_coord1.x = a_texCoord1.x;

v_texture_coord1.y = (1.0 – a_texCoord1.y);

}

设置顶点位置,拷贝贴图的坐标给varying values,这样片段着色器就可以使用这些值。现在我们一起来分解片段着色器。

#ifdef GL_ES

varying mediump vec2 v_texture_coord;

varying mediump vec2 v_texture_coord1;

#else

varying vec2 v_texture_coord;

varying vec2 v_texture_coord1;

#endif

声明从顶点着色器传递过来的“varying” 值

uniform sampler2D lightmap;

还记得在将着色器应用到网格时所使用的 state-setUniformTexture(“lightmap“,light map); 语句么?这个值就是对应语句中的那个贴图。

void main(void)

{

gl_FragColor = texture2D(CC_Texture0, v_texture_coord) *(texture2D(lightmap, v_texture_coord1) * 2.0);

}

这个语句设置像素颜色。首先你会注意到从未声明过的 CC_Texture0变量。Cocos 2d-x中有大量可在着色器中使用的默认统一变量。再次强调,可在CCGLProgram.cpp中查看完整属性列表。这个例子中,CC_Texture0对应在3D模型中所应用到网格中的贴图。texture2D命令会在给定的贴图坐标中去查找贴图的像素颜色和透明度。它会返回一个包含了那个像素的RGBA值的vec4值 。所以这里我会在UV1中查找到瓦片贴图的颜色值,然后在UV2中查到光照贴图的颜色值,最后把两个值相乘。

你应该注意到了我先是把光照贴图的颜色值两两相乘了。因为贴图颜色值范围为0.0-1.0,所以很显然,如果用白色值vec4(1.0, 1.0, 1.0, 1.0)去乘中间灰值vec4( 0.5, 0.5, 0.5,1.0 ),那么你仍是得到一个中间灰值vec4( 0.5, 0.5, 0.5,1.0 )。将两个值相乘可以使贴图更亮,同时也可以使贴图更暗,这将使你获得一个很好的可变的亮度范围。

cocos creator 如何加载一张图片并渲染出来的

导读:   ccc 我们在使用一张图片的时候,使用cc.laod api ,回调传回来cc.spriteFrame 或者cc.texture来供我们使用。下面的内容会解密中间到底经历了哪些过程(native)。

加载:首先会在js引擎中,通过一些方式得到资源的完整信息,包括资源的完整路径资源类型等(可以了解下load的加载过程)。

然后调用jsb_global_load_image方法,利用native来加载这张图片到内存中,拿到内存首地址和内存大小。

把刚才拿到的信息转为jsObject,内存地址和大小会被描述成arrayBuff,包装好的对象回调回给js。

js引擎拿到回调后会创建一个texture来,然后调用 texture.initWithElement()方法,把之前包装好的数据再传回给native的texture对象(js的texture利用jsb来管理native的texture对象,并且是1对1的)。

渲染:native的texture接收到数据后会用OpenGL的api来开辟显存,绑定纹理数据(分配一个纹理id给native的texture)。然后通过device(DeviceGraphics是单例,大多数的OpenGL api接口都是通过他调用)渲染到屏幕上。(OpenGL api可自行查找资料)

我们在js端让一个精灵显示图片的时候,是在load的回调里 把cc.spriteFrame给精灵使用,spriteFrame里持有cc.texture对象,cc.texture又持有由native返回的数据。通过这种方式让纹理数据和将要渲染的对象绑定起来。

还有许多包括顶点数据  node的位置 大小 shader 等等 都在RenderFlow等类中获取和封装(比较复杂),最后配合纹理数据 渲染出来。我们加载的一张图片就这样渲染到了屏幕上。

流程图:

cocos js 怎样做出按钮选中效果

cocos js 做出按钮选中效果示例:

一,首先使用cocos新建一个Cocos2d-js的新项目,然后再cocostudio中创建一个场景,在场景中添加三个按钮分别设置三态的图片

二,打开编辑器,实现代码如下:

var HelloWorldLayer = cc.Layer.extend({

ctor:function () {

this._super();

//导入cocostudio中拼好的界面

mainscene = ccs.load(res.MainScene_json).node;

this.addChild(mainscene);

this.teamButton = ccui.helper.seekWidgetByName(mainscene,"Button_0");

var btn2 = ccui.helper.seekWidgetByName(mainscene,"Button_1");

var btn3 = ccui.helper.seekWidgetByName(mainscene,"Button_2");

//先默认设置一个按钮为选中状态   this.teamButton.setBrightStyle(ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT);

this.teamButton.setEnabled(false);

var teamInfo = this.teamButton;

this.teamButton.addTouchEventListener(this.selectedBtn1,this);

btn2.addTouchEventListener(this.selectedBtn2,this);

btn3.addTouchEventListener(this.selectedBtn3,this);

return true;

},

selectedBtn1: function (sender, type) {

if(type == ccui.Widget.TOUCH_ENDED){

this.callBack(sender);

cc.log("==========商店界面");

}

},

selectedBtn2: function (sender, type) {

if(type == ccui.Widget.TOUCH_ENDED){

this.callBack(sender);

cc.log("==========卡牌界面");

}

},

selectedBtn3: function (sender, type) {

if(type == ccui.Widget.TOUCH_ENDED){

this.callBack(sender);

cc.log("==========战斗界面");

}

},

callBack: function (sender) {

if (this.teamButton == sender){

return;

}else{

this.teamButton.setBrightStyle(ccui.Widget.BRIGHT_STYLE_NORMAL);

this.teamButton.setEnabled(true);

sender.setBrightStyle(ccui.Widget.BRIGHT_STYLE_HIGH_LIGHT);

sender.setEnabled(false);

this.teamButton = sender;

}

},

});

var HelloWorldScene = cc.Scene.extend({

onEnter:function () {

this._super();

var layer = new HelloWorldLayer();

this.addChild(layer);

}

});

三,运行就可以查看界面,点击不同的按钮显示不同的输出结果

[Log] ==========商店界面 (CCDebugger.js, line 331)

[Log] ==========卡牌界面 (CCDebugger.js, line 331)

[Log] ==========战斗界面 (CCDebugger.js, line 331)