年度大赏 | 2018最受欢迎的UWA问答

新年伊始,随着大家紧锣密鼓地开始了工作,UWA每周推送的知识型栏目《厚积薄发|技术分享》已经伴随大家走过了150个工作周。在此我们优选了12个开放性的精彩回答,分享给大家。

UWA 问答社区:answer.uwa4d.com
UWA QQ群2:793972859(原群已满员)


1、如何设计渲染等级?

现思考如何设计项目中的渲染等级,求有经验的大佬指个方向,例如ShaderLOD,还有其他什么思路吗?谢谢!

精彩回答:正好我也整理过项目的LOD规则,可能不限于题主描述的渲染等级。一套好的LOD系统需要美术在资源上做大量的资源分级工作,需要程序搭建完善的LOD框架和辅助工具,每增加一个功能模块都需要把LOD考虑进来。

一、如何确定项目的LOD分档和性能标准

LOD(Level of Detail),这里的D代表Detail而不是Distance,也就是说,所有游戏画面和游戏功能的细节都可以进行分级,不必受限于距离。

1、如何制定性能标准?

在分级之前,需要确定目标(省电、正常的游戏体验、噱头),我们要在哪一种机型上面运行哪些表现效果和功能,达到怎样的性能目标(帧数FPS、内存占用、Drawcall、同屏三角面数等)。

◆经验总结:

1)画质的表现力与性能开销是相互矛盾的
2)需要持续维护,相关功能系统的设计都需要考虑到不同画质
3)极简画质牺牲了可玩性,同时会增加LOD框架的复杂性,使用最简单暴力的方式去处理

◆兼容性问题:

1)低配画质需要考虑的适配问题
• 可能不支持Shader定义8张以上的贴图纹理
• 可能不支持ETC2格式的贴图纹理
• 可能不支持OpenGL ES3.0

2)高配画质需要考虑的问题
• 支持PBR、线性空间
• 奇怪的Bugs

3)需要解决各个画质下的兼容性问题,建立黑名单和白名单。

2、如何找出可以进行分级的细节?

◆优先找出开销大的点
• 后处理效果Bloom、HDR、ToneMapping、MotionBlur、DOF等
• 实时光照和阴影、水面实时反射
• PBR物理光照
• Ragdoll、DydamicBones等物理系统
• 日夜循环、特效天气系统

◆细节模块的LOD功能考虑
• 场景/角色/特效/摄像机相关/其他系统模块

(完整答案请前往问答社区进行查看。)

感谢文雅@UWA问答社区提供了回答,欢迎大家转至社区进行交流:
https://answer.uwa4d.com/question/5acc208b425802635474fc7d


2、PBR在手游开发中的适用性

我们是MMO游戏,现在想给主角(包括其它玩家)使用PBR材质(Untiy自带的Standard),其它角色和场景不使用。不知这种情况下性能是否能抗住,同时我也想了解下目前手游中对于PBR材质的使用情况。

精彩回答:目前手游中使用PBR材质的项目明显增多,特别是MMO、RPG等项目中,主要角色、NPC和大Boss等都开始往PBR方面走了。

如果PBR仅是在以上情况下使用时,Unity引擎自带的PBR是没有太大性能问题的,因为一般角色占据的屏幕面积都会比较小,而过剧情时,虽然屏幕面积占据较大,但时间一般都很短,所以给总体性能造成的压力不大。

但PBR暂时还不建议在中低端设备上用在地形等常常在屏幕中占据较大面积区域的物体上,因为它确实会造成较高的GPU压力,我们在UWA Day 2018上也对此进行了定量分析(类似下图),这点需要研发团队在使用时注意。但是,一切应该以自身项目测试为主,具体查看项目在自己设定的低配机器上到底性能如何。

最后,在使用Standard Shader时,除了关注性能外,还要关注下它对于内存的影响,可以参考这篇文章:【求知探新】Unity中ShaderLab内存优化

该回答由UWA提供,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5ae2f40132493548fbd32bbc


3、使用FairyGUI开发经验分享

我们新项目中想使用下FairyGUI,主要还是为了减轻程序工作量,请问大家有在项目中使用过的吗?主要是关于图集、DrawCall优化、一些滚动条的优化和Richtext解析等等,想问下在这些方面FairyGUI有没有很好的支持呢。另外可以支持自定义UI控件么?有经验的朋友都可以分享下吗?

精彩回答1:两个上线产品,一个自家的一个朋友的:
http://www.9game.cn/xxyg
http://www.9game.cn/mengxiangqiyuan

主要几个点:

