做游戏技术主要讲究的是套路,以及对套路的掌握程度。比如说你要搞个体积光,那么从用mesh+uv动画,到volumetric scattering你都得知道,而且要知道这些方案的优缺点,以及具体的实现细节,比如camera会不会到体积光里边之类的,这种细节的了解会让你更加有信心做出各种技术决策。
所以3a级游戏的大神技术也是对各种领域的套路玩得比较溜,这里我也分享一些做游戏20来年自己领悟出的一些套路吧。
美术用工具输出的3d模型,材质一定要做一个导出插件,否则做出来和进引擎效果不一样,就只能做做手游这种无光照的手绘贴图质量的产品了。
动画要想不滑步,就只能用animation driven的方法,这个需要跟策划做好深度的沟通,得让策划知道移动不是说配置一个速度就可以了,得去找动画师一起调整移动的动画。
动态天气的困难不是制作上的困难,是可以用lightmap的物件会少很多,性能不一定扛得住,这个要在项目初期一定得和制作团队沟通清楚。
球类游戏要达到非常自然的动画,一方面动画肯定是要动捕的,另一方面更重要的是搭建一套动画选择机制,然后根据运动中的球类位置来选择最合适的动画来匹配,再加上小部分的ik。
头上冒字和冒血这种hud就应该用hud的标准方法来制作,切记不能涂省事用ui的方法,对性能效率会有非常大的影响。
音频对最终品质影响很大,一般遵循46原则,即图像资源在最终包中占6成,音频资源占4成。给音频设计师配置一个独立的程序来达成音频的设计需求。
状态机最好是用可视化的方法来实现,游戏中80%的bug都是和状态没切对有关,有个可视化的状态机对于找bug非常方便。
control是最需要状态机化设计的(不同的情况下按同样的按键达成不同的逻辑)
做面部表情,如果不是捕捉就用骨骼简单搭搭就好,如果是捕捉,制作成本会变得非常的高(制作各种morphing target)
对最终画面影响最大的是镜头效果,所以尽量节省渲染时间留给镜头特效。一般影响最大的是校色,如果硬件平台允许尽量给美术提供带深度校色的工具。
有比较宽广视野的游戏,室外可以用一些很取巧的方法来模拟mie scattering和rayleigh scattering,加上哪怕是假的对画面的提升也是巨大的。
对于不同的数据采用不同的配置方法,不要什么数据都用excel,对于有可视化需求的配置,比如ui或者角色身上需要装配一些武器的,提供可视化的工具。对于需要描述父子关系的例如技能树解锁之类的用json或者xml来描述,对于纯数字逻辑的就用csv就好了。
场景的材质如果制作normal map对于你们团队比较复杂,多加一层detail map也能对效果获得较大的提升。
角色的材质,如果性能有限或者说制作成本无法承受的话specular map比normal map的效果要好。
如果角色会近距离看脸,脸部的眼睛一定要单独拿出来处理,脸可以糊,眼睛一定不能糊。
脚步声的标准做法是在地面上放一层低模做和脚的碰撞检测(脚步声如果追求真实,最少得有3个以上的样本随机)
如果要提升动画效果,考虑主角的前臂加上twist骨骼,左肩和右肩不要从脖子上搭建骨骼,要从胸口开始(做head lookat的时候效果会更好)
衣服的标准做法是通过贴图来控制哪些顶点受skin和物理影响的权重比,那张贴图还可以用一个通道来控制流汗的时候哪些地方的smothness要提高。
搭建一个运行时数据库,并且游戏中经常需要访问的数据都放入数据库,可以类似redis那样非常简单的提供一个set和get就行了,运行时数据库可以帮助你找到绝大多数bug。
制作ai尽量使用行为树,并且花时间一定要让策划具备编辑和调式行为树的能力。
顶点色可以各种花式使用,无论是用来bake ao还是决定detail map的权重,都可以用很低廉的代价来获得非常棒的效果。
动画不是在任何时候都可以blend的,要想效果好,牢记:左脚落地的时候只能blend到左脚落地开始的动画,右脚同上。
做上下楼梯的locomotion的时候,用椭球碰撞体会非常简单的获得还不错的效果。
如果画面会经常快速的运动,可以加入一个vector based motionblur,效果会出奇的好。
要想场景生动,一定要使用decal,一个方便美术的decal工具可以让美术一天之内让整个场景提升几个档次。
暂时想到这些,不说了,休息好了继续干活。
~~~~~继续更新一波套路
解决alpha透贴排序的标准方法是两次绘制,第一次在不透明队列里渲染一次alpha test(cutout),打开zwrite,第二次在transparent队列里开alpha blend不开zwrite,ztest lessequal渲染就能还原美术在maya里看到的效果。
弹簧是个非常好用的物理组件,其虎克系数可以有效的模拟力的衰减来做出很多感人的效果,从乳摇,臀摇,尾巴,头发马尾,布料,脸上被重拳击中的肌肉变化都可以看到弹簧的身影。
adobe fuse cc + mixamo可以非常快速的搭建模型和动画来帮助策划找到剧情的场景的感觉。
脚下ik从程序来讲是很方便实现的,大多数引擎都有ik功能,但是工作流程我发现很多公司都没有正确使用。正确的流程是对输出的动画有一个左右脚高低的分析工具,逐动画生成每个脚步离水平面的高度曲线,然后运行时根据脚步的高低来决定ik和skin的权重。
镜头的设置很重要,最好给美术一个和相机镜头类似的算法来反过来计算fovx和fovy,我看到很多产品的fov都是一水的60之类的。
对于类似铁丝网或者其他半透物体的mipmap的标准做法是先自动生成mipmap,然后要美术手动的来降低不同lod贴图的alpha,换句话说近处看有铁丝网,远看就只有框中间近乎全透了来降低锯齿感。
dx10以上的平台上特效的shader加一句根据当前depth和已经绘制的depth的差来控制alpha可以实现简单且效果不错的软粒子效果。
头发的物理效果可以参考衣服的做法,发根受skin影响多,发梢受物理多一些即可。(额前刘海受物理要关掉重力)
如果实时sss负担太重,可以简单的把模型厚度信息烘培在顶点色的某个通道上,然后只需三两行代码就可以让皮肤有sss效果。
看到好多项目用双面材质只是在shader中简单加一句cull none,这个是完全错误的实现。正确的做法是需要把三角形索引信息走vs传递进来,然后判断是否顺逆时针,对于反面需要把法线反转才能获得正确的渲染结果。
先更新到这。
完了,感觉思绪开始打开了,又更新一些,怕一会会忘。
动画驱动的模式下,转向最少需要8个动画,原地左转90,右转90,左转180,右转180,移动同样四个,然后根据控制器的输入来决定混合的权重,一般神海这种级别的产品光locomotion牵扯到的动画会在40-50个这种量级。
对于衣物和皮肤,detail normal十分重要,可以瞬间让你的衣服能看出针织的材质。
处理声音的时候,远处的声音混响需要程序来手动提升,近处降低混响,对临场感增加很多。
声音如果样本有限,也一定要做随机,哪怕就一个脚步声样本,播放的时候也应该随机pitch和volume。
给策划提供一个调整动画曲线的工具,横轴是动画时间,纵轴是动画播放的速度,策划通过这个工具可以调整出情绪非常饱满的动画效果(例如:攻击前摇动画速度变慢,攻击过程加速之类的)这个需要和动画师沟通清楚,要求他们只需要k好几个相关pose即可。
卡通渲染的时候有一步是非常关键也是很多公司都忽略的,就是手动调整模型法线,这一步得在美术工具内完成,通常是定义toon shading的光方向之后,通过调整法线来让一些部位有“看起来”较为舒服的受光,主要是鼻子,腋下和两个胯这三个位置。
游戏加载的正确做法是,在出包的时候对各资源的单位加载时间进行预计算(适合配置固定的主机游戏)。之后在运行时加载的时候,根据每一帧cpu的可用空闲时间来决定当前帧可以加载的资源类型和数量。
渲染阴影的时候,很多人都会忽略绘制阴影那个pass的优化,以前做上一代游戏机的时候所有会有实时阴影的模型都会做一个低模和专门的材质(如果有透贴阴影的需求)。
对于写实类型的游戏,decals的正确制作方法是拿相机去拍,比如地上的水渍,墙上的裂痕,车上的划痕之类的,开闪光灯拍照,然后回来在ps里面抠出来。
有很多arpg的游戏中都有霸体的设计,霸体中不会受击,其实这个的正确做法是动画新增一个受击层,在播放霸体动画的同时轻微的blend一个受击动画,打击感会舒服很多。
午饭时间!
反响不错啊,再来一波=)
写实风格的贴图,推荐尽量使用Substance制作,打包不同目标平台的时候,可以根据目标平台的实际硬件情况,决定是Bake出Texture还是用Procedual Texture,其实很多时候会发现很多PBR贴图除了Google图片出来修改之外,只有Substance才能比较好的制作出来。
有一个关于Animation Driven的系统中,AI的制作问题,主要是因为动画状态机自己有自己的行为准则,所以传统的AI设计思路就变得比较无力,比如说我希望我的NPC每0.3秒攻击一次,但是攻击动画本身就超过0.3秒了,怎么办?或者说状态机的逻辑无法响应到0.3秒的攻击。这个时候需要跟策划沟通,在Animation Driven的系统下,要完全的分开设计,NPC的大脑是AI,NPC的体格是动画状态机,很多时候AI的设计要根据体格的情况来酌情调整。要在行为树里增加一些检查身体体格的节点,比如说,我要转向某个方向,那么在适当的时候需要检查自己的身体是否真的转到指定方向了;同时对于大脑向身体发送的指令要分优先级,优先级的实现方法是该指令的有效时长,比如说我的身体在受击的状态中,但是我的大脑仍然下命令让我攻击一次对方,这条指令优先级存在时间0.2秒,如果受击状态在0.2秒内复原了,则该指令身体可以执行一次,如果0.2秒内身体仍然无法攻击,就丢掉此次指令。
Volumetric Cloud/Fog/Light的使用一定要提前和美术进行商量,因为计算过程中牵扯到大量的Depth sampling,所以画面中多大会存在多大面积的这类效果一定需要严格控制,否则到了后期不得不移除这些效果的时候会让整个产品瞬间降低一个档次。
在一些中低端设备上可以用一些简单的压缩算法来把RGB + Luminance除以一个除数来压缩到32bits的颜色空间中来获得非常划算的HDR效果,相比较RGBM,用除数可以免费获得“假”正确的alpha blend效果。这一条无需和美术沟通,直接上就行。(移动平台可用,效果很好)
关于差值,差值计算最大的问题是需要和策划沟通清楚,越是符合现实生活运动规则的,只能使用物理的方法进行差值,物理的方法是没有办法精确的保障差值的最终位置和时间,但是却可以获得完美的差值效果。这里有一个非常小的tips来实现物理差值:一个物体从旋转R0,位置P0,差值到旋转R1,位置P1,需要差值的时候,在物体上挂一个弹簧,弹簧的另外一端挂在位置P1上,另外物体的运动规则增加两条:1,每帧运动转角不能超过XX度;2,物体的实际运动位置是当前朝向 * 力矩;即可,差值出来效果棒棒哒,无论是飞个火球还是跟踪导弹都可以用这个。
美术资源的优化,这件事情比较好的方法是要严格的关注,但是尽量不要过早的修改这些问题,因为开发的过程中始终要留一些空间用来提升画面效果,所以过早的修改掉性能瓶颈,可能会导致到最后不得不放弃已经集成进版本的一些效果,非常不划算。所以等大家都对画面比较满意了之后,再进行一轮性能优化,结果还能再增加一些效果,对于美术大兄弟们来说就变成一件很好的事情了。
本来没打算写这么多,只是开始写了个头,就发现还有很多类似的问题也都可以罗列出来,于是出现这么多杂乱的内容,回头有时间会仔细整理整理,比如说配个图什么的,如果有朋友对于一些tips有疑义或者想知道一些详细的实现细节,欢迎私信单聊。
应某同学的要求
更新一波手游的经验ヽ(•̀ω•́ )ゝ
贴图进版本的时候做一个alpha通道的剥离,一方面可以比较方便的适配安卓ETC1压缩格式,另一方面后期要压包的时候alpha通道可以随意缩大小,美术基本无感知。
如果是UI资源比较重的游戏可以采取layout和资源分离的方式来获得大量的性能提升。针对unity引擎来说就是遍历ui里所有用到的material,把里面的贴图替换成4*4的空白贴图,另外建立一个从材质对应贴图的索引。因为手机是ssd的缘故所以磁盘io读取贴图的速度是非常快的,这样就可以把整个ui的layout都留在内存中不用切场景释放,不同场景对应加载不同的贴图做一个运行时的对应即可,加载ui的时间能提升80%。这一步建议新项目中前期使用,后期项目做这种级别的修改不划算,风险高。
如果是动画资源比较重的产品,建议使用自定义的动画格式,采取float16的四元数储存关键帧数据,然后加载时还原引擎需要的动画数据,以前做wii上的产品,1000个左右的人形动捕数据可以压缩到23m左右。
经历过很多手游项目的全屏大图比较多(推广图,loading图),有的会占到整个贴图量的30%甚至更多,这时候一定要优化大图的制作工艺,和美术沟通把背景,文字和前景拆开制作,一方面可以更好的压缩(方形,2的次幂),另一方面背景图可以采取比较极端的压缩参数。
加载的过程中往往最后会卡一下,这个是第一次shader提交到gpu产生编译消耗的时间,可以通过在屏幕上绘制一个透明的三角形来完成warmup,这一步基本上主流引擎都有接口,如果单帧消耗过高,可以考虑分布在若干帧里完成。
打击感的一个小trick,击中的一瞬间把时间tick调成0持续个0.1秒左右,又轻巧效果又好。
搭建UI框架的时候给每页ui增加一个fadein和fadeout的接口并且管理好状态机的切换,今后可以很方便策划或者美术增加ui打开和关闭的动态效果。
2018国庆更新
国庆期间玩了一些当下比较流行的游戏产品,感触还是挺大的,玩法设计都非常的优秀,但是整体的产品的质量差得还是比较远的,所以这一次我打算更新一期专门讲UI开发的套路。
在国产游戏中,UI是比较重的一块,基本上一个项目会有70%-80%的开发量都集中在UI上面,那么有效的提高UI的生产开发效率以及UI的品质,就会让整个产品无论是成本还是效果上都会提升很大一个档次。
为每个UI上看得到的控件都封装一个独立的类,不要去直接用Button或者AnimationButton这种级别封装的类,太底层了,至少要封装到:OKButtonGeneral, CancelButtonGeneral这种级别的类,因为UI往细节上调整无非就是加动画,加效果,如果不想一个个来搞就从最开始设计UI的时候就先把这些基类建好。
给每个可以交互的控件都要单独设计一个响应范围,例如有一个很小的图片,很难点中,但是把图片放大了又不太好看,所以最好的方式就是用小图,但是扩大响应范围。对应的要开发一个开关,让策划人员可以随时看到每个控件的响应范围。
UI开发中比较大的痛点就是每次重构或者换风格的时候,有大量的旧资源搞不清楚是否还在使用,删又不敢删,之前的美术或者策划或者程序又离职了,这样整个项目越开发越臃肿,越不可维护,碰到这种情况千万不要犹豫,在开始换风格的时候就一定要说明,原有的UI Atlas一个都不能重用,全部用新的,因为做一次atlas的时间是你清理一次资源的1/10的时间和精力,资源的版本管理本来就是技术分内的事情。
给每一页UI取一个有意义的名字,我就见过好几个美术策划程序为一个UI问题争吵了很长时间,最后发现大家在讨论的是不同的东西,UI的命名一定不能重名,否则到了后期,哪个UI在用,从哪边跳转过来的都分不清,文档都没法写。
UI的跳转,不要简单的切换一下页面,把之前的隐藏,新的显示出来这样。一定是先push一个切换UI的请求,然后UI控制中心要根据当前UI的动画播放情况,逻辑是否处理完了等等来决定是否切换,而且切换只是把当前页面指向栈顶元素,因为还要通过pop来处理返回的逻辑。
我以前看过一个程序小朋友开发UI,发现他工作中有接近30%-40%的时间是在处理显示层级的问题,即谁显示在谁前面。这里分享一个小技巧,如果你无法想明白究竟谁应该在前,谁应该在后,那就说明这两个东西本身就应该是同一个东西,写一个新的类来包含这两者,比如说有个ITEM的图标,图标上面要画一个高亮选择光圈,光圈上面还要显示ITEM的数量,那么说明这三者就应该放到一个统一的类里面去,例如说GlowableCountableItems
UI里面除了图片之外,其他的控件都应该采用九宫格,或者反过来说,只有碰到你没有办法采用九宫格的元素,才考虑不使用九宫格。
做屏幕适配的时候,不要考虑缩放图片这样的方法,按照九宫格的原理进行挂靠,如果内容太多,就需要考虑在细节元素上面再挂一个父节点,通过挂靠父节点来完成适配
字体不要乱用,一般一款游戏控制在3种字体以内,不要轻易的给字体加类似粗体/斜体之类的效果,因为最终字体是要画到贴图上缓存起来的。用到专门的字体一定要购买一个版权,省的上线以后打官司。
UI的本地化问题遵循的原则是开发一个类似于LocalizableText之类的控件,里面输入什么文字自动的写到数据库里,否则到了后期UI量大了要把文字提取出来都不是件容易的事。
另外一个本地化相关的就是美术字也应该做成特殊的资源,类似LocalizablePictureText这样的,也是节约后期本地化的时间。这些统称为LocKit(Localization Kit的简称)有了这些基础设施,之后无论是产品出海到哪个国家都可以比较安心,不慌。
有一些UI效果可以考虑用shader来完成,举个例子,类传奇的游戏装备图标都会有一圈光圈围着转,这个东西用shader可能就是10行之内的事,我看到过最奇葩的实现方法就是创建了10多个小珠子,每一帧计算这10多个小珠子的位置来实现,当时我就惊呆了。
输入法这个东西要谨慎处理,如果是单机游戏,都可以考虑在弹出输入法的时候让游戏暂停,因为你在输入的时候其实是没有办法和游戏进行其他交互的。
很多游戏都有某个窗口弹出来的时候,背景模糊掉之类的需求,这种的正确制作方法是实现一个类叫BackBufferPicture,然后这个类可以配置截图的参数和属性,这样在任何地方都可以很方便的来实现这样的效果。
同样也有很多需求是在UI中嵌入3D模型,这个也是要实现一个独立的类来实现,如果3D模型上还要增加一些UI来对3D模型进行一些说明,则应当用HUD的方式在3D中实现。另外UI中嵌入3D模型很多程序直接用正交投影,这样出来的效果就会比较奇怪,但是一时又说不上来,记住,任何情况下显示3D物体都请用透视投影。
释放UI的时候一定要记得释放Render To Texture的内存,现在动不动就是2K屏幕,一块FrameBuffer很耗内存的。