找一个类似于1010的游戏,好像叫score还是什么的,是一个多边形的形状里放益智方块消除除的游戏

1010 Colour World中文版|1010 Colour World破解版下载V1.0.1安卓版_西西安卓游戏
西西软件园多重安全检测下载网站、值得信赖的软件下载站!
当前位置: →
→ 1010 Colour World破解版 V1.0.1安卓版
1010 Colour World破解版
扫描下载到手机
安卓游戏推荐
分类:休闲益智游戏大小:23.2M游戏语言:中文
版本:V1.0.1安卓版更新时间:游戏星级:
官网:游戏厂商:游戏平台:Android
游戏标签:
1010 Colour World是一款类似于2048的游戏,玩家将方块组成的图形放入格子中消除。将一个个小正方形组成的各种方块形状放入格子中进行消除,玩法轻松有趣,休闲益智,快来1010 Colour World体验吧!1010 Colour World破解版简介:《1010&Colour&World》是一款画面非常清晰的方块消除了类益智游戏,玩家将方块组成的图形放入格子中消除。将一个个小正方形组成的各种方块形状放入格子中进行消除,消除得越顺利,获得的空间就越多,当剩余的方块没有足够空间摆放时,游戏就宣告失败!1010 Colour World破解版特色:在10×10的区域,每一次都会出现3个不同的块,没有时间限制,没有颜色搭配。当一行或列被填充时,将被淘汰,游戏将结束时不再是空白区域。立即进入这个新的和有趣的广场世界!只下降块创建和消灭全行的屏幕上的垂直和水平,并保持在这个令人上瘾的益智游戏屏幕填充块。没有时间限制,没有颜色匹配!用匹配的块填满所有的网格,并享受这个谜题游戏!
安卓版PC版IOS版
西西点击类手游专区为大家带来各种触屏点击类游戏下载,可谓是手残党的福音哦!各种点击类益智游戏,点击类...
西西软件园为大家提供各种好玩免费的休闲益智手机游戏下载大全和安卓休闲益智手游排行榜,在这里有各种好玩...
休闲游戏有很多种,一般都是那种玩法特别容易理解,也不需要思考太多的游戏,这类游戏都是上手容易精通难,...
1010 Colour World破解版 V1.0.1安卓版
本类下载排行
同类最新合集&img src=&/50/v2-e20ad3df48fbdca8c2afafef7d4ba5d9_b.jpg& data-rawwidth=&1280& data-rawheight=&720& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&/50/v2-e20ad3df48fbdca8c2afafef7d4ba5d9_r.jpg&&&p&《崩坏3》出了以后,Cel-shading一下子就火了,以前一直玩的都是真实感渲染,一次偶然的机会让我有机会去接触赛璐珞感觉挺有意思的,所以在这里分享一下我的这段经历给喜欢图形渲染的朋友,顺便也声明一下回归,毕竟消失了这么多年。7年前的《&a href=&/?target=http%3A//www.opengpu.org/bbs/forum.php%3Fmod%3Dviewthread%26tid%3D2870%26extra%3Dpage%253D1& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Crysis分析 》&i class=&icon-external&&&/i&&/a&由于没有Gamma Correction以及适当的抗锯齿已经显得非常地令人无法接受,希望有机会再做高端真实向渲染的时候再与大家分享。&/p&&p&《崩坏3》的日漫角色给我留下了非常深刻的印象,作为一个《崩坏1》的老玩家以及资深的画面党,看到这样的作品上线自然是非常的开心的。我有简单逆向过它的渲染帧,发现他使用的规格还是相对简单的,真正令人惊讶的是它竟然分配了超过1.5W的多边形来制作角色,这种极端的选择让我非常的惊讶,因为这会导致场景制作可用的资源变得非常有限,当然我承认对二次元作品来说,角色的重要性比起真实感渲染高出非常多,这样的选择虽然激进,但是我非常认同这样的冒险,毕竟就国内的资本环境而言,这实在是非常难能可贵的一件事,在此我要对米哈游以及《崩坏3》的全体制作团队表示深深的敬意。&/p&&p&当然对于我来说,《崩坏3》所使用的shading方式有点太过于简单了,因为那样的做法想要在一个6K左右的普通模型上实现差不多的效果是非常困难的,所以我就没有仔细分析他们的渲染方式,有兴趣的小伙伴们自己去看吧。在这里,我必须把故事拉回到那个第一次把赛璐珞做到超高还原度的GGX上,先来分析下他们可以做到如此正确渲染的原因,然后再试着简化他的渲染模型,来实现一个手机上运行起来性能可以接受并且很美的效果。在此要特别感谢很久之前翻译了GGX访谈的&a href=&/?target=http%3A///TracePlus/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Trace&i class=&icon-external&&&/i&&/a&大大。&/p&&p&在我看来CelShading最重要的东西就是面数了,没有什么比面数高更能大幅度提升效果的方法了,所以作为单机格斗的GGX会拥有非常巨大的面数预算优势(据官方表示角色预算在12.5W),同样面对《崩坏3》,我所使用的6K模型劣势也是非常明显的。对于赛璐珞风格来说,能够精细地控制描边是非常正义的一件事情,所以额外PASS的法线挤出描边是唯一的一个选择了,因此,面数对于这样的风格来说,会额外地有压力。在低面数情况下,角色高频光影有非常大的需求用纹理来解决的,这是我最先考虑的一个问题。但是我一开始并没有草率的决定使用何种方式的纹理数据来表现高频光影。&/p&&p&下面罗列下GGX所使用的光影类渲染数据: &/p&&p&1. 首先是高光MASK,使用了MASK后角色的高光只会在合适的位置出现,对于赛璐珞来说,并不需要有杂点的MASK来表现不平整的表面,所以这个MASK只是被用来标记某个区域是否有高光显示。&/p&&img src=&/v2-898e04fd04b413af88a280_b.jpg& data-rawwidth=&552& data-rawheight=&751& class=&origin_image zh-lightbox-thumb& width=&552& data-original=&/v2-898e04fd04b413af88a280_r.jpg&&&p&&br&&/p&&img src=&/v2-39aa446cbfdda474b3afb8_b.jpg& data-rawwidth=&552& data-rawheight=&751& class=&origin_image zh-lightbox-thumb& width=&552& data-original=&/v2-39aa446cbfdda474b3afb8_r.jpg&&&p&2. 然后是高光进入倾向,这个其实很好理解,就是specular power的ramp版,来控制高光点的样子和位置来表现不同反光度的表面,可以看到下图中,身上手上和头盔上的高光倾向不同,头盔上的倾向低,强度高,所以有明显的金属感。&/p&&img src=&/v2-c09ffaab6eba1d03992ab2_b.jpg& data-rawwidth=&500& data-rawheight=&635& class=&origin_image zh-lightbox-thumb& width=&500& data-original=&/v2-c09ffaab6eba1d03992ab2_r.jpg&&&p&&br&&/p&&img src=&/v2-4cafec42bd4280_b.jpg& data-rawwidth=&500& data-rawheight=&635& class=&origin_image zh-lightbox-thumb& width=&500& data-original=&/v2-4cafec42bd4280_r.jpg&&&p&3. 阴面倾向,用来让一些位置更容易变暗,看起来像是用了一张烘出来的AO作为这个图的数据,其实只是让阴的部分连接更多的区域,这个其实也是好理解的,因为他们没有卡通条来控制这个倾向,而且每个点都可以有一个独立倾向于,使得绘制过程更容易被美术控制来实现一个更加正确的渲染结果。&/p&&img src=&/v2-f6650add2f38a203fd3aed0a1dbe7a3c_b.jpg& data-rawwidth=&701& data-rawheight=&755& class=&origin_image zh-lightbox-thumb& width=&701& data-original=&/v2-f6650add2f38a203fd3aed0a1dbe7a3c_r.jpg&&&p&&br&&/p&&img src=&/v2-de51b8ae56_b.jpg& data-rawwidth=&701& data-rawheight=&755& class=&origin_image zh-lightbox-thumb& width=&701& data-original=&/v2-de51b8ae56_r.jpg&&&p&&br&&/p&&img src=&/v2-cf649f1aa8e1db6173195_b.jpg& data-rawwidth=&701& data-rawheight=&755& class=&origin_image zh-lightbox-thumb& width=&701& data-original=&/v2-cf649f1aa8e1db6173195_r.jpg&&&p&4. SSSTexture,这个呢,其实就是每个点都能独立决定暗部的颜色和光颜色的关系,而不是简单的mul光的颜色产生一个非常愚蠢的暗部。&/p&&img src=&/v2-8ade850e8ed65fbd656da52f3bc36173_b.jpg& data-rawwidth=&675& data-rawheight=&677& class=&origin_image zh-lightbox-thumb& width=&675& data-original=&/v2-8ade850e8ed65fbd656da52f3bc36173_r.jpg&&&p&&br&&/p&&img src=&/v2-262e80aaee6a75e65f1ac843f6b583c8_b.jpg& data-rawwidth=&675& data-rawheight=&677& class=&origin_image zh-lightbox-thumb& width=&675& data-original=&/v2-262e80aaee6a75e65f1ac843f6b583c8_r.jpg&&&p&5. 边缘光MASK,就是一个简单的把边缘光抖掉的东西&/p&&img src=&/v2-5da89a2f6_b.png& data-rawwidth=&1000& data-rawheight=&535& class=&origin_image zh-lightbox-thumb& width=&1000& data-original=&/v2-5da89a2f6_r.png&&&p&&br&&/p&&img src=&/v2-311d12ea72fe536cd1c6_b.png& data-rawwidth=&1000& data-rawheight=&535& class=&origin_image zh-lightbox-thumb& width=&1000& data-original=&/v2-311d12ea72fe536cd1c6_r.png&&&p&可能还有一些别的什么纹理来影响,由于没有逆向,我也不太清楚,点了逆向天赋的朋友们可以试试,在这里我觉得信息量已经足够让我有一个合适的解决方案了,所以就此打住GGX,开始思考要使用一个什么样的规格。由于移动平台的ETC压缩格式的关系,我更倾向于使用三通道的规格,一开始就决定让美术绘制两张三通道的纹理来实现效果。那方案是什么呢? 感觉要给个华丽丽的分割线来卖个关子,于是就这么干了。&/p&&p&__________________________________________________________________________&/p&&p&然后我来放一张原始的不带任何后处理的shading结果来展示下一个我觉得还不错的4K的模型&/p&&img src=&/v2-98bcdc27d7052fee7296fe_b.png& data-rawwidth=&503& data-rawheight=&792& class=&origin_image zh-lightbox-thumb& width=&503& data-original=&/v2-98bcdc27d7052fee7296fe_r.png&&&p&为什么这样的效果看起来很好呢?其实我觉得西川老师非常的坑爹,把最重要的东西藏在了一个非常不起眼的位置说了一个非常不联系的解释。其实关键就是SSSTexture,这个真的不只是用来做SSS的,而是一个对于Celshading来说最为重要的功能,如果没有这个功能, 是很难做还原度的(《崩坏3》确实没有这个,但是人家是原创的,画好看就好了)。因为赛璐珞的画的啊,背光面是啥颜色怎么可能是一致的mul,如果使用直接的ramped(NdotL)得有多难看啊,暗部的每一个颜色都需要美术的控制,才能正确地绘制,这才是和真实感渲染最不一样的地方。所以GGX有了那张SSSTexture才会让人感觉光影色域非常地和谐。所以这个功能需要很大程度上去保留,但是这让我看到了一个优化用的点。GGX所使用的方式是一张对应UV1的纹理,也就是说每个点都可以有一个自己的变色,但实际上,日漫效果一般色块就那么几个,非常的有限,所以用材质索引的方式好像就好了,而且由于我当时做的Fate角色没有崩坏那么复杂的颜色配置,用一个255精度的id去索引一个2D的卡通条显得非常的高效。卡通条的V方向决定每个位置的阴面倾向,U方向是材质ID,这样的话,如果使用一个半条一个整条的方式,就能画出高频的影,然后我在卡通条的alpha中存放了边缘光的倾向,使得一个ID同时实现了GGX中变色,边缘光和倾向绘制三个特性,赚得一本满足,于是就心满意足地让美术开工了。最后锁定的规格是,顶点RGB决定描边色,A决定边粗细,一张albedo填充大色块,一张mat纹理,R中存放高光MASK,G中存放ID(重要属性必须使用一般压缩格式中精度最高的G),B中存放手绘细节线条(GGX中那个UV拉法太变态了,需要很高的面数支持,带来巨大的制作麻烦,但是收益只是特写镜头中的完美线条,感觉对于手机游戏来说一点意义没有,所以直接纹理解决)。&/p&&p&分享一下这个模型的纹理:&/p&&img src=&/v2-a88daa620e05f_b.png& data-rawwidth=&941& data-rawheight=&799& class=&origin_image zh-lightbox-thumb& width=&941& data-original=&/v2-a88daa620e05f_r.png&&&p&就这样,突然就迷上了日漫赛璐珞了呢,一个相对简单的规格,就在低模上有如此不错的表现真是非常开心的。当然还有反射的处理,写不动了,就放张手机上实际场景的图吧,等以后有机会再讲我反射相关的处理,当然老生常谈一句,没有HDR肯定是不行的讲道理嘛。&/p&&img src=&/v2-da2a5d3ac34207cba7d3ce44d0bf1447_b.png& data-rawwidth=&1805& data-rawheight=&867& class=&origin_image zh-lightbox-thumb& width=&1805& data-original=&/v2-da2a5d3ac34207cba7d3ce44d0bf1447_r.png&&&p&呆毛姐姐感觉需要一个特写&/p&&img src=&/v2-eed45f40c0ef064c7cd3cfa5ab321d8e_b.png& data-rawwidth=&313& data-rawheight=&445& class=&content_image& width=&313&&&p&好了,这一期就先到这儿了,这里特别感谢下图形方面带我装逼带我飞的 &a class=&member_mention& href=&/people/0b21747b1fec79ad8af7e68a2b1ff681& data-hash=&0b21747b1fec79ad8af7e68a2b1ff681& data-hovercard=&p$b$0b21747b1fec79ad8af7e68a2b1ff681&&@叛逆者&/a&, 教我使用Unity的 &a class=&member_mention& href=&/people/96ebf60da4f1295abab79cce388e85c0& data-hash=&96ebf60da4f1295abab79cce388e85c0& data-hovercard=&p$b$96ebf60da4f1295abab79cce388e85c0&&@钱康来&/a& 以及不记得名字但是陪我一起研究做原型的美术同学。&/p&
《崩坏3》出了以后,Cel-shading一下子就火了,以前一直玩的都是真实感渲染,一次偶然的机会让我有机会去接触赛璐珞感觉挺有意思的,所以在这里分享一下我的这段经历给喜欢图形渲染的朋友,顺便也声明一下回归,毕竟消失了这么多年。7年前的《…
&img src=&/50/v2-9a2b7d5714_b.jpg& data-rawwidth=&851& data-rawheight=&315& class=&origin_image zh-lightbox-thumb& width=&851& data-original=&/50/v2-9a2b7d5714_r.jpg&&&p&就在近期的Unite Europe 2017 中,有两个talk比较有意思,分别是The AAA graphics of Spellsouls: achieving 60FPS on mobile 和 The&br&Real-time VFX of Spellsouls,恰好最近在做一些优化方面的工作,就一起学习了一下。&/p&&p&&br&&/p&&p&游戏官方介绍说是一个Moba类的卡牌,但个人感觉就是3D版的炉石?下面是几个截图。&/p&&p&&br&&/p&&img src=&/50/v2-a1a09fbbaa2d_b.png& data-rawwidth=&1251& data-rawheight=&657& class=&origin_image zh-lightbox-thumb& width=&1251& data-original=&/50/v2-a1a09fbbaa2d_r.png&&&p&&br&&/p&&p&&br&&/p&&img src=&/50/v2-912faeb817a2cc3b7daeeec7d847a2f9_b.png& data-rawwidth=&1256& data-rawheight=&655& class=&origin_image zh-lightbox-thumb& width=&1256& data-original=&/50/v2-912faeb817a2cc3b7daeeec7d847a2f9_r.png&&&p&&br&&/p&&p&&br&&/p&&p&作为一个图形程序,目标有两个:&/p&&p&&br&&/p&&p&AAA级别的画质&/p&&p&支持尽可能多的移动设备&/p&&p&&br&&/p&&p&所面临的挑战&/p&&p&&br&&/p&&img src=&/50/v2-020af72fcdf16d5e152a_b.png& data-rawwidth=&1147& data-rawheight=&609& class=&origin_image zh-lightbox-thumb& width=&1147& data-original=&/50/v2-020af72fcdf16d5e152a_r.png&&&p&&br&&/p&&p&&br&&/p&&p&首先是如何基于PBR Shading打造一种真实暗黑风格,然后是Shader的变种,接着是对性能的优化,最低设备支持到iphone4s,最后是动态画质调整。&/p&&p&&br&&/p&&img src=&/50/v2-04ac0d1366_b.png& data-rawwidth=&1134& data-rawheight=&604& class=&origin_image zh-lightbox-thumb& width=&1134& data-original=&/50/v2-04ac0d1366_r.png&&&p&&br&&/p&&p&PBR Shading之多对性能消耗很大,是因为其光照模型非常的复杂,这个代价对于大部分的低端设备还是不太现实的,我们对PBR做了一些深入研究之后,决定还是走Blinn-Phong这一套,采用的是近似的方法来处理。&/p&&p&通过和美术同学的通力合作,我们得到了一些不错的效果,而且在移动平台,由于屏幕尺寸很小,所以和真实的PBR差别并不是很大。&/p&&p&&br&&/p&&p&&br&&/p&&img src=&/50/v2-a571cccbeac_b.png& data-rawwidth=&1125& data-rawheight=&587& class=&origin_image zh-lightbox-thumb& width=&1125& data-original=&/50/v2-a571cccbeac_r.png&&&p&&br&&/p&&p&当一提到PBR的时候,你可能第一时间会反应出一个模型拥有不同的质感,比如皮革,金属,木头等等。我们最初就用了Roughness和Metalness来处理,但是我们发现这还不够,原因有两点,对于Roughness和Metalness的计算非常消耗性能,另一个原因是我们的游戏是一个魔幻类的游戏,有时候又不想那么真。最终我们添加了一张新的Reflectivity贴图,这样计算cubemap的反射就非常简单了。&/p&&p&&br&&/p&&p&对于环境光对角色的影响,采用的是分级的Cubemap&/p&&p&&br&&/p&&img src=&/50/v2-5525a56aff9c9dede71e484_b.png& data-rawwidth=&1116& data-rawheight=&594& class=&origin_image zh-lightbox-thumb& width=&1116& data-original=&/50/v2-5525a56aff9c9dede71e484_r.png&&&p&&br&&/p&&p&同时我们对CubeMap进行了HDR的处理,让暗的地方更暗,亮的地方更亮,这样最终效果会更好一些。&/p&&p&&br&&/p&&p&接下来要说的是&/p&&p&&br&&/p&&img src=&/50/v2-efefcf4103ffd54d0ec7feb_b.png& data-rawwidth=&1138& data-rawheight=&599& class=&origin_image zh-lightbox-thumb& width=&1138& data-original=&/50/v2-efefcf4103ffd54d0ec7feb_r.png&&&p&&br&&/p&&p&对于动态阴影,我们首先考虑的是Unity自带的阴影系统,他可以适用于很多场合,FPS,TPS等等,但是我们只有俯视角的操作,所以我们实现了自己的基于PCF的阴影系统,比Unity自带的影子系统更快一些,而且可以精准的控制,你们如果要自己来处理阴影的话,最好先考虑下基于自己的游戏能不能做的比Unity更好,同时有没有时间去处理,我们对这两个问题的回答都是yes,所以我们这样做了。&/p&&p&&br&&/p&&p&可以注意到场景中的动态阴影和地面烘培的静态阴影可以完美地Blend,这更加符合真实世界的表现。技术上,对于Lightmap,rgb三个通道用来表示光照的,阴影Bake在alpha 通道里面,最终和动态阴影Blend。&/p&&p&&br&&/p&&p&我们采用的VRay来进行光照的烘培,这是设计师和技术共同的抉择,从技术方面我们可以实现很酷的阴影,美术方面他们可以在Max里面控制烘培的效果,品质也会更高。&/p&&p&&br&&/p&&p&接下来是动态的光照&/p&&p&&br&&/p&&img src=&/50/v2-a8fe0e0cadf5fbfa42a679a_b.png& data-rawwidth=&1119& data-rawheight=&577& class=&origin_image zh-lightbox-thumb& width=&1119& data-original=&/50/v2-a8fe0e0cadf5fbfa42a679a_r.png&&&p&&br&&/p&&p&我们没有去做Defered rendering,因为这在移动平台上不太现实,而用forward的方式渲染的时候,对于多个光源的情况,需要通过多个Pass来渲染,这也很 expensive,所以我们做了几个不同的shader来处理0个灯光,1个灯光,2个灯光,3个灯光,4个灯光的情况,按照设备的性能来使用对应的shader。&/p&&p&&br&&/p&&p&对于每一个材质我们都可以在编辑器上定义一些渲染状态,&/p&&p&&br&&/p&&img src=&/50/v2-b51eada2510_b.png& data-rawwidth=&1113& data-rawheight=&591& class=&origin_image zh-lightbox-thumb& width=&1113& data-original=&/50/v2-b51eada2510_r.png&&&p&&br&&/p&&p&为了给设计师充分的空间,我们的Shader通常写得非常复杂&/p&&p&&br&&/p&&img src=&/50/v2-0db6fb2b12bc97d0225fee16_b.png& data-rawwidth=&1137& data-rawheight=&587& class=&origin_image zh-lightbox-thumb& width=&1137& data-original=&/50/v2-0db6fb2b12bc97d0225fee16_r.png&&&p&&br&&/p&&p&遇到了三个问题&/p&&p&&br&&/p&&img src=&/50/v2-cbde_b.png& data-rawwidth=&1131& data-rawheight=&599& class=&origin_image zh-lightbox-thumb& width=&1131& data-original=&/50/v2-cbde_r.png&&&p&&br&&/p&&p&分析了一大堆之后,决定自己动手撸一个Variant system&/p&&p&&br&&/p&&img src=&/50/v2-43c5f4f8e1cb172840df_b.png& data-rawwidth=&1130& data-rawheight=&581& class=&origin_image zh-lightbox-thumb& width=&1130& data-original=&/50/v2-43c5f4f8e1cb172840df_r.png&&&p&&br&&/p&&p&听起来很炫酷,但其实很简单,一共分为两个部分&/p&&p&&br&&/p&&img src=&/50/v2-a8c57def6_b.png& data-rawwidth=&1138& data-rawheight=&574& class=&origin_image zh-lightbox-thumb& width=&1138& data-original=&/50/v2-a8c57def6_r.png&&&p&&br&&/p&&p&还优化了构建的速度&/p&&p&&br&&/p&&img src=&/50/v2-9e4eef27bf7e0af817e250_b.png& data-rawwidth=&1131& data-rawheight=&593& class=&origin_image zh-lightbox-thumb& width=&1131& data-original=&/50/v2-9e4eef27bf7e0af817e250_r.png&&&p&&br&&/p&&p&重点,CPU和GPU的优化!我们实际上需要优化的东西有三点,帧率,电量,发热&/p&&p&&br&&/p&&img src=&/50/v2-35ecc27c5ce8b37785decbc6a24531a4_b.png& data-rawwidth=&1123& data-rawheight=&594& class=&origin_image zh-lightbox-thumb& width=&1123& data-original=&/50/v2-35ecc27c5ce8b37785decbc6a24531a4_r.png&&&p&&br&&/p&&p&做优化的时候,一定要同时考虑三者。首先讲GPU的优化&/p&&p&&br&&/p&&img src=&/50/v2-527c73d7bc485c7defbc223_b.png& data-rawwidth=&1122& data-rawheight=&599& class=&origin_image zh-lightbox-thumb& width=&1122& data-original=&/50/v2-527c73d7bc485c7defbc223_r.png&&&p&&br&&/p&&p&可以用Adreno Profiler截帧,然后实时改shader生效,这样就解决了重新编译之痛。&/p&&p&&br&&/p&&p&不过Adreno Profiler看到的shader很难看懂,一个trick就是你可以用Unity Editor编译出来的shader直接贴在这里,也可以立即生效。&/p&&p&&br&&/p&&p&在Adreno Profiler还可以看到shader里面指令数量,指令数量越多,消耗肯定就越高&/p&&p&&br&&/p&&img src=&/50/v2-ec1881155cad2ca15bfaa66c75fb50e5_b.png& data-rawwidth=&1126& data-rawheight=&584& class=&origin_image zh-lightbox-thumb& width=&1126& data-original=&/50/v2-ec1881155cad2ca15bfaa66c75fb50e5_r.png&&&p&&br&&/p&&p&下图中的抖动是因为移动设备的过热保护造成的。下面是很容易踩到的坑,希望你们别踩到了。&/p&&p&&br&&/p&&img src=&/50/v2-ad43e1285fdf_b.png& data-rawwidth=&1125& data-rawheight=&598& class=&origin_image zh-lightbox-thumb& width=&1125& data-original=&/50/v2-ad43e1285fdf_r.png&&&p&&br&&/p&&p&1. 不要在develop mode来衡量fps,虽然在develop mod可以用来做profiling和找性能瓶颈,但是你所面对的游戏和你的最终用户所面对的游戏是不一样的,很多地方代码消耗都不一样,最不济也是在release版本下在屏幕上放个fps统计。&/p&&p&2. 因为移动设备对于过热会有降频保护,所以在测试的时候,很可能会因为性能波动而造成fps波动,多疑参考第三点&/p&&p&3. 把目标帧率拔高一些作为优化目标,这样在发布的时候帧率恢复到正常帧率就不会出问题了,比如我们在优化60fps的时候是将目标帧率锁定在80的。&/p&&p&&br&&/p&&p&&br&&/p&&p&对于Shader的优化主要是两个点,减少指令数,小心No-ops.&/p&&p&&br&&/p&&img src=&/50/v2-de065f2afd5b65c883a6d_b.png& data-rawwidth=&1136& data-rawheight=&599& class=&origin_image zh-lightbox-thumb& width=&1136& data-original=&/50/v2-de065f2afd5b65c883a6d_r.png&&&p&&br&&/p&&p&当年我们在做自己的GPU Skinning,下面是一条最简单的蒙皮计算&/p&&p&&br&&/p&&img src=&/50/v2-d2e49f6c3d_b.png& data-rawwidth=&835& data-rawheight=&58& class=&origin_image zh-lightbox-thumb& width=&835& data-original=&/50/v2-d2e49f6c3d_r.png&&&p&&br&&/p&&p&性能和预期差别太大了,我们在Profiler里面显示有250条No-ops,。结果我们换成下面的形式&/p&&p&&br&&/p&&p&&br&&/p&&img src=&/50/v2-ca3d793ebe5e774cb8837_b.png& data-rawwidth=&1029& data-rawheight=&140& class=&origin_image zh-lightbox-thumb& width=&1029& data-original=&/50/v2-ca3d793ebe5e774cb8837_r.png&&&p&&br&&/p&&p&快了20%!&/p&&p&&br&&/p&&p&最后一个是用half来替代float,这个在shader里面可以提速很多。不要用fix类型,很多移动GPU是不支持fix的,这些GPU会把fix转成half。&/p&&p&&br&&/p&&img src=&/50/v2-b3ad8ee1794eafafbbf8_b.png& data-rawwidth=&1132& data-rawheight=&602& class=&origin_image zh-lightbox-thumb& width=&1132& data-original=&/50/v2-b3ad8ee1794eafafbbf8_r.png&&&p&&br&&/p&&p&下一个优化是最简单的优化,缩放分辨率。&/p&&p&对于现在的一些移动设备,分辨率已经大到变态了。比如一些1440p,相对于1080p,gpu要多渲染75%的像素,移动GPU对于填充率是非常敏感的,所以比较好的方案是渲染1080p的图像,然后放大到1440p,在移动平台上通常是发现不了的。&/p&&p&&br&&/p&&img src=&/50/v2-04d879a1f5b06a223ccfb8_b.png& data-rawwidth=&744& data-rawheight=&398& class=&origin_image zh-lightbox-thumb& width=&744& data-original=&/50/v2-04d879a1f5b06a223ccfb8_r.png&&&p&&br&&/p&&p&缩放的方案也有硬件实现方案和软件实现方案。&/p&&p&&br&&/p&&p&对于现在的移动设备,MSAA是基本免费的(貌似5.6才支持?)。&/p&&p&&br&&/p&&p&由于fillrate对于移动GPU来说很容易变成性能瓶颈,所以下面要说的帧率杀手就是,overdraw。&/p&&p&&br&&/p&&p&Overdraw主要是由于半透明物体的渲染引起的,因为每渲染一个半透明物体,就要很framebuff里面已存在的pixel做blend。不过很难凭人眼去判断overdraw的程度,所以我们做了一个检查overdraw的工具,这些设计师就可以一键检查自己制作的特效是否合格。这个工具免费share给大家。&/p&&p&&br&&/p&&img src=&/50/v2-e2b6d4ca729d_b.png& data-rawwidth=&1135& data-rawheight=&595& class=&origin_image zh-lightbox-thumb& width=&1135& data-original=&/50/v2-e2b6d4ca729d_r.png&&&p&&br&&/p&&p&上面的都是GPU方面的优化,下面要说一下CPU方面的优化,主要的优化方法我们都尝试了,这里要说的主要是两个方面。&/p&&p&第一,预加载和对象池。首先要说明的一点,io是非常耗时的,所以对于资源最好是采用一些预加载,&/p&&p&包括实例化对象和warm up shader.&/p&&p&关于shader的Warm up,我们的做法是在loading阶段在看不到的地方用所有材质去渲染一个quad。&/p&&p&&br&&/p&&img src=&/50/v2-a5dcfd355e6f_b.png& data-rawwidth=&1128& data-rawheight=&590& class=&origin_image zh-lightbox-thumb& width=&1128& data-original=&/50/v2-a5dcfd355e6f_r.png&&&p&&br&&/p&&p&第二个点是逻辑Update和渲染Update分离。&/p&&p&我们将逻辑Update用更慢的速度Update,每秒20次,帧与帧之间的结果想办法用插值来处理,相比于每秒60次的update 快了200%。&/p&&p&&br&&/p&&img src=&/50/v2-cef38cc348dee89c834a41_b.png& data-rawwidth=&1116& data-rawheight=&592& class=&origin_image zh-lightbox-thumb& width=&1116& data-original=&/50/v2-cef38cc348dee89c834a41_r.png&&&p&&br&&/p&&p&最后聊一下画质分级。&/p&&p&主要是跟据GPU来进行画质分级的,不同画质对应着不同的特性。&/p&&p&&br&&/p&&img src=&/50/v2-e31b7e0a17c6fd1c6fd639_b.png& data-rawwidth=&1116& data-rawheight=&577& class=&origin_image zh-lightbox-thumb& width=&1116& data-original=&/50/v2-e31b7e0a17c6fd1c6fd639_r.png&&&p&&br&&/p&&p&测试方面,我们开发了一个真机上的工具,用来开关这些特性&/p&&p&&br&&/p&&img src=&/50/v2-4c4a4fa3044c15dbfe0d5cf0cc394562_b.png& data-rawwidth=&1124& data-rawheight=&620& class=&origin_image zh-lightbox-thumb& width=&1124& data-original=&/50/v2-4c4a4fa3044c15dbfe0d5cf0cc394562_r.png&&&p&&br&&/p&&p&这样就可以很快地对设备进行分级了。&/p&&p&&br&&/p&&p&&b&关于游戏的特效也专门有一个talk,这里也简单整理一下。&/b&&/p&&p&&br&&/p&&p&从制作的流程上看,分别有下面三个阶段&/p&&p&&br&&/p&&img src=&/50/v2-f430f8d42ace8d9ea771c63_b.png& data-rawwidth=&1114& data-rawheight=&621& class=&origin_image zh-lightbox-thumb& width=&1114& data-original=&/50/v2-f430f8d42ace8d9ea771c63_r.png&&&p&&br&&/p&&p&Art通常是创意阶段,给游戏的风格指明方向后面的两个阶段都是以Art为基础和目标。为了给游戏制作独一无二的特效,肯定是需要TECH作为支撑,最后我们需要就是一条打磨得非常完美的流水线,能够让每个人都能够在流水线上发挥自己的才华。&/p&&p&&br&&/p&&p&首先是Art,在设计方向,我们首先需要表达出gameplay想要表达的意思,让玩家能够理解&/p&&p&&br&&/p&&img src=&/50/v2-cd5d468f1eed68_b.png& data-rawwidth=&1060& data-rawheight=&564& class=&origin_image zh-lightbox-thumb& width=&1060& data-original=&/50/v2-cd5d468f1eed68_r.png&&&p&&br&&/p&&p&&br&&/p&&img src=&/50/v2-7f952af554df88a437019efb2d4e452b_b.png& data-rawwidth=&1143& data-rawheight=&643& class=&origin_image zh-lightbox-thumb& width=&1143& data-original=&/50/v2-7f952af554df88a437019efb2d4e452b_r.png&&&p&&br&&/p&&p&我们想在保持尽量真实的情况下又有一些风格化&/p&&p&&br&&/p&&p&下面是制作贴图的一些建议&/p&&p&&br&&/p&&img src=&/50/v2-9dec9e74f208694fdfc880a7596fd86d_b.png& data-rawwidth=&1149& data-rawheight=&646& class=&origin_image zh-lightbox-thumb& width=&1149& data-original=&/50/v2-9dec9e74f208694fdfc880a7596fd86d_r.png&&&p&&br&&/p&&p&下面是动画制作的一些建议。&/p&&p&&br&&/p&&img src=&/50/v2-dedd4ecbed5b9cba2f22ea_b.png& data-rawwidth=&1143& data-rawheight=&629& class=&origin_image zh-lightbox-thumb& width=&1143& data-original=&/50/v2-dedd4ecbed5b9cba2f22ea_r.png&&&p&&br&&/p&&p&没怎么听懂…&/p&&p&&br&&/p&&p&接下来讲Tech。&/p&&p&通常特效其实是一种折衷,因为设计师总有各种天马行空的想法,但是技术上不一定能实现。实际上技术就是让美术发挥无限的可能性,特别是在移动平台。作为特效设计师,我一直认为在工具和打磨流水线上的投资是值得的。&/p&&p&&br&&/p&&p&我们自定义了作为特效的Shader&/p&&p&&br&&/p&&img src=&/50/v2-54a71da0066abadb1fb33a_b.png& data-rawwidth=&747& data-rawheight=&408& class=&origin_image zh-lightbox-thumb& width=&747& data-original=&/50/v2-54a71da0066abadb1fb33a_r.png&&&p&&br&&/p&&p&上面有很多特性开关。&/p&&p&&br&&/p&&p&自定义颜色的几种方法&/p&&p&&br&&/p&&img src=&/50/v2-c5e97df4cdd335fd042e2cae3a167a62_b.png& data-rawwidth=&1140& data-rawheight=&636& class=&origin_image zh-lightbox-thumb& width=&1140& data-original=&/50/v2-c5e97df4cdd335fd042e2cae3a167a62_r.png&&&p&&br&&/p&&p&&br&&/p&&p&可以在shader里面定义很多Color变量,中间做插值渐变,也可以用LUT,,通常推荐用LUT,这样会更灵活,而且对设计师也更加友好,设计师可以用别的图片编辑软件来编辑这张LUT,或者在Unity做一个托渐变的工具也不错。&/p&&p&一张贴图的通道分布&/p&&p&&br&&/p&&img src=&/50/v2-6a34ad499ea2ec01e5375_b.png& data-rawwidth=&1128& data-rawheight=&642& class=&origin_image zh-lightbox-thumb& width=&1128& data-original=&/50/v2-6a34ad499ea2ec01e5375_r.png&&&p&&br&&/p&&p&减法运算&/p&&p&&br&&/p&&img src=&/50/v2-d005f959bcc3eafb7f1446_b.png& data-rawwidth=&1047& data-rawheight=&638& class=&origin_image zh-lightbox-thumb& width=&1047& data-original=&/50/v2-d005f959bcc3eafb7f1446_r.png&&&p&&br&&/p&&p&用第二张贴图来控制alpha值,获得更复杂的效果。右边的火焰只用了一个dc就实现,他是由一个sprite sheet和一张alpha mask组成。&/p&&p&&br&&/p&&img src=&/50/v2-f30f9e675660dbde_b.png& data-rawwidth=&1025& data-rawheight=&469& class=&origin_image zh-lightbox-thumb& width=&1025& data-original=&/50/v2-f30f9e675660dbde_r.png&&&p&&br&&/p&&p&还有裁剪方式与混合模式上效果的变化&/p&&p&&br&&/p&&img src=&/50/v2-5ce3e2b348fb0d8bca7218_b.png& data-rawwidth=&1149& data-rawheight=&640& class=&origin_image zh-lightbox-thumb& width=&1149& data-original=&/50/v2-5ce3e2b348fb0d8bca7218_r.png&&&p&&br&&/p&&p&在优化方面,主要要优化的有亮点,DC和overdraw,后者更加要注意&/p&&p&&br&&/p&&img src=&/50/v2-43b22c5c74c1b36832adfed_b.png& data-rawwidth=&1142& data-rawheight=&635& class=&origin_image zh-lightbox-thumb& width=&1142& data-original=&/50/v2-43b22c5c74c1b36832adfed_r.png&&&p&&br&&/p&&p&&br&&/p&&p&对于不同的设备做了LOD,像Glow和Bloom这种后期效果我们基本都是用一些fake的方法去模拟。&/p&&p&&br&&/p&&p&最后是Pipeline&/p&&p&首先是概念设计&/p&&p&&br&&/p&&img src=&/50/v2-fb1fce333b32f_b.png& data-rawwidth=&1142& data-rawheight=&644& class=&origin_image zh-lightbox-thumb& width=&1142& data-original=&/50/v2-fb1fce333b32f_r.png&&&p&&br&&/p&&p&&br&&/p&&p&我们的特效基本都是基于Mesh制作,可以说我们的特效,90%都是在Mesh上做一些贴图的动画,由于我们的摄像机是固定的,所以我们很多时候都可以采用一些treat的做法。&/p&&p&&br&&/p&&p&重点讲下Morph target,Wiki里面的解释&/p&&p&&br&&/p&&p&&b&Morph target&br&animation&/b&, &b&per-vertex animation&/b&, &b&shape interpolation&/b&, or &b&blend shapes&/b&&a href=&/?target=https%3A//en.wikipedia.org/wiki/Morph_target_animation%23cite_note-Liu-2006-1& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&[1]&i class=&icon-external&&&/i&&/a& is a method of 3D &a href=&/?target=https%3A//en.wikipedia.org/wiki/3D_computer_graphics& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&computer animation&i class=&icon-external&&&/i&&/a& used together with techniques such as &a href=&/?target=https%3A//en.wikipedia.org/wiki/Skeletal_animation& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&skeletal animation&i class=&icon-external&&&/i&&/a&. In a morph target animation, a &deformed& version&br&of a mesh is stored as a series of &a href=&/?target=https%3A//en.wikipedia.org/wiki/Vertex_%28geometry%29& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&vertex&i class=&icon-external&&&/i&&/a& positions. In&br&each &a href=&/?target=https%3A//en.wikipedia.org/wiki/Key_frame& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&key frame&i class=&icon-external&&&/i&&/a& of an&br&animation, the vertices are then &a href=&/?target=https%3A//en.wikipedia.org/wiki/Interpolation& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&interpolated&i class=&icon-external&&&/i&&/a& between these stored positions.&/p&&p&对于变形的mesh,我们通常都使用Marph target这种方法,它很节省性能,这个冰块生长的动画就只使用了5个Morph target就搞定了。&/p&&p&&br&&/p&&img src=&/50/v2-bccf65d1ec3372cdc3c41_b.png& data-rawwidth=&1163& data-rawheight=&634& class=&origin_image zh-lightbox-thumb& width=&1163& data-original=&/50/v2-bccf65d1ec3372cdc3c41_r.png&&&p&&br&&/p&&p&当实在需要用骨骼的时候,我们通常会限制在10根骨骼以下,每个顶点最多只受两个骨骼影响。&/p&&p&对于贴图,我们是像下面这样分类的。&/p&&p&&br&&/p&&img src=&/50/v2-36cd38170f5aad25f66d_b.png& data-rawwidth=&757& data-rawheight=&421& class=&origin_image zh-lightbox-thumb& width=&757& data-original=&/50/v2-36cd38170f5aad25f66d_r.png&&&p&&br&&/p&&p&只有在用其它方法完成不了的时候,才使用sprite sheet,比如说闪电或者一些很特别烟。&/p&&p&&br&&/p&&p&在绘制贴图的时候,我们出了手绘,用PS去绘制,还尝试了用Substance基于procedual的方式去制作一些贴图,我觉得它简直是上天赐予给特效设计师的礼物!可能在初期需要付出一些学习成本,但当你逐渐掌握的时候,迭代的效率简直Crazy。&/p&&p&&br&&/p&&p&我们还使用了AE,MAX,Phoenix等工具。&/p&&p&&br&&/p&&p&然后是粒子系统&/p&&p&&br&&/p&&img src=&/50/v2-af4cfcd75d131_b.png& data-rawwidth=&1128& data-rawheight=&637& class=&origin_image zh-lightbox-thumb& width=&1128& data-original=&/50/v2-af4cfcd75d131_r.png&&&p&&br&&/p&&p&我们不会把粒子作为一个特效的主体,而只是把它作为一些调料加载特效里面,不过对于一些很依赖随机性的东西,我们只能用粒子系统去做,不过要遵循一定的约束。&/p&&p&&br&&/p&&p&最终在整合的时候,我们使用的是Unity的Animation system.&/p&&p&&br&&/p&&img src=&/50/v2-abaa1fff4d4a_b.png& data-rawwidth=&1172& data-rawheight=&641& class=&origin_image zh-lightbox-thumb& width=&1172& data-original=&/50/v2-abaa1fff4d4a_r.png&&&p&&br&&/p&&p&特效的每一个阶段都是一个Animation clip,通过时间来触发状态的切换,通过Layer来对特效进行分层。我们基本不使用Animationd的transition而是直接跳转,因为很多东西没法Blend。&/p&&p&&br&&/p&&p&最后举了一个特效的例子&/p&&p&&br&&/p&&img src=&/50/v2-c5a47c20bdb9db9731075fd_b.png& data-rawwidth=&740& data-rawheight=&409& class=&origin_image zh-lightbox-thumb& width=&740& data-original=&/50/v2-c5a47c20bdb9db9731075fd_r.png&&&p&&br&&/p&&p&完全没有用到粒子系统.&/p&&p&&br&&/p&&p&&b&Link&/b&&/p&&p&&a href=&/?target=https%3A///watch%3Fv%3DYZWKdw03Gls& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Unite Europe 2017 - The Real-time VFX of Spellsouls&i class=&icon-external&&&/i&&/a& \&/p&&p&&a href=&/?target=https%3A///watch%3Fv%3DvJZcbscZ4-o%26t%3D2979s& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Unite Europe 2017 - The AAA graphics of Spellsouls: achieving 60FPS on mobile&i class=&icon-external&&&/i&&/a&&/p&&p&&/p&&p&&/p&
就在近期的Unite Europe 2017 中,有两个talk比较有意思,分别是The AAA graphics of Spellsouls: achieving 60FPS on mobile 和 The Real-time VFX of Spellsouls,恰好最近在做一些优化方面的工作,就一起学习了一下。 游戏官方介绍说是一个Moba类的卡牌…
以前有个人说的很好。 中国的游戏市场,就像个巧克力喷泉,你说你怎么吃?当然是把头摁在里面,像猪一样吃。&br&&br&&br&做脑残扒皮游戏,投入50%,回报300%,风险50%。&br&换个皮,数值照抄,八成预算扔渠道里,请个明星代言,广告一炸,泔水一样的坑钱系统都有猪一样的玩家争先恐后的跳进去。&br&&br&&br&做高大上游戏,投入1000%,回报50%,风险200%。&br&你花个好几年,投入无数,质量还未必能竞争的过国外老牌大厂。国内高大上玩家又抠得很,一点质量不好,不满意就刷差评。地图小了,喷,剧情不行,喷,数值有问题,喷,bug,喷。喷多了一言不合就滚,忠诚度不到口嫌体正直的泔水游戏玩家的10%。&br&要迎合这个群体,得和那堆资深欧美大厂刚正面不说,还得被玩家骑着跟孙子一样。&br&万一你的创意和比你强的欧美大厂撞了车,或者泄了,人家现成游戏一个dlc就拿质量压死你,你这笔生意就哭死。&br&&br&&br&你是风投,你投谁?&br&没钱,发不起高工资,没有牛逼团队,怎么做高大上游戏?&br&&br&你们只不过是小众而已。
以前有个人说的很好。 中国的游戏市场,就像个巧克力喷泉,你说你怎么吃?当然是把头摁在里面,像猪一样吃。 做脑残扒皮游戏,投入50%,回报300%,风险50%。 换个皮,数值照抄,八成预算扔渠道里,请个明星代言,广告一炸,泔水一样的坑钱系统都有猪一样的…
&img src=&/50/fe73fed07bab398ba01ba7_b.jpg& data-rawwidth=&1440& data-rawheight=&900& class=&origin_image zh-lightbox-thumb& width=&1440& data-original=&/50/fe73fed07bab398ba01ba7_r.jpg&&中国游戏幕后史三 &br&暴雪其实不想跟九城分手 魔兽世界幕后故事&br&文/BBKinG&p&  说起中国游戏幕后史,《魔兽世界》在中国的运营案例堪称经典中的经典。&/p&&p&  2004年,由于之前《魔剑》和《EQ》等大型游戏在中国的运营失败,导致美国暴雪娱乐当时正在封测的同类型网游《魔兽世界》并不被中国游戏业内看好,而这款游戏在之后的几年里,却在世界范围建立起了一个超级王国,不但成为业内标杆,还带动了一系列前所未有的游戏周边产业和文化的兴起,同时也让签下国内代理的第九城市集团名利双收,跻身中国一线游戏公司。&/p&&p&  而2009年,暴雪和九城的“离婚”案,更是沸沸扬扬,还一度牵扯到文化部和新闻出版署的高层斗法。期间双方的各种明争暗斗,你死我活,不亚于谍战血火,甚至衍生出一个地下暗战的代言人体系——舅舅党。&br&&/p&&p&  如今斗转星移,到了2014年,暴雪与网易已步入感情稳定期,新闻出版署也与广电在2013年合并,变成国家新闻出版广播电影电视总局,《魔兽世界》也即将发布6.0版本,一切仿佛都归于平静。&/p&&p&  可是,历史是绕不开,也不容忽视的。&/p&&p&  你知道美国暴雪当初并不想跟九城“离婚”吗?&/p&&p&  甚至在暴雪2008年最后一次美国总部的专项讨论会上,大家依然得出不要分家的结论。&/p&&p&  那为什么最后还是分了?谁压下最后一根稻草?是谁把对方逼上了绝路?是九城的策略失误?还是暴雪的冲冠一怒?&br&&/p&&p&  让我们从头开始&/p&&br&&p&  2004年4月,第九城市集团与维旺迪(Vivendi Universal Game)旗下的暴雪娱乐(Blizzard Entertainment)签署中国战略合作协议,第九城市取得《魔兽世界》(World of Warcraft(TM))在中国大陆地区的独家代理运营权。&/p&&p&  当时这个项目组的负责人叫孙涛,九城的CTO,据说他是帮九城抢下WOW的大功臣,也是第一任项目负责人,因为人长的非常帅,被游戏圈戏称为游戏行业最帅的男人(后来他离开九城创立了冰动游戏公司,几年后卖掉,现在平安中国工作)。&/p&&p&  另外两个重要人物是产品总监黄凌冬和技术总监江焕新。&/p&&p&  黄凌冬是九城虚拟社区的第一个成员,是公司元老了(后升任九城的产品副总裁,现腾讯上海互娱合作产品部副总经理)。他亲自筹建了《魔兽世界》项目组,早期团队里的很多人都是由他亲自面试招入的。&/p&&p&  比如,负责对外沟通的项目经理 马刚(现育碧中国高级市场总监),媒介经理刘峰(昵称Aya,现杭州乐港副总裁),以及创建&艾泽拉斯国家地理& 网站的Ediart田健,他负责汉化(2011年田健创建上海游点信息科技有限公司,做手游研发),还有贯穿九城和暴雪中国历史的WOW项目组元老吴健,当时他负责策划和运营(之后加入暴雪中国负责魔兽世界和其它暴雪产品的运营,后受邀出任空中网COO)等等。&/p&&br&&p&  技术总监江焕新,出身惠普,在魔兽世界项目启动初始加入九城,后来出任九城的副总裁,离开过九城一段时间,最近似乎又回到九城帮助公司开拓北美疆域。&/p&&br&&p&  九城当时是没有市场部的,只有一个大产品部。网站早期是外包出去的,接外包的团队叫01media,现在也是赫赫有名的设计公司了,后来专门招了一个人负责网站,这个人叫周豪ZAX(现希玛公司CEO,做电子竞技,WE俱乐部和StarsWar就是该公司旗下的品牌),还有一个网站美工叫胡依林,现在也成为知名的独立设计师了。&/p&&p&  最初的WOW团队只有十来个人(请原谅我收集到的信息有限,有些人可能会有错漏,我会不断完善的),一直到2004年年底,依然还是这些人。&/p&&br&&p&  《魔兽世界》项目组成立后,对游戏的汉化和中文配音便成了首要工作。&/p&&p&  最初的WOW版本有100多万字翻译量,当时是找了六七个兼职的翻译人员准备大干一场。九城为了方便大家工作,专门把翻译组从中信泰富移到了旁边比较清静的凯迪克大厦,还腾出一个会议室给他们加班加点的翻译,翻译好的内容,刘吉磊(后加入腾讯做手机接入)做第一轮校对,吴健做第二轮校对,田健做第三轮校对和润色,其中最为关键的是田健的润色,他凭借自己对欧美游戏文化的深刻理解,将生涩的翻译变成了优美连贯的文字,他的工作后来也得到了广大玩家的认可。&/p&&p&  中文配音找了配音出身的著名上海译制片导演 倪康 做配音导演,据悉,他同时也是后来英雄联盟的中文配音导演。&/p&&p&  倪康老师是个非常认真的人,他挑选了大江南北的顶级人员来上海配音,其中,为了给游戏里的大BOSS 奈法利安 和 拉格纳罗斯 配出霸气十足的语音,特意找了一个蒙古配音演员 龚格尔,让他连夜坐火车来上海。&/p&&p&  第二天一早,龚格尔直接进棚就开始录,但是折腾了几个小时后,大家发现:这小伙完全没感觉。后来到中午了,项目组商量了下,打算请他吃个饭就算谢绝了。&/p&&p&  可是,谁知道吃完饭后,蒙古人的精气神突然全有了,霸气的感觉也全来了,一口气2个小时就配完了所有大BOSS的音。&/p&&p&  于是,大家后来在打副本被灭的死去活来时,听到的那些欠打的嘲讽声,十有八九是龚格尔吃饱了后说的。&br&&/p&&br&&p&  筹备内测、准备上线、政府审批,以及和可口可乐的合作,便成了2005年公测开始前的几个重点工作。&/p&&p&  此时的外界依然不看好《魔兽世界》,而九城内部却越来越有信心。&/p&&p&  内测刚开始发号的时候,几天里就有30多万的暴雪粉丝来申请,而且当时的申请条件很苛刻,需要填写大量的用户信息和资料,但是WOW项目的人发现,玩家都填的相当仔细。&/p&&p&  《魔兽世界》的网络社区里也开始有了很多相当不错的内容,比如,可能现在很多老玩家还记得的一个视频叫《康熙也想玩魔兽》,做的非常不错,在2005年刚放到网上不久,就有几十万的点播量,九城的工作人员还专门去找到了视频制作者,送了几个CDKEY作为感谢。&/p&&p&  日,第一个魔兽世界日,九城在上海卢湾体育馆办了一个玩家见面会,在这个见面会上将宣布《魔兽世界》的公测时间。&/p&&p&  那天下着非常大的雨,但是却来了几千人,不但里边坐满了人,外面还挤了非常多的玩家在雨里等待,这给了WOW项目组极大的信心和鼓励,据说那天九城老板朱骏也来了,他进场看了一眼,笑了笑就回到了后台,已然成竹在胸。&/p&&p&  当天宣布公测时间为4月29日,但是实际公测时间是4月26日。&/p&&p&  内测结束的那天晚上,九城的工作人员办了一个叫 “恶魔入侵 世界末日”的活动,由运营团队控制大怪物,到各个主城里与玩家互动,跳舞,一起庆祝,暴雪对GM控制NPC的行为有严格的限定,但是那天晚上除外,所以那场活动恐怕是十分罕见的,如果你有幸参与了那天晚上的互动,那会是非常美好和值得纪念的回忆。&/p&&p&  这里要说个小插曲,公测前运营商一般会制作发放WOW的安装盘,而用来制作这个安装盘的母盘,当时是暴雪的绝密文件,因为这是最完整的游戏文件,里边整合了最新翻译,还有所有的游戏内容。&/p&&p&  暴雪对快递公司不放心,于是专门派了一个员工Stan Wang,亲自从美国送过来,九城这边的项目组兴奋的一夜没睡,就为了等这张盘,而当他们拿到这张盘,迫不及待的插入电脑后,却发现这张母盘竟然坏了,真是让人啼笑皆非。&/p&&p&  公测了,终于公测了。&/p&&p&  封顶45级,而玩家的热情超出想象,所有的服务器都在排队,那个时候美国暴雪在欧美地区曾出了一个市场文案叫:A world awaits(一个世界在等待)。结果被中国玩家戏称为:一个世界在排队。&/p&&p&  《魔兽世界》的公测排队对之后的游戏也产生了深远的影响,这变成了一种文化,有业内人士说,后来有些游戏甚至不用排队也要制造出排队的效果。&/p&&p&  强势的暴雪&/p&&p&  暴雪对九城在《魔兽世界》运营上做了很多要求,有些要求是蛮高的,比如关于服务器的选择,在暴雪的要求下,九城向惠普购买了当时最先进的服务器,而整个服务器集群的计算能力据说是远超银河计算机的。&/p&&p&  暴雪的出发点非常简单:为了玩家有最好的游戏体验。而有时候这种强势的做法,会让运营商十分难受的,这也为日后两家公司的裂痕埋下了隐患。&/p&&p&  很快,公测的人数就突破了60万。&/p&&p&  整个项目组的人都非常高兴,因为除了成就感以外,大家都很期待老板朱骏兑现他承诺的奖金。&/p&&p&  那是在2005年初,朱老板曾对大家说,如果这个游戏人数超过50万,就发50万美元的奖金。&/p&&br&&p&  而很多人直到最后走了,都没看到这笔钱,这也为后来很多项目成员的离开埋下了伏笔。&/p&&p&  2005年,野心勃勃的九城,开始布局他新的战略。陆续从国外拿回来了大量新的游戏,比如,卓越之剑、奇迹世界、地狱之门、激战等等。&/p&&p&  这个战略一方面是为了压制国内潜在的竞争对手,先下手为强,把好游戏都拿下来。另一方面也是因为九城不想一辈子做暴雪的傀儡。&/p&&p&  从战略的层面说,这个方向是对,毕竟盛大的案例摆在面前,代理公司和游戏研发公司的矛盾只会增长,必须要有所准备。但是不同于盛大的是,他们的对手可不是什么韩国公司,而是老牌巨无霸级游戏航母 美国暴雪娱乐。&/p&&p&  2005年年底,新矛盾说来就来了&/p&&p&  此时,国外已经要上新资料片《燃烧的远征》了,而这个资料片里加了很多新的技术,美国方面认为,这需要更好的服务器支持,才能确保提供给玩家更好的游戏体验,于是,他们提出,要求九城方面更新服务器。&/p&&p&  注意,此时,九城刚花大价钱买的那些远超银河的服务器,可还没用多久呢!&/p&&p&  所以,九城犹豫了。&/p&&p&  裂缝就这样又大了一些&/p&&p&  于是,暴雪开始推进亲自进入中国市场的战略,于2005年着手执行建立暴雪中国分公司的计划。&/p&&p&  可以看到,双方都在博弈,其实这没有什么对错之分,都是为了活下去,这就是丛林法则。&/p&&p&  2006年,暴雪加速在中国的扩张。&/p&&p&  而九城此时走了一步很诡异的棋,他们开始把WOW项目组的核心人员纷纷调离这个项目,让他们去负责之前拿回来的各种新游戏。而把九城自己做研发的人员调过来做WOW的运营。&/p&&p&  我个人猜测,这步棋可能有多个目的:一个是让这些已经有成功运营经验的成员去带带新游戏。一个是通过实战数据,培养自己的研发人员。还有一个,恐怕是防止WOW项目组亲暴雪派的势力过大。&/p&&p&  这步诡异的棋是谁的主意?我不知道,我也不知道我的猜测是否准确,但是我打赌做决定的人一定没想到这步棋会像七伤拳一样,伤人也伤己。&/p&&p&  首先是项目组负责人亲暴雪派的孙涛直接辞职,去建立了自己的公司,还带走了一批人。之后九城换上的新COO是Nancy Zhou周宁,相对孙涛,她对待暴雪要强势许多。(Nancy现任育碧中国的总经理)&/p&&p&  九城运营方面的负责人吴健则因为不愿意去做别的项目,被暴雪顺势挖去做了暴雪中国的第四号员工。&/p&&p&  朱骏为此大发雷霆,准备给吴健和暴雪同时发律师函,还在公司内部大会上布下了严旨,不许任何人与吴健有任何形式的接触,也不许暴雪让吴健插手任何与WOW相关的所有工作。&/p&&p&  这个事情闹的很大,逼得后来九城和暴雪还签订了一个协议,用来禁止相互间挖角,才算是慢慢平息。&/p&&p&  表面上看只是一个员工的跳槽,实际上,背后是两个公司战略级的碰撞。&/p&&p&  暴雪此时的总经理叫Michael Fong,他是一个加拿大籍香港人,他有一个重要的工作是筹建暴雪中国分公司。而负责调研的就是刚去的吴健。&/p&&p&  之后的几年,与《魔兽世界》跟中国玩家的关系越来越火热正好相反,九城和暴雪的关系越来越冷漠,一方面是暴雪希望更多的介入运营,了解细节,另一方面是九城不更新服务器,而且把数据也藏着掖着不告诉暴雪。&/p&&p&  博弈越来越激烈,矛盾也越来越大&/p&&p&  虽然更换代理商这个念头早就在暴雪内部出现过无数次,但是暴雪此时依然不想换,原因很简单,暴雪觉得任何决策都不能伤到玩家。熟悉暴雪的人可能知道,这是暴雪公司的核心文化,也是很多决策制定时的根本出发点。&/p&&p&  甚至在日,EA以1.67亿美金入股九城15%股权时,作为EA主要竞争对手的暴雪都还是怒而不发。&/p&&p&  直到2008年,忍无可忍的暴雪才开始与其它厂商进行接触,研究接盘的可行性。&/p&&p&  而这期间,九城的高层依然在用强硬的态度处理与暴雪的关系,这不但没有缓和越发紧张的局势,还最终激怒了暴雪。&/p&&p&  这里我要声明一点,九城的战略是控制并平衡自己与暴雪谈判的位置,谁都想把话语权控制在自己手里。所以,他们走多游戏代理,尝试摆脱暴雪的控制,推自主研发,甚至拉EA入伙,都是为了让自己对暴雪的谈判筹码更多一些,从战略层面上说,这个大方向是没错的。&/p&&p&  但是,可悲的是,卡住了九城脖子的是时代的瓶颈,别说那个时候的中国游戏自主研发了,即使到这么多年后的现在,世界上有几个游戏能超越《魔兽世界》的?&/p&&br&&p&  就像小国家想独立,你没核武器,没反制能力,资源和经济都没有绝对优势,最大的收入又要依靠人家,那所谓平起平坐,也就只是个口号罢了。&/p&&p&  邓小平说,落后就要挨打。&/p&&p&  如今只是被打的更文明了一点而已。&/p&&p&  而当时的九城还是一副没弄清楚状况的样子,依然强硬。&/p&&p&  就在暴雪最后一次会议依然决定不“离婚”的那天夜里,动视暴雪的老大Bobby Kotick突然下达了与九城的分家命令。&/p&&p&  或许是一个邮件?一个报表?一个句话?这已经都不重要了,强势的外企遭遇强硬的本地代理,这个性格不合的组合必然导致“离婚”。&/p&&p&  最后一根稻草缓缓的压下,却让整个局势瞬间崩塌。&/p&&p&  之后的事情,我简单说下,暴雪在与众多厂商接触后,网易和腾讯走到了最后,但暴雪美国方面觉得网易和丁磊对玩家的态度更加契合暴雪的核心文化,于是,选择了网易。  &br&&/p&&p&  日,网易《魔兽世界》重开内测。&/p&&p&  之后的故事,我们过些年再写出来吧。&/p&&p&  中国游戏幕后史&/p&&br&&br&&p&『中国电竞幕后史』实体书29.9元包邮:&br&&a href=&/?target=https%3A///item.htm%3Fspm%3Da1z10.1-c.w9584.1.pWkTys%26id%3D%26scene%3Dtaobao_shop& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&中国电竞幕后史 电竞圈幕后传奇故事 淘宝店&i class=&icon-external&&&/i&&/a&&/p&
中国游戏幕后史三 暴雪其实不想跟九城分手 魔兽世界幕后故事 文/BBKinG 说起中国游戏幕后史,《魔兽世界》在中国的运营案例堪称经典中的经典。 2004年,由于之前《魔剑》和《EQ》等大型游戏在中国的运营失败,导致美国暴雪娱乐当时正在封测的同类型网游《魔…
&p&简书地址:&a href=&/?target=http%3A///p/abfab0e6f2fc& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Unity手游开发札记——2.5D大世界动态加载实战&i class=&icon-external&&&/i&&/a&&/p&&h2&0. 前言&/h2&&p&项目第一次对外技术测试落下帷幕,终于有时间来填&b&大世界动态加载&/b&这样一个大坑。
从去年11月份开始,在需求改变、制作方案更改等各种影响下,断断续续地制作维护这个功能,估算下来花费在它上面的有效时间也得有1个月左右。目前我们游戏大世界的制作进入铺量阶段,已经制作好的功能也经过了第一次技术测试的验证,静下心来写这篇《Unity手游开发札记——2.5D大世界动态加载实战》。&/p&&blockquote&需要说明的是:一方面任何技术方案都有其&b&适用范围&/b&,相对应的也就是它们有着自身的&b&局限性&/b&,因此这篇文章肯定不是一颗万能的“银弹”;另外一方面,在实际工程中,实现一段代码、一个技术功能点往往是最为简单的那步,设计适合团队工作的工作流程,让功能可以快速高效的产出结果,并且便于维护,才是工作量更大的部分。因此,正在阅读这篇文章的你,不必抱着多大的希翼可以通过学习它实现你们自己项目的大世界动态加载架构,它是一篇“实战记录”——意味着这里的经验经历过一个真实项目的洗礼,也意味着它们可能更适用于我们项目而已。&/blockquote&&h2&1. 需求分析和技术调研&/h2&&blockquote&一切都在变化,没有东西会消失。——奥维德:&a href=&/?target=https%3A///subject/2364765/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&《变形记》&i class=&icon-external&&&/i&&/a&&/blockquote&&h2&1.1 需求分析&/h2&&p&“需求一直都在变化,没有需求会消失。。。”回头来看我们游戏整个大世界的制作方案的确定过程,我要把改编自奥维德名言的这句话送给我们团队的策划和美术同学,这里饱含了一个程序的吐(fen)槽(hen)。我们项目的需求变更主要体现在大世界制作方案的改变上,从2016年11月份开始,经历过传统3D制作方案、基于六边形的风格化方案、比例缩小版写实风格,最后到基于Terrain的沙盘风格。每次变更都意味着美术制作流程的变化,随之而来的就是程序需要开发的工具集调整。&/p&&p&回到项目立项初期讨论的时候,当时我们就确定了大世界的方向。其实从程序的角度能够预估这其中的技术难度,毕竟团队中从策划到程序再到美术谁都没做过完整的大世界项目。带着初创团队初生牛犊不怕虎的劲,再加上策划同学拍着胸脯说“实在不行我们就用2D地图也能接受”的允诺,就往这个方向来努力。
第一个版本美术预研的大世界效果出来之后,纠结在视角使用3D还是2.5D——2.5D的大世界制作成本和技术难度会比较低,但是从当时的设计来看,3D的体验会更好,而且看得越远越好……因此最初的技术预研方向也是在往自由3D视角的目标来做。&/p&&h2&1.2 Unity插件调研&/h2&&p&从程序角度,无论什么视角,针对Unity引擎做初步的技术调研是最基础的工作。这时候有那么一点怀念之前自己掌握引擎代码的日子,即使没有引擎组的支持,自己在引擎C++底层来做是方法明确而且效率更高的方式。好在Unity也有自身的优势——Asset Store。搜索加询问,最后找到看着还比较靠谱的两个插件—— &a href=&/?target=https%3A//www./en/%23%21/content/15356& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&SECTR COMPLETE&i class=&icon-external&&&/i&&/a& 和 &a href=&/?target=https%3A//www./cn/%23%21/content/36486& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&World Streamer&i class=&icon-external&&&/i&&/a&。
&b&World Streamer&/b&这个我没有非常仔细去看实现细节,整体的思路是按照位置拆分成按照Scene组织的格子(Grid),然后根据距离做逐步加载,因为要区分地表、特物体和细节物体等不同粒度,提供了分层拆分的功能。提供一篇找到的博客供需要的同学参考:&a href=&/?target=http%3A//blog.csdn.net/wanghaodiablo/article/details/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&《Unity 场景分页插件 World Streamer 支持无限大地图的解决方案》&i class=&icon-external&&&/i&&/a&。
&/p&&img src=&/v2-8dccfa8ae278c9d39a1a78d121e99130_b.png& data-rawwidth=&1068& data-rawheight=&1067& class=&origin_image zh-lightbox-thumb& width=&1068& data-original=&/v2-8dccfa8ae278c9d39a1a78d121e99130_r.png&&&p&&br&&/p&&p&WorldStreamer拆分后的场景列表&/p&&p&&br&&/p&&p&&b&SECTR COMPLETE&/b&这个插件是我购买并学习了一段时间的一个插件,原因之一是这个插件是被Unity官方推荐过的,而且FireWatch游戏就是用的这个插件,可以参考GDC的演讲&a href=&/?target=http%3A///play/1023191/Making-the-World-of& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Making the World of Firewatch&i class=&icon-external&&&/i&&/a&。这个COMPLETE是一个售价100美元的插件集合,它包括CORE、STREAM、VIS和AUDIO等几个部分。VIS做动态的遮挡剔除,动态的大世界主要是STREAM部分。
SECTR STREAM通过自动或者手动创建Sector的方式,用包围盒来决定场景中的哪些物体被放置到哪一个Sector中,然后将这些Sector导出为名称对于的分块场景,加载的时候在角色身上添加一个Loader,通过Loader与留在场景中的Sector碰撞盒进行交互来判断哪些Sector对应的场景组件需要被加载。Loader的类型不同加载方式也不同,比如包括Neighbor Loader、Region Loader、Trigger Loader甚至DIY Loader等。
&/p&&img src=&/v2-3f9c317c3a54cdf5e5c78fe1c3da2770_b.png& data-rawwidth=&1447& data-rawheight=&817& class=&origin_image zh-lightbox-thumb& width=&1447& data-original=&/v2-3f9c317c3a54cdf5e5c78fe1c3da2770_r.png&&&p&&br&&/p&&p&SECTR STREAM的拆分界面&/p&&p&由于最终我们并没有使用这两个插件,因此在此不进行更详细的描述,有兴趣的朋友可以自己买来玩一下。&/p&&h2&1.3 UWA技术分享&/h2&&p&在2016年11月份的时候,UWA组织了一场在上海的分享,其中有一个就是张强的《大规模场景的资源拆分和动态加载》,很兴奋地去听了一下,主要是2.5D视角下基于Terrian的实现方案,因为当时我们的需求方案还是倾向于3D自由视角,所以听的时候感觉帮助没有那么大。当时在回来之后的博客笔记里说——&/p&&blockquote&“我个人觉得这部分的一个问题是整个工程是基于一个Demo性质的实现,而非正式的项目,因为时间关系没有在后面进行深入的交流,因此也不清楚目前的实现是否在正式的项目中应用了。”&/blockquote&&p&在现在来看,其实张强的分享内容中有很多是我在后面设计和实现的过程中没有去考虑的部分,比如资源打包策略的制定等,这些问题都是在实际项目中需要去注意的内容。而当时我想了解但这个分享不包含的内容是大世界的制作和维护流程的部分,鉴于主题是《大规模场景的资源拆分和动态加载》,其实针对这一主题已经很有实用性了。&b&这里也借这篇文章的机会,给UWA的张强同学做一个小小的道歉,当时的评价过于草率,非常抱歉。&/b&
如果想要了解这次分享的同学可以去UWA的官网搜索,这里给一个我自己备份的PPT&a href=&/?target=http%3A//o9hm1ti4o./%25E5%25A4%25A7%25E8%25A7%%25A8%25A1%25E5%259C%25BA%25E6%2599%25AF%25E7%259A%%25B5%%25BA%%258B%%E5%E5%258A%25A8%25E6%E5%258A%25A0%25E8%25BD%25BD-%25E4%25B8%258A%25E6%25B5%25B.pdf& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&下载地址&i class=&icon-external&&&/i&&/a&。&/p&&h2&1.4 调研结果&/h2&&p&通过对这两个插件和UWA分享沙龙的学习,基本确定了在Unity中制作动态大世界的基本思路:美术制作完整场景 -& 自动/手动拆分场景 -& 运行时根据规则自动加载角色周围的部分。
&/p&&p&&br&&/p&&img src=&/v2-dd3ae6f4c355ea0ea5f081d411bc8a26_b.png& data-rawwidth=&1343& data-rawheight=&255& class=&origin_image zh-lightbox-thumb& width=&1343& data-original=&/v2-dd3ae6f4c355ea0ea5f081d411bc8a26_r.png&&&p&&br&&/p&&p&制作动态大世界的基本思路&/p&&p&与此同时,也了解到几个需要去注意的技术点:&/p&&ol&&li&光照贴图,整个大世界使用一张Lightmap显然不合适,SECTR STREM是支持自动拆分的,也有一些插件支持光照贴图的拆分,这个貌似不用太担心;&/li&&li&寻路信息,Unity 5.6之前的版本是不支持动态的Nav Mesh的,只能跟随场景加载/卸载。既然没有办法更改,暂时看起来也没有担心的必要;&/li&&li&光照探针,这个也是不支持动态加载的,但是初步看起来手游项目用这个的可能性不太大,暂时不去担心。&/li&&/ol&&p&&br&&/p&&h2&2. Demo实现&/h2&&p&在进行一系列的技术调研之后,也迎来了一大波的需求调整。通过美术工作量、项目时间限制和技术难度评估的综合考量之后,我们终于妥协为了2.5D视角,但是镜头高度会相对普通的2.5D要高不少。2.5D视角的确定让整个功能实现的技术难度降低了很大一部分,也确定了自己来开发动态加载核心功能的技术方向。经历一些纠结和试验之后,最终选择最为通用的&b&基于九宫格的动态加载方案&/b&,主要原因包括:&/p&&ol&&li&现成的插件虽然功能强大但是有各种问题,比如SECTR STREM需要对每一个Sector创建一个GameObject和对应的碰撞盒,在手游上担心有比较大的消耗;拆分过程虽然很灵活但是需要美术进行较多的操作,当拆分完毕之后,如果想再进行编辑,需要再做一遍完全的拆分过程才行;&/li&&li&九宫格的方案技术难度比较低,需要定制的内容也相对较少,可以按照我们自己的美术制作流程来进行定制;&/li&&li&最后,自己造轮子不也是程序员的乐趣之一,不是么?(手动微笑)&/li&&/ol&&p&九宫格的方案其实很简单也很好理解,将完整的大世界按照固定大小拆分成小的Chunk,然后运行时根据角色位置和约定好的Chunk尺寸判断角色所在的Chunk和周围八块的索引,加载对应的Chunk文件即可。当角色移动的时候,判断是否需要加载新的Chunk和卸载老的Chunk文件。在这个阶段美术还在做效果预研,所以自己先制作一个Demo来模拟整个功能。首先还是先设想了一下整个大世界的制作流程,大致如下:&/p&&ol&&li&美术完成整个大世界场景的制作;&/li&&li&使用自动拆分工具,根据设置好的分块大小,将场景中的每一个物体根据位置坐标拆分到对应的Chunk中;&/li&&li&将Chunk自动保存成规定路径下对应名称的场景文件(.scene),删除拆分过的Chunk文件剩下的作为BaseWorld.scene文件;&/li&&li&运行时首先加载BaseWorld,然后在角色身上绑定一个DynamicLoader,根据角色位置自动按照Additive的方式加载周围九块Chunk对应的场景。&/li&&/ol&&p&在这个工作流程下,美术制作的永远都是完整的大世界场景,约定好分块大小,只需要使用自动拆分工具就可以更新拆分后的场景文件。这里关于寻路信息和光照贴图信息的处理如下:&/p&&ol&&li&美术烘焙场景的单位为一个单独Chunk的场景文件,即在确定本块场景不修改之后再进行烘焙工作,如果还需要修改,就需要重新烘焙,烘焙过的场景加入到自动导出工具的覆盖黑名单中,完整重新导出时不再进行覆盖;&/li&&li&Navmesh和一些跨Chunk的全局物体(比如大面积的水域)暂时放置在BaseWorld中,运行时BaseWorld.scene为active的场景;&/li&&li&所有的光照、雾效果等信息一律放置在BaseWorld.scene中。&/li&&/ol&&p&&br&&/p&&p&按照这个工作流程,需要制作的工具包括场景自动拆分功能和自动加载组件两个部分。&/p&&h2&2.1 场景自动拆分实现&/h2&&p&场景自动拆分的功能比较简单,最终也仅仅实现了如下截图中的几个功能,最为核心的也就是“自动拆分场景”和“导出拆分后的物体”两个了。
&/p&&p&&br&&/p&&img src=&/v2-0fd8d18ace807e5884be_b.png& data-rawwidth=&395& data-rawheight=&318& class=&content_image& width=&395&&&p&自动拆分工具界面截图&/p&&p&代码也很简单,首先遍历所有需要处理的GameObject,我们只需要处理&b&包含MeshRender组件和Terrain组件的物体&/b&即可。这里给美术添加了一个限制,有MeshRender的GameObject的孩子节点不再进行拆分,因为为了保持原有的层次结构,如果一个GameObject的孩子被分配到了不同Chunk,那个这个作为父节点的GameObject会被完全拷贝到多个Chunk中。那么,如果父节点包含了比如MeshRender的组件,就会导致较多的渲染消耗,也并不合理,因此只要包含MeshRender这样的组件就会连着其孩子节点完整地放置到一个Chunk中。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&// 首先使用遍历出所有需要处理的GameObject
GameObject[] roots = EditorSceneManager.GetActiveScene().GetRootGameObjects();
List&GameObject& objsToProcess = new List&GameObject&();
foreach (GameObject root in roots)
TraverseHierarchy(root.transform, new ActionTransform((Transform obj) =&
//如果有MeshRender或者Terrain组件,并且是静态物体,则认为是一个要处理的叶子节点,不再处理其孩子节点了
GameObject tempObj = obj.gameO
if (tempObj.activeSelf == false)
if ((tempObj.GetComponent&MeshRenderer&() || tempObj.GetComponent&Terrain&()) && (!onlyStatic || (onlyStatic && tempObj.isStatic)))
objsToProcess.Add(tempObj);
}), false);
&/code&&/pre&&/div&&p&找到所有需要拆分的物体之后,直接按照位置进行拆分即可。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&// 逐个处理可能需要移动的GameObject
for (int i = 0; i & objsToProcess.C ++i)
EditorUtility.DisplayProgressBar(progressTitle, &Processing & + objsToProcess[i].name, (float)i / (float)objsToProcess.Count);
ClassifyGameObject(objsToProcess[i], width, height);
/// &summary&
/// 对一个GameObject按照位置进行分类,放置到对应的根节点下面。
/// &/summary&
/// &param name=&obj&&&/param&
static void ClassifyGameObject(GameObject obj, float width, float height)
Vector3 pos = obj.transform.
// chunk的索引
int targetChunkX = (int)(pos.x / width) + 1;
int targetChunkZ = (int)(pos.z / height) + 1;
string chunkName = ChunkRootNamePrefix + string.Format(&{0}_{1}&, targetChunkX, targetChunkZ);
GameObject chunkRoot = GameObject.Find(chunkName) ;
if (chunkRoot == null)
chunkRoot = new GameObject(chunkName);
//复制层次关系到Chunk的节点下面
GameObject tempObj =
List&GameObject& objs2Copy = new List&GameObject&();
while(tempObj.transform.parent)
objs2Copy.Add(tempObj.transform.parent.gameObject);
tempObj = tempObj.transform.parent.gameO
tempObj = chunkR
for (int i = objs2Copy.Count - 1; i & -1; --i)
GameObject targetObj = objs2Copy[i];
// 对于符合Chunk命名规则的父节点不进行拷贝过程。
if (targetObj.name.StartsWith(ChunkRootNamePrefix))
Transform parent = tempObj.transform.FindChild(targetObj.name);
if (parent == null)
parent = new GameObject(targetObj.name).
CopyComponents(targetObj, parent.gameObject);
parent.parent = tempObj.
targetObj = parent.gameO
tempObj = parent.gameO
Transform tempParent = obj.transform.
obj.transform.parent = tempObj.
// 移动完毕之后发现父节点没有孩子节点的情况下,向上遍历将无用节点删除。
while (tempParent != null && tempParent.childCount == 0)
Transform temp = tempParent.
EngineUtils.Destroy(tempParent.gameObject);
tempParent =
&/code&&/pre&&/div&&p&拆分完毕之后的场景如下图所示。这一步需要美术进行一个大致的检查,保证拆分结果的正确性。
&/p&&img src=&/v2-dd50d073bc5c05e94a0f6_b.png& data-rawwidth=&505& data-rawheight=&746& class=&origin_image zh-lightbox-thumb& width=&505& data-original=&/v2-dd50d073bc5c05e94a0f6_r.png&&&p&经过拆分的场景结构&/p&&p&然后将拆分后的组件保存到对应的Scene文件中,这里为了避免遗漏拷贝场景参数,采用了比较trick的方式——生成每一个Chunk文件时,将完整场景文件进行一次拷贝,然后删除掉不需要的GameObject,即比如要生成_worldchunk6_8.scene,将整个场景文件完整拷贝,然后删除掉除了_worldchunk6_8这个GameObject之外的所有物件。这样就做到了所有场景参数的一致性,但是代价是花费的时间稍微久一点。
这样做的意义在于,比如Ambient Source相关的参数会影响烘焙结果,如果稍微有些不同,会导致最终烘焙出来的Chunk之间存在明显的接缝问题。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&static void ExportChunksToScenes()
EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo();
GameObject[] roots = EditorSceneManager.GetActiveScene().GetRootGameObjects();
List&string& rootsNamesToExport = new List&string&();
foreach (GameObject root in roots)
if (root.name.StartsWith(ChunkRootNamePrefix))
rootsNamesToExport.Add(root.name);
if (rootsNamesToExport.Count == 0)
EditorUtility.DisplayDialog(&Export Error&, &不存在符合导出要求的分组,请先使用自动拆分功能!&, &确定&);
if (!EditorUtility.DisplayDialog(&Info&, &导出场景将会删除之前已经导出过的场景Chunk目录,是否继续?&, &继续&, &取消&))
string sceneD
string sceneN
string exportDir = MakeExportFolder(&Chunks&, true, out sceneDir, out sceneName);
if (string.IsNullOrEmpty(exportDir))
EditorUtility.DisplayDialog(&Export Error&, &Could not create Chunks folder. Aborting Export.&, &Ok&);
string progressTitle = &导出拆分后的场景&;
EditorUtility.DisplayProgressBar(progressTitle, &Preparing&, 0);
string originalScenePath = CurrentScene();
int counter = -1;
foreach (string rootName in rootsNamesToExport)
counter += 1;
EditorUtility.DisplayProgressBar(progressTitle, &Processing & + rootName, (float)counter / (float)rootsNamesToExport.Count);
string chunkScenePath = exportDir + &/& + rootName + &.unity&;
AssetDatabase.CopyAsset(originalScenePath, chunkScenePath);
EditorSceneManager.OpenScene(chunkScenePath, OpenSceneMode.Single);
GameObject[] tempRoots = EditorSceneManager.GetActiveScene().GetRootGameObjects();
foreach (GameObject r in tempRoots)
if (r.name != rootName)
EngineUtils.Destroy(r);
EditorSceneManager.SaveScene(EditorSceneManager.GetActiveScene());
AssetDatabase.Refresh();
// 拷贝出一个删除了Chunk物体的Base场景
string baseScenePath = sceneDir + &/& + &baseworld.unity&;
AssetDatabase.DeleteAsset(baseScenePath);
AssetDatabase.CopyAsset(originalScenePath, baseScenePath);
EditorSceneManager.OpenScene(baseScenePath, OpenSceneMode.Single);
GameObject[] chunkRoots = EditorSceneManager.GetActiveScene().GetRootGameObjects();
foreach (GameObject r in chunkRoots)
if (rootsNamesToExport.Contains(r.name))
EngineUtils.Destroy(r);
EditorSceneManager.SaveScene(EditorSceneManager.GetActiveScene());
AssetDatabase.Refresh();
// Cleanup
EditorUtility.ClearProgressBar();
&/code&&/pre&&/div&&p&拆分后的Chunk场景列表如下:
&/p&&img src=&/v2-ee134bbd9e040b54b3b0115b_b.png& data-rawwidth=&501& data-rawheight=&883& class=&origin_image zh-lightbox-thumb& width=&501& data-original=&/v2-ee134bbd9e040b54b3b0115b_r.png&&&p&&br&&/p&&p&拆分后的Chunk场景列表&/p&&h2&2.2 动态加载组件&/h2&&p&动态加载的过程也并不复杂,因为涉及到游戏内的代码,这里就不放源码了,整个算下也也就不到500行,逻辑也很简单。绑定一个Transform,每帧update检查Transform的位置所对应的Chunk的索引是否有变化,如果有则计算出需要卸载的Chunk和需要加载的Chunk卸载和加载操作。
在Demo阶段,选择使用Scene来作为Chunk的存储单元的原因主要有:&/p&&ol&&li&看到的两款插件都是基于Scene来做的,而且Unity从5.0开始就原生支持Multi-Scenes的场景加载方式,因此预想问题应该不大;&/li&&li&考虑到美术进行烘焙的最小单元是Scene,使用Scene作为最小单元可以“偷懒”不用去手动管理每一个Chunk的Lightmap数据,对于多个Scene同时进行烘焙的方案也是进行过实验,证明具有可行性的。&/li&&/ol&&p&这样,我就基于设想中的美术制作流程实现了第一版本的动态加载Demo。&/p&&h2&2.3 问题总结&/h2&&p&除了一些代码实现上的bug之外,这里值得记录的几个问题有:
&b&1) Static Batching导致的顿卡&/b&
在电脑上运行的时候已经可以感受到明显的卡顿,打开Profiler看了下发现是由于Static Batching导致的:
&/p&&img src=&/v2-32c3d8c2b4fed4e55ed2828865bec780_b.png& data-rawwidth=&1444& data-rawheight=&989& class=&origin_image zh-lightbox-thumb& width=&1444& data-original=&/v2-32c3d8c2b4fed4e55ed2828865bec780_r.png&&&p&&br&&/p&&p&Static Batching导致的加载顿卡&/p&&p&解决方法很简单,在测试项目中关闭了工程的Static Batching,而在正式工程中,场景组件不再勾选Static Batching选项,就可以避免Chunk的场景加载时这段CPU消耗的峰值。当然代价也是无法进行batching,draw call的消耗比较高。&/p&&p&&b&2) NavMesh分块测试&/b&
因为不死心,所以特意做了一下NavMesh分场景bake之后加载的效果,果然是不行的——在其中一块NavMesh上无法移动到另外一个Chunk的NavMesh上:
&/p&&p&&br&&/p&&img src=&/v2-bcda214cffbd7_b.png& data-rawwidth=&1447& data-rawheight=&728& class=&origin_image zh-lightbox-thumb& width=&1447& data-original=&/v2-bcda214cffbd7_r.png&&&p&多块NevMesh的移动试验&/p&&p&&b&3) 场景物件导入到Unity的时候中心点需要在原点&/b&
这个比较好理解,按照位置把物体划分到Chunk的时候是按照世界坐标来划分的,如果物件的中心点位置并不在中心点的话,可能会造成偏差,这也是自动拆分工具执行完毕之后需要美术进行检查的一部分工作之一。解决方法一方面是要告知美术场景物件导入到Unity的时候中心点需要在原点这个规则,另外一方面是在代码中使用包围盒的中心点而非世界坐标的位置来作为划分区域,这样可能错误的概率更小一点。当然,如果物件的形状太过奇怪,包围盒的方式也可能会有问题。&/p&&p&&b&4) 所有场景的Lightmap模式必须一致&/b&
在测试应用烘焙效果的问题的时候,出现过Lightmap失效的情况,检查后发现是因为部分场景使用了默认的Directional模式,部分场景使用了Non-Directional的模式导致的。&/p&&p&在Demo完成之后,进行打包和手机上的简单测试,基本满足了设想的要求。这段时间场景美术也进入了美术效果和制作方案的频繁更改阶段,这块工作也就搁置了很长一段时间。&/p&&h2&3. 正式版本实现&/h2&&p&最初的Demo版本没有去考虑的一个内容是像地表这样的大块Mesh是如何拆分的,原因也主要是当时美术的制作方案是按照六边形作为一个单元,每一个单元都不会很大,自然可以正确地被分割到不同的Chunk中。而后面改为T4M刷地表贴图来表现更多细节的制作方案之后,就有了可能需要让美术手动拆分或者程序来做Mesh分割的需求。想来也不是很难,按照顶点的位置来做判断,确定要分割的边界之后把这些边界上的顶点复制多份分别放到对应的Chunk下似乎也就可以了。但当这块预研工作刚刚开始推进的时候,美术又改了主意,为了表现地面的高低起伏,想用Terrain的方式来进行地表的制作。&/p&&p&技术上仍然不算什么难题,Unity有丰富的插件来做这种事情,而且相比于Unity5之后就不再维护的T4M,似乎官方的Terrain更好用也更稳定一点点。Terrain转Mesh的插件有不少,我们使用的是&a href=&/?target=https%3A//www./en/%23%21/content/47276& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Terrain To Mesh&i class=&icon-external&&&/i&&/a&,后文统一简称T2M。经过思考和讨论,权衡一些问题之后,最后制定了如下图所示的工作流程。
&/p&&img src=&/v2-f197cdcaceea_b.png& data-rawwidth=&1471& data-rawheight=&867& class=&origin_image zh-lightbox-thumb& width=&1471& data-original=&/v2-f197cdcaceea_r.png&&&p&&br&&/p&&p&基于Terrain和T2M的工作流程图&/p&&p&我们分几步来说明一下这个流程图的几个关键步骤的设置原因和具体的制作方式。&/p&&h2&3.1 Chunk大小的确定&/h2&&p&其实在这个流程开始之前,第一件要做的事情是确定Chunk的大小尺寸。在之前Demo中构想的流程里,因为视野、美术风格都未确定,为了能够方便地兼容Chunk尺寸更改的情况,所有的组件都是在美术进行了Chunk大小的设置之后自动拆分的。这样如果中途要更改Chunk大小,其实是一件工作量不太大的事情,只是烘焙过程要重新进行。而基于Terrain的方案,虽然T2M也有自动拆分的功能,但是手游上处于性能和省电的要求,我们规定——&/p&&blockquote&&b&每一个地表所能使用的贴图层数不能超过4张,尽量保证3张的时候也是可看的,低配下程序保留了强制切换为3张的权利&/b&。&/blockquote&&p&于是美术就要求可以更加灵活地使用和分配这几层贴图。由于我们大世界会有不同的地貌和气候风格,风格之间还要有过度的效果,因此经过商讨,美术可以自由分配贴图的最小单位为一个Chunk。这样就不太好把很大一块区域作为一整个Terrain来制作,因此我们使用了一个Chunk就是一个Terrain的方案,让美术可以自由分配这个Chunk下的四张Layer贴图的内容。(这里和美术讨论的纠结过程就不详细描述了,这些琐碎的细节可能只有真正使用这种制作方案的人才能有更深的体会。)
那么,首要的问题就是确定Chunk的大小,而这个一旦确定,制}

我要回帖

更多关于 方块消除游戏 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信