1)对美术十分友好,各种习惯跟Adobe系列的一致,编辑器本身就是AS3开发的;
2)包装了一些概念,十分方便拼界面工作;如关联=>屏幕适配 、控制器=>状态控制等等;
3)之前的版本解析使用xml,GC较多,最新版本已经更新为二进制,界面创建的CPU和内存消耗都降低了很多,但是还在内部使用,并未应用到线上;这个功能FairyGUI也刚刚发布不到两个月;
4)自带图集支持Alpha通道分离,在贴图压缩和机型兼容上可以直接应用到;PS:建议稍微修改源码,让Alpha的贴图格式为Alpha8,实测这样的在保证视觉效果的前提下可以把贴图压很比较小;
5)各种基本的东西:DrawCall、图集、各种类型组件等等这些都属于还不错的状态,一般不会遇到什么支持不了的;
6)讲一个调试缺点,FairyGUI的组件并不是MonoBehaviour类型的,所以在Unity里面看到的GameObject并不能和组件一一> 对应,遇到一些奇怪问题的时候需要一定想象力,不能像UGUI或者NGUI简单直接看到UI的参数;
7)FairyGUI是跨平台的,会遇到FairyGUI编辑器中预览的和UnityEditor里面看到的不一样的情况,如果对Flash的渲染有一定了解,应该不算什么障碍,如果没有相关经验还是需要踩一点坑的。
感谢袁首京@UWA问答社区提供了回答

精彩回答2:作者也来凑凑热闹。最大的优势当然是开发效率,用了FairyGUI的基本都中毒,这种开发模式的效率是其他UI远远不能比的,越大的项目优势越明显。UI开发有一个很大的特点是重构次数比较多,一旦发生这种情况,通常都会有让一线程序员辞职的念头,但用FairyGUI的就可以做到云淡风轻。

大家很关注的性能,我觉得NGUI/UGUI为了降低DrawCall采用的合并Mesh技术对UI制作要求太高,一旦动静分离不合理会引发灾难。FairyGUI提供的优化技术是动态后期优化,在制作时对UI人员基本没有要求。简单的说,就是你随便拼,FairyGUI负责自动优化。两者的运行性能,你很难感受到差别。但如果UGUI你不优化,就会和FairyGUI有很大差别。所以有一个说法,FairyGUI可以轻松应付低端机,但UGUI却要花大力气。

GC问题是C#库不可回避的话题,FairyGUI也在不停迭代中改进。最近推出的二进制格式,更是解决了大家一直有意见的加载问题。FairyGUI运行时,如果不发生文字和图片的更换,是没有GC的,即使各种动效(位移、透明、旋转等等)在不停运行。这一点是很难得的,因为一般情况下,你如果要用其他UI实现这些效果,那么势必要引入其他插件或者自己写大量代码,那么这些代码的优化是要你自己完成的。

最后也来说说缺点,首先FairyGUI需要你学习多一个编辑器,了解一种不同的开发模式,在FairyGUI目前知名度远远不及UGUI的情况下,选择FairyGUI需要决策者有前瞻性;其次FairyGUI结合UI实际运用的痛点,自带了很多缓存机制,例如游戏中List总是避免不了不停刷新,所以FairyGUI的List是自带Cache的等等,你需要了解一下这些特点,否则会造成FairyGUI有内存泄漏的错觉。

感谢谷主@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5bd275efa4201c0aa434742a


4、Lightmap平台色差问题解决方案

问题描述
PC上烘培,转到安卓平台即可复现,但非所有项目都会遇到这个问题。我使用的Unity版本是2017.4.6f1,经过测试2017.4.14f1依然存在这个问题。色差具体表现有亮度降低和色相变化。

经过了一个通宵,排除了贴图格式、项目设置、烘培设置、灯光参数等,最终确定改了问题原因:

问题原因
Android不支持完整的exr(HDR)格式,在Swith To Android的时候,Unity会把Lightmap自动转换成一种低精度格式(并且不给任何选项和提示)。重点是这个格式转换并不是完整映射,而是类似拷贝过去的形式,转换过程会有数据溢出的问题。

变暗很好理解,而色相问题可以这么理解:假设光照贴图是一个(2000,255,0)的近乎大红的橙色,经过一个有数据溢出的格式转换后,会变成(255,255,0)的纯橙色,这就是我们看到色差的原因。

解决方案探索
在解决问题的过程中搜索到了这两个链接:

1、Unity填坑笔记(二):移动设备上烘焙变暗问题

解决方案:测试出Lightmap数据unity_Lightmap_HDR,然后使用这个参数直接调用源码中的HDR解码算法,并将贴图转成ETC(2)_RGB4。

这个方案我持否认态度,首先Alpha通道是用于保存亮度倍数的,抛弃了必定是有损的;其次,unity_Lightmap_HDR是根据不同烘培结果定的一个值,不是每个场景都固定的。就是说,即使要这个方案也不是这么做的,Alpha通道不能丢弃,unity_Lightmap_HDR还是得读原来的值,否则换个场景就又有色差了。

2、Lightmap在PC上与iOS和Android上表现不同的问题

解决方案:拿原图重新编码,游戏中使用重新编码的贴图进行解析。

这个方案比较靠谱,但是我这边测试做不出来。

问题的进一步分析
我这边已经基本上完全排除其他因素了,用新建的项目和同样的贴图、灯光对象,全部使用默认设置来烘培,这东西确实是引擎Bug,但有些项目却不会遇到,这让我感到困惑,这一定是制作流程问题。

通过对比我发现,我们场景的贴图画得非常暗,而烘培使用了高亮度的烘培,而这个做法是不合理的,贴图那么暗(基本压到0.4以下),是一种严重的精度浪费,而光照强度也很不符合正常环境的亮度。

所以如果没特殊原因,应该所有出问题的项目都是因为低亮度贴图强行烘亮的操作引起的。

我个人认为最科学的解决方案
以正常亮度为标准来绘制贴图,以符合现实世界强度的灯光参数来烘培场景,就不会出现这个问题了。不需要重新编码,也不需要实时解码,就可以避开这个引擎问题。但是如果有高亮度烘培的硬性需求的话,就必须自行编码重新保存了。

精彩回答:
解释两句,题主说的那个Unity填坑笔记后来整理了一份更加详细的文档:
https://zhuanlan.zhihu.com/p/28728151

解释几点:
1)这个文章要fix的问题是Unity 5.x版本中对于线性空间烘焙处理的一个Bug,这个Bug在2017版本中已经修复了,所以和题主遇到的问题并没有直接关系。所以文章的解决方法并不能解决题主的问题。

2)赞同Alpha通道抛弃掉必定有损,但是这是我们自己项目在观察美术烘焙好的lm贴图的alpha通道之后得出的结论——我们项目中lm贴图占用的内存尺寸和Alpha通道带来的效果提升相比,我们更倾向于损失后者,所以这是个取舍问题,建议各个项目根据自己的具体情况来定,所以并不赞同题主认为的不能丢弃的观点。

3)使用unity_Lightmap_HDR的确不正确,在我们项目中效果“正确”也只是看上去一样而已。我们也已经更改为2017 fix的正确答案:

inline half3 DecodeLightmapDoubleLDR( fixed4 color )
{
float multiplier = IsGammaSpace() ? 2.0f : GammaToLinearSpace(2.0f).x;
return multiplier * color.rgb;
}
inline half3 GammaToLinearSpace (half3 sRGB)
{
// Approximate version from http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html?m=1
return sRGB * (sRGB * (sRGB * 0.305306011h + 0.682171111h) + 0.012522878h);

// Precise version, useful for debugging.
//return half3(GammaToLinearSpaceExact(sRGB.r), GammaToLinearSpaceExact(sRGB.g), GammaToLinearSpaceExact(sRGB.b));
}

另外,美术把贴图做得亮度偏低,然后通过打光来提高整体亮度,貌似很多美术喜欢这种做法...我们美术在制定了线性空间下标准贴图亮度为187左右的情况下,还有部分场景故意使用较暗的贴图亮度。也可能是我们没给场景开HDR的原因。

感谢贾伟昊@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5be90015a8b4ee66df69c250


5、如何深入掌握研发项目的物理性能

如何提高Unity物理引擎Physx的性能?我在场景中加入100个具有物理刚体的小人,并充分碰撞,发现低端机的帧率只能跑到10帧以下。

精彩回答1:如果需要充分进行物理计算,这些拥挤在一起的小人很可能会造成大量的物理碰撞,进而造成很高的物理耗时。

在优化之前,题主需要先了解一些基础物理数值推荐,并不是所有设备都能流畅跑起100个自由制作的蒙皮模型的。所以,建议先看这篇文章:如何读懂UWA性能报告?—物理篇

另外,题主还需要看一下真机上的具体耗时瓶颈是否真正耗时在物理上,100个角色,如果Mesh量很大,渲染耗时也是不可忽视的,所以建议通过Unity Profiler来先确定一下真机上性能瓶颈。

最后,是否每个小人都需要精确的物理计算,是否可以通过一些射线求交、范围判断等性价比高的判断方法来代替纯物理碰撞?这需要题主从设计的角度上来进行权衡。
该回答由UWA提供

精彩回答2:你并没有什么办法直接调用PhysX的API,所以所谓优化物理引擎的性能,倒不如说优化相关组件的性能。首先优先使用CharacterController而非RigidBody。然后尽量避免使用MeshCollider,用BoxCollider、SphereCollider和CapsuleCollider代替,如果不可避免,那么钩上Convex。当然,最好的优化就是不要用物理碰撞。射线能解决很多问题,但是射线也不是免费的,它的消耗跟场景里的面数正相关,当然设置射线的maxDistance和LayerMask能节省掉不必要的消耗。最好就是用简单的物理模型来描述问题,自己写代码实现。

感谢凯奥斯@UWA提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5ab47292d35eb22c10a0a403


6、大世界场景优化和加载策略

关于大世界(SECTR+Terrain)我有几个问题:
1)市面上是否有手游(比如吃鸡)使用了 SECTR 和 Terrain 来解决大世界的问题,并且实现效果还不错的呢?另外是否有其他现成插件也适用大世界的??
2)Terrain 的 Draw Call 有没有什么优化的 Guideline?我注意到 Terrain 自带的树和草似乎都比较费。另外,水平视角的时候能看到较多场景中的内容,有什么一般性的策略来减轻渲染负担?
3)在 SECTR 的框架下,可以很容易的给一个地图分块,但应该如何解决地表分层的问题(比如地面、建筑、装饰等)?这里的层似乎已经不符合 SECTR 中 Sector 的概念,而是另一个维度。
4)大地图中用何种手段解决 LOD 的问题比较好?SECTR 提供了一个简单的 LOD 方案,只是对组件(尤其是 Renderer)根据其 Bound 来进行显隐。SECTR 是否在 GC 方面有坑?
5)性能上,通过 AssetBundle 频繁加载和卸载子场景(这需要修改 SECTR_Chunk),如何能减少卡顿?

精彩回答:就目前我们优化过的超大地形(8kx8k)的移动游戏来看,基本上都没有使用SECTR+Terrain这一解决方案的,而是全部转换成Mesh来进行无缝拼接。我们没有使用过SECTR这一插件,所以对其分拆机理和组织方式并不了解。但是对于Terrain来说,一般研发团队更倾向于使用Mesh来进行替换。

Terrain的优势在于编辑十分方便,通过一些插件(比如Terrain Composer)可以快速生成基础地形等等,但是它的Draw Call并不容易控制,至少很不直观,内存同样较之同等复杂程度的Mesh要大,且TerrainData的加载效率也并不高。所以,对于前期通过Terrain来进行地形编辑的团队,后续往往会将其导出成Mesh来进行动态分块加载。这是目前我们较为推荐的方案。

对于场景的加载,只要AssetBundle中的内容不多,Size不大,现在通过LoadFromFile+LZ4的方式来进行加载已经相当快了,现在的顿卡一般不出现在AB加载上,而是出现在AB.Load和实例化上。对此,有效地办法是通过预加载、缓存和自己制作流式加载来缓解卡顿问题。前两者伟昊在他的回答中已经很详细了。流式加载则是指控制每帧中加载和实例化的资源数量,这需要根据具体的内容、情况来进行具体分析了,并没有统一的准则可遵循,唯一要做的就是多测试、多试验。

除上述之外,还需要以下几点了解一下(以下为题外话):
(1)地形切得不要过于细碎,否则会加大Culling以及后续引擎场景规划(CreateSharedRenderScene)的开销;
(2)超大地形的游戏(吃鸡、沙盒等)中,UI模块的开销较之其他游戏(MMO、ARPG、卡牌等)要明显降低,这其实可以给其他模块贡献出更多的计算空间;
(3)物理模块的耗时则大幅提升,如果在加上一些车体载具,那么其往往会在不注意之间加入大量的物理开销,这是研发团队在面对大地形开发时会遇到的新话题。

该回答由UWA提供,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5b4481362a652c518d8d5356


7、如何把握卡通渲染制作流程?

我最近在Unity中制作角色的卡通渲染效果,目前的工作流程是这样的:
1)程序在Unity中写Shader调效果;
2)美术在3dmax修改模型顶点色和法线等资源,修改完导出给程序;
3)程序将资源导入Unity中验证效果。目前需要频繁地修改资源、导出导入资源,效率比较低下。
所以我有以下两个问题:
1、如何在3ds max中写着色器,美术修改模型后能及时看到效果?
2、成熟的制作流程是什么样的?

精彩回答1:
1、这个不难的,让渲染程序员简单看一下Maya或者Max的文档,几个小时基本都是可以搞定的,Max或者Maya都有例子和文档,比如Max的话就是用DirectX Shader Material,不用把这个想得很难,好好看文档。

2、我觉得本质上主要是想要所见即所得,所有的工作也都是为了这个目的。卡通渲染对美术资源的修改大多需要定制化,例如靠刷顶点色控制描边,靠改顶点法线去改善光照,所以如果把shader做到max里可以大大提高美术的制作流程,而不是总是导入导出。通常的流水线是,维护一个和引擎预览效果一直的max(或maya)shader材质,再加一个自定义的法线编辑工具(如果美术觉得内置的不够用的话,比如max的法线编辑比较困难),这样在修改美术资源保证效果一致性就好了。
感谢乐乐@UWA问答社区提供了回答

精彩回答2:
对于第一个问题,读书哥提供了一个方法:

max里可以用HLSL写,有DX9/11的Sample,但是问题挺多的,Driver建议用Nitrous Direct 3D 9,记得关掉Gamma/LUT和SSAO。

附上参考文档链接:
http://docs.autodesk.com/3DSMAX/16/ENU/3ds-Max-SDK-Programmer-Guide/index.html?url=files/GUID-0C7A600E-7954-42B0-86EE-586A379A2CAD.htm,topicNumber=d30e34269

感谢李嘉乐@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5ac0dbc1910222635366dc85


8、吃鸡游戏的物理碰撞

由于吃鸡类游戏的强同步,很多时候可能使用帧同步,客户端无法使用直接使用物理引擎,或者状态同步情况下服务器需要计算碰撞等。此时怎么处理这一块碰撞呢?数据结构又是怎样呢?

精彩回答1:如果让我选择技术方案的话,绝地求生这种3D自由视角的吃鸡游戏绝对不会选择帧同步,原因有:

1)射击游戏在玩家移动、开枪等操作上会有较强的手感体验上的诉求,帧同步很难支持即时的操作反馈;
2)自由视角的吃鸡虽然没有战争迷雾,但是会有视距的问题,使用帧同步把所有信息广播给玩家,外挂做起来简单太容易,而吃鸡手游中标定其他玩家位置这样的外挂又有很大的优势,所以本质上不适合。

不知道题主说的帧同步和我理解的帧同步是否一致。然后,基于状态同步,服务器可以跑物理,但是真实的物理完全在服务器跑,对于服务器的压力太大,需要付出的成本过高,一台物理机也可能承载不了多少同时在线的玩家消耗,运维的成本你要评估下是否可以接受。

常见的做法:
1)简化3D物理,根据上下文状态只做部分关键判定,比如类似命中这样的。不过因为物理中的数据计算比较敏感,浮点误差都可能导致结果不一致,这里的工作量和坑应该都不少。

2)使用2D物理系统代替3D物理系统来做,在物理计算中去掉高度,只做2D的碰撞,结合专门的检测进程,是一种可行的检测方案,性价比比较高;

3)客户端判定,服务器验证,先相信客户端的判定,然后进行客户端表现,然后服务器基于数据做验证,这里可能会使用2D物理引擎,也可能在核心判定中再添加一些比如高度的信息等来做;

4)客户端判定,加严格的反外挂方式,封号之类的。这种当然你也要可以判断出来玩家作弊,判断方式可以未必实时去做,类似帧同步放后面通过回放模拟来做也可以,这时候有可能可以使用3D物理的来做(经验上依然不推荐,只是从实时变成离线,对于性能的要求没有那么高了,3D成为一个可能性)。

5)先不做,等游戏火了有钱了再加,没火的话,也没什么专业的外挂团队来使坏。
至于数据结构,太细节了,根据需求自己设计吧。2D的直接集成开源的2D引擎就可以了。
感谢贾伟昊@UWA问答社区提供了回答

精彩回答2:吃鸡玩家数量一般在100个以上,这种情况下用帧同步需要同步的数据量会很大,延迟也会比较严重。因为帧同步一般需要收集所有同场景玩家的输入,然后分发给各个客户端,让各个客户端用相同的逻辑自己去计算每个玩家的位置、状态,游戏逻辑是跑在客户端的。MOBA适合使用帧同步是因为一场比赛只有10个玩家。

我觉得吃鸡还是适合状态同步。状态同步怕的是角色太多,导致需要同步状态的角色过多,造成网络同步数据量大。吃鸡没有什么野怪,全部是玩家,所以场景里角色就是玩家。可拾取的装备需要同步的数据比较少,基本上需要一个位置坐标就行了,玩家身上的状态数据量要多很多。客户端看不见的玩家、装备,完全可以不用同步,因为逻辑完全跑在服务器端,客户端只需按照服务器的逻辑做绘制就行了。

关于游戏手感的问题,FPS游戏对延迟的要求是所有游戏类型中最高的。如果玩家网络不是很好,也很难优化到比较好的情况。客户端先行可以先做显示的预判例如:击中后的血迹。但是数值结果还是依靠服务器端的计算,否则很容易被外挂利用。即使服务器结果判定没有打中,问题也不是很大,最多就是玩家看到有几枪打中有血迹特效,但是对方没扣血。这种情况大概率出现在网络环境不好的情况。

感谢ZFK@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5a90c4960b827e2c0bfdcfc4


9、帧同步的浮点数精度的不一致问题

我们游戏采用帧同步框架,计算逻辑的时候不可避免地产生浮点数运算,如移动和跳跃等。为了保证在不同的平台和不同的机器上得到一致的结果,有什么好的方案能解决或避免浮点数结果不一致的问题呢?

精彩回答1:一般情况下,浮点计算涉及到的位置同步无需保留过高的精度,小数点后保留2位到4位足矣。因此计算前将浮点数乘以1000,然后取整再进行计算,可以有效地解决多端的精度不同步问题。但是需要注意一个问题,就是别超出了你数值类型的最大值范围。
感谢odiecc@UWA问答社区提供了回答

精彩回答2:根据我们自己正在摸索的帧同步经验,如果不是王者荣耀这种级别的游戏,帧同步的浮点数精度影响不是系统的瓶颈。如果战斗时长不长,露馅的概率很低,全改整数的工作量是非常巨大。如果是小公司,要好好评估是否能挺住。

逻辑与表现的分离才是最大的问题,意味着Unity的大量组件不能使用。大量的重新实现的东西需要从头去写,当然全用整数也一样得重头去写。游戏小公司需慎重评估生存问题和完美方案的性价比。
感谢李先生@UWA问答社区提供了回答

精彩回答3:帧同步还是定点数比较靠谱,浮点数带来的误差有可能累计到一个无法接受的地步。另外回答其他朋友的一些问题。

1)网络传输,使用可靠的UDP(TCP)传输;

2)另外看到其他朋友提到的逻辑与表现的分离,这个是帧同步方案必须的,至于说到的Unity中大量组件组件无法使用,主要是> > 帧同步方案逻辑的处理不应该按照本地时钟时序,而是严格按照服务器逻辑帧处理,说不可用其实主要针对逻辑层而言,表现层其实不见得Unity组件都不可以用,表现层上Unity的组件其实必不可少的。

感谢Chale@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/59488b5a252497237a7c3f9e


10、Unity中纹理格式的探究

关于Unity中使用的纹理格式问题,自己查了一些资源,有了一些大概的认知,但是希望能有比较完整、有理有据的依据。如果已有整理好的文章求科普!目前从各方面渠道得到的大致结论有:

  • ETC2:安卓推荐格式,支持Alpha通道。
  • PVRTC:iOS推荐格式?支持Alpha但是效果很差。
  • ASTC:效果很好,iOS推荐格式,不支持iPhone5s。
  • RGB24/RGBA32:不推荐使用,尽可能用ETC2/PVRTC/ASTC,如果不行用Dither(UWA建议)
  • Alpha8:Mali GPU的机型不支持。

产生了以下疑问:

  • 以上结论是否正确,有没有什么补充或者坑?目前使用来说感觉PVRTC的尺寸限制比较大(正方形+长宽2的幂)
  • 大家在场景、角色、UI不同的用途来说一般都是如何选择的?目前我们项目里感觉UI用PVRTC美术接受不了(ASTC暂时还没决定用),lightmap用ETC2在某些地方放大疵边比较明显,有什么好的办法吗?
  • 尺寸大家一般是如何定的?比如1920*1080的全屏Loading图,一般定多少?(我看王者荣耀的loading图画质很差)
  • Mipmap一般要不要开咧?如果开的话,其中的一些设置怎么设比较合理?
  • 其他可能大佬们愿意教教我的这方面的内容?

精彩回答1:关于ASTC的支持率,参考贾伟昊的回答。
https://answer.uwa4d.com/question/5a6700517daacf4c7ff04918

可以考虑在iOS上用起来,但是要放弃一些机型。安卓上建议使用ETC2,搭配Unity的Crunched算法,效果更佳。RGB24/RGBA32确实不建议使用,主要是会占用显存带宽,但是效果确实好。Dither是可以用,但是对Scale9和渐变不友好。

UI的Mipmap不要开,UI不会发生Mipmapping的情况,除非你设计的纹理尺寸比实际用到的要大很多。

模型的纹理资源的Mipmap一般是要开的。RTR第三版 18.3.1提到Mipmap可以提高纹理Cache连续性,即提升Cache的命中率,也提升了纹理采样的速度。另外开了Mipmap,可以在Mipmap level之间进行三线性滤波(当然这个是不建议开的),可以使纹理放大缩小的时候,看起来质量更好。因为在生成Mipmap的时候,Unity可以选择滤波算法,所以即使不开三线性滤波,在对应的Mipmap level上采样,也比在原来的大尺寸的纹理上采样效果要好一些。
感谢凯奥斯@UWA问答社区提供了回答

精彩回答2:凯奥斯已经回复得很全面了,想到的内容就补充一下好了。

1)了解一下各种压缩格式对应的设备OpenGL ES版本限制,这样方便你面对问题的时候做取舍,常规的建议终究只是立足于经验和项目的建议,个人根据自己项目需求的判断更加适用。

2)类似PVRTC的限制,和压缩方式有关,也和GPU采样效率有关。所以即便选择没有限制的压缩格式,甚至不压缩,PVRTC的限制都最好保持长宽为2的幂。

3)UI用PVRTC的确难以接受,主要还是Alpha通道的问题。大型项目可以考虑ASTC,另外的思路就是拆分Alpha通道、白名单内的贴图采用不压缩或者Alpha通道拆分的方式。

4)我们Loading图一般是对应的设备上的压缩格式,比如安卓ETC2、iOS上ASTC,其实Loading图一般不透明,PVRTC也够用了。尺寸按照UI需求一般是和设计分辨率一致。这个也完全看缩小之后的效果UI是否满意,Loading图注意及时卸载,只增加峰值,不常驻占用,内存影响不大,包体方面一般没这么敏感。

5)除了UI不用开Mipmap之外,比如一些2.5D的固定视角游戏有时候也不开,目的是追求清晰度;另外有些特殊的贴图也可以不开,比如染色用的Mask通道图等等,我们一些面部的贴图美术也要求关闭掉,这些从效果出发都可以满足,不一定完全按照固定的规则执行。
感谢贾伟昊@UWA问答社区提供了回答

精彩回答3:之前整理过项目里面几种纹理格式的特点,其实题主大部分也都提到了,就作为一个补充贴出来吧。其中画质是我个人的肉眼感觉,没有绝对的数据比较,仅供参考。

感谢喵小逗@UWA问答社区提供了回答

精彩回答4:能不能压缩,也需要考虑美术的感受。

最近手上的游戏2D序列帧用得比较多, 此时使用ETC2和PVRTC因为压缩的原因,会产生闪的问题。使用拆Alpha通道的方式可以一定程度上避免,特别是对于带Alpha通道的图,ETC2质量低的原因大半在于对Alpha的压缩。

ASTC的质量是明显好于PVRTC的,iPhone上唯一的问题是iPhone 5s的支持。我们的方案是,如果机型不支持ASTC,会额外准备一份低质量的PVRTC的资源,尺寸是原图的一半,而设计的主要目的是解决内存问题,顺带解决iPhone 5s的压缩问题。

感谢史亚征@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5c1a1bde4e577c207402d2c5


11、项目中策划数据如何储存和读取

因为项目中策划数据是生成二进制文件,最近发现在获取String值的时候消耗了大量的Mono堆内存(byte[] to string)。我尝试把所有的Excel数据转成ScriptableObject对象再打到AssetBundle中发现AssetBundle.LoadAsset()相比于byte[] to string申请Mono堆内存更大。请问大家项目中策划数据是如何存储和读取的,对于大量文本内容如何能尽量减小Mono内存的消耗?

精彩回答1:配置表二进制,ScriptableObject, CSV都是常用的方式,如果是Lua重度的游戏可能会直接把配置表转为Lua文件进行加载。加载配置表的时候Mono堆内存消耗大,一个可能是本身配置表数据量过大,再一个可能是同时加载的配置表过多,导致申请的Mono堆内存过大,而这个峰值上来了就降不下来了。

如果是本身配置表过大,检查下是否可以缩减一些冗余数据,再一个就是拆表,分步加载。另外就是注意在解析数据的过程中分配的内存,List,String等的复用来减少频繁分配内存。
感谢赵林@UWA问答社区提供了回答

精彩回答2:我们游戏用的是Lua文件来存储数据。确实会出现光数据就有60MB的内存。感觉还是使用一些db作为数据比较合适。用的时候去对应数据并缓存下来即可。而且一个玩家在玩的过程应该不会用到所有的数据,如果直接用Lua或其他文本文件,那就意味着只要用到其中一条,就把整个表都加进来了。
感谢halm@UWA问答社区提供了回答

精彩回答3:

  1. 不要将配置表打成AssetBundle包,这样不仅降低加载速度,也会产生大量的GC,毕竟有一次转化过程,而且增加了Mono内存;
  2. 少用序列化文件;
  3. 重点是我们要将配置表进行适时的加载,不要一次性加载,Streaming加载部分数据,降低读取整表需要的耗时和内存消耗。

感谢郑骁@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5c1d028fcbf84301a9dd1f03


12、半透明物体实现阴影效果的方法

当"RenderType" = "Transparent"的时候貌似是没有办法接受阴影的。我们需要在场景中做一层半透的地表, 来掩盖模型和地表之间的接缝,所以需要显示阴影, 请教各位大佬有什么好的方法吗?另外我想了解下为什么半透明物件默认不能接受阴影呢?

精彩回答1:抛开Unity引擎,从本质上说,半透物体肯定是可以接受阴影的。之前就实现过地表有一块玻璃材质,会在玻璃上以及下面的物体上都有投射的阴影效果。所以如果自己编写的Shader,想要接受阴影,只需要采样Shadowmap,走一下阴影计算的过程就可以了。

对于Unity引擎,我试了一下的确选择Transparent的RenderType也就没有了阴影,这个我不是非常清楚是否可以自己在Shader中去强制走一下Shadowmap的处理过程来解决,题主可以试下。

但是题主要注意,半透物体接受阴影的情况下,尤其是题主要解决的这种覆盖接缝的情况,会导致这部分最后产生的阴影变得比较重的效果,因为半透下面的物体肯定还会有阴影产生,半透的阴影虽然可以受Alpha的影响变淡,但是叠加在一起就会出现变得更暗的问题。当然Transparent的部分不接受阴影,意味着阴影效果经过Alpha Blend之后会变得淡。
感谢贾伟昊@UWA问答社区提供了回答

精彩回答2:这个问题恰好之前做了些尝试,正如@贾伟昊所说,内置的Transparent是不接受阴影的,但可以尝试在自定义shader中强制走Shadowmap的。参考代码如下:

Shader "Transparent/Diffuse With Shadows"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Alpha ("Alpha", float) = 1
    }
    SubShader
    {
        Pass
        {
            Tags {"LightMode"="ForwardBase" "RenderType"="Transparent"}
            ZWrite Off
            Blend SrcAlpha OneMinusSrcAlpha
            ColorMask RGB

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            #pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap novertexlight
            #include "AutoLight.cginc"

            struct v2f
            {
                float2 uv : TEXCOORD0;
                SHADOW_COORDS(1)
                fixed3 diff : COLOR0;
                fixed3 ambient : COLOR1;
                float4 pos : SV_POSITION;
            };
            v2f vert (appdata_base v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = v.texcoord;
                half3 worldNormal = UnityObjectToWorldNormal(v.normal);
                half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz));
                o.diff = nl * _LightColor0.rgb;
                o.ambient = ShadeSH9(half4(worldNormal,1));
                TRANSFER_SHADOW(o)
                return o;
            }

            sampler2D _MainTex;
            float _Alpha;

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                fixed shadow = SHADOW_ATTENUATION(i);
                fixed3 lighting = i.diff * shadow + i.ambient;
                col.rgb *= lighting;
                col.a *= _Alpha;
                return col;
            }
            ENDCG
        }
    }
}

但直接用这个Shader也还是没有效果…
因为文档里有句话,重点是粗体:
Only opaque objects cast and receive shadows so objects using the built-in Transparent or Particle shaders will neither cast nor receive. Generally, you can use the Transparent Cutout shaders instead for objects with “gaps” such as fences, vegetation, etc. Custom Shaders must be pixel-lit and use the Geometry render queue.

所以需要把Render Queue调整到2500:

然后效果就出来了:

该回答由UWA提供,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5b67b9851e88b37d34e651da


回顾三年多来,我们分享了近500个和游戏开发、优化相关的精彩问答。这些问答不仅有具象明确的提问,也有详细周全的解答;既能供研发团队自身项目中即学即用,还能通过参与者的回答分析,帮助我们在解决问题的过程中触类旁通、鉴往知来。如果你知道答案,欢迎你来分享;如果你有疑惑,欢迎你来提问。生有涯而学无涯,期待你的加入!

推荐阅读更多精彩内容