UWA问答 | 博客 | 游戏及VR应用性能优化记录分享 | 侑虎科技 - lightmap
type: channel
link: https://blog.uwa4d.com/tag/lightmap/
items: 骨骼捏脸功能的实现方法
items: Unity中光照图错乱问题研究
items: 技术分享连载（八十）
items: 技术分享连载（七十六）
items: 关于Unity中的资源管理，你可能遇到这些问题

骨骼捏脸功能的实现方法
type: item
date: 2018-10-16T07:11:00+03:00
description: 本期我们聚集了这些话题：项目骨骼规范已经确定的情况下如何增加骨骼捏脸功能、网格重建定位、ScriptableObject加载速度分析、光照贴图和材质组合导致额外DrawCall... 这是第132篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群：793972859（原群已满员） 骨骼动画 Q1：我所在的项目的骨骼规范已经确定，cs骨骼和bone骨骼加起来有60根。现正在调研捏脸的方案，基本确定通过增加面部骨骼来进行捏脸。先描述下我对面部骨骼的理解，如有错误请大家指正。 增加的骨骼与原有的骨骼同时导出制作Avatar供骨骼动画使用，但是骨骼动画并不控制这些骨骼。玩家捏脸后的数据，也就是骨骼的缩放和旋转，直接应用到这些面部骨骼上，完成脸部的定制。实际应用到项目里，有如下几个问题： 1、现有项目中，导入时Optimize Game Object选项是勾选的，这样就无法在C#层拿到骨骼信息，Expose出来的骨骼是“只读”的，没办法把捏脸数据直接应用到运行时的骨骼上。 暂时只能通过“使用额外的未开优化的Avatar动态生成目标Mesh”的方法来绕过，不知道还有没有其他更直接的方法？ 2、已有的骨骼规范没有脸部的骨骼，如果要加上，就需要重新导出之前所有的动画。 有没有不修改现有骨骼的方案呢？ 头部和身体分离，不过接缝处可能会穿帮。 另外还脑洞了一个方案：专门为头部做GPU Skin。导入模型时做预处理，将头部的骨骼和权重添加Mesh的uv2和uv3上（代码里区分一下是否是头部骨骼，身体部分的全是零就好了），另存为asset。然后每帧传骨骼矩阵到Shader里，在vs里面修改顶点的坐标。不过这样会占用额外的带宽。 感谢凯奥斯@UWA问答社区提供了回答 接楼上，头和身体分离，QualitySettings->Blend Weights改成4，可以解决大部分接缝穿帮问题。其实现在游戏中，大部分头发也会有动画，所以头发也要分离。捏脸后的Mesh保存下来，在游戏中和身体拼接的时候，用保存的Mesh（大部分游戏脸部没有动作）。实际游戏中，并不需要我们捏脸时的骨骼。 感谢郑骁@UWA问答社区提供了回答 离线骨骼采样的时候不需要勾Optimize Game Object。等整合出脸了以后再，把脸型贴回去。或者只限定脸部的骨头可读写。 感谢马古斯@UWA问答社区提供了回答 该问答来自UWA问答社区，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5bbc2dba17780b3478091926 UI Q2：在Profiler中，我们能否看到重建的具体是哪些网格呢？ 目前我只能通过VB Uploads的大小来判断是否引起了网格重建，但是并不知道一个界面中哪些元素会引起网格重建。 这里我有个测试案例，image放进动态canvas和不放进canvas里，这个上传的绘制内容会有很大的变化，但是具体是哪些东西如果每个东西都去测试一遍，感觉很耗时。 用VB Uploads来判断重建可能不太直观，因为SkinnedMesh和粒子系统应该也会引起这一项的变化。 在UGUI里，网格重建分为两个部分：Rebuild和Rebatch。其中Rebuild是以UI元素为单位的，比如一个Image的Color改变了，那么这个Image就会发生Rebuild操作，开销是包含在Canvas.SendWillRenderCanvases中的，只要是改变了UI元素的顶点属性的操作都会引起SendWill的开销。至于是哪一个UI元素发生了Rebuild，从Profiler里确实是看不出来的。 而Rebatch是以Canvas为单位的，只要Canvas里有任何一个UI元素发生了变化（也包含位置变化），那么这个Canvas就要进行Rebatch，开销是包含在Canvas.BuildBatch和子线程中的Canvas.SortJob、Canvas.GeometryJob等函数中的。至于是哪一个Canvas发生了Rebatch，可以通过Canvas.BuildBatch函数来确定，在Profiler里选中Canvas.BuildBatch，然后在右侧显示相关的对象，里面列出的就是当前帧发生Rebatch的Canvas的名字，但这个Rebatch是由哪些UI元素的变化引起的，在Profiler里也是看不出来的。 该回答由UWA提供，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5bbb2aa217780b34780918ed 渲染 Q3：发现Unity内部的光照贴图分配方式…

Unity中光照图错乱问题研究
type: item
date: 2018-07-23T15:23:00+03:00
description: 本期聚集话题：Unity中光照图错乱问题研究；UGUI静态、动态画布； AssetBundle打包零冗余方法；AssetBundle依赖打包报错... 这是第121篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） Lightmap Q：我来分享下Unity项目中可能会引起光照图错乱的问题及其处理方式。 近期项目使用Unity 2017 版本升级后，团队中某些人的机器光照图总是不正确，而有的人是正确的。我们一开始怀疑模型资源的问题，检查了下资源和导出设置，是有些问题但不是引起错乱的原因，后来看到光照图错乱和正确的机器上，同一个模型的UV确实完全不一样。 后来终于确认原因并且可以复现：Unity导入模型会做顶点优化，顶点数并不是和Max 中一致但是面数绝对一致，重点是不同Unity 版本即使同一个模型优化过的顶点数也不一致（应该是算法不同的问题），顶点数不同自然光照图 UV 分布生成的也不同。所以比如在Unity 2017.3中导入一个模型并生成光照图，导出成Package并导入到 Unity 2017.4或者其它版本，会发现光照图 UV 错乱，因为重新导入的模型顶点和光照图 UV 都不同了。所以同一个团队中的美术同学一定要和开发人员使用相同版本。 这里有一个更隐蔽的情况：大家都使用同一个Unity版本，但是不同的机器依然会出现某些人光照图错乱的问题。表现正常的机器是由于使用低版本的Unity烘焙完光照图或者更新了别人烘焙完的光照图后，然后直接用高版本的Unity 打开这样是不存在问题的；如果同一个项目删掉Library后，再用高版本的 Unity 重新打开这时候就不对了。究其原因是因为不删除Library升级项目每个模型不会被重新导入，顶点数维持在老版本导入的结果，一旦删除Unity就会重新按照新版本来导入并生成顶点数，当然其实你在新版本中修改模型的设置，也会导致按照新版本来重新导入模型而发生光照图错乱。 以上就是所有原因，并可以轻松复现，结论就是： 1）建议团队中所有人使用同版本的Unity开发； 2）升级过程中需要删除本地的 Library 然后再用新版本Unity打开。 希望其它的朋友可以避过这个坑，在此感谢钱康来@UWA问答社区在查找过程中的帮助：） 感谢Yaukey@UWA问答社区分享了该经验，欢迎大家转至社区进一步交流： https://answer.uwa4d.com/question/5b4ed6e61e88b37d34e650a4 UGUI Q2：之前了解过UGUI的画布上的图片或者文字发生改变，画布会重新算一遍UV，重新合并图集，以达到减少DrawCall的目的，所以为了减少画布重新绘制带来的性能问题，我把经常变动的UI放到一个动态画布上，不频繁改变的放到静态画布上。这里产生了一点疑惑：如果我一个UI窗口制作成一个预设，这个UI有动有静的，那我是将这个UI放到静态画布上还是动态画布上好，这个怎么放？ 另外，不在同一个画布下面，UI之前的层级关系怎么处理？比如画布A放静态，画布B放动态，现在有一个UI叫C，放到A，一个UI叫D放到B；如果画布B是挡在画布A前面，但是我需要UI C挡在UI D前面，这种怎么处理？ 题主的提问里有些描述可能不太准确，下面先简单说一下：“重新算一遍UV”的操作是发生在Canvas.SendWillRenderCanvases这个函数中的，发生变化（改图片、改文本、改Alpha等）的UI元素越多，开销就越大，通过“动静分离”是优化不了这部分的开销的，这部分开销需要从控制变化频率来入手。 “动静分离”主要是用来优化Canvas.BuildBatch的开销，这部分开销产生的原因是：当某个Canvas里任何元素发生任何变化（图片、文字、alpha、位置、缩放等等…）的时候，该Canvas就需要进行合并Mesh的操作。如果Canvas比较复杂，耗时就会比较高。 而在进行“动静分离”时，理论上是需要根据Canvas的复杂度来规划的，个人觉得Canvas的总顶点数可以作为一个简单的指标。以下用几个例子来说，可能比较直观一些： 对于一个常见的MMO项目来说，常规做法是会把技能面板，任务面板独立划分Canvas。其中，技能面板即使是在读CD的时候，一般来说顶点数也不太会超过1000个，UI元素数量也不会太多，所以即使这个面板里有动态元素，也有静态元素，但其实不太需要“动静分离”，因为这样的面板BuildBatch的开销不太明显。 而任务面板中，由于条目比较多，产生的顶点数通常也会很高，2000以上也是很常见的，所以这个面板里如果…

技术分享连载（八十）
type: item
date: 2017-09-26T11:17:00+03:00
description: 本期聚集话题：LightingDataAsset Delete后Lightmap展开问题、Gamma和Linear颜色空间问题、AlphaTest和Alpha Blend的性能差异... 我们将从日常技术交流中精选若干个开发相关的问题，建议阅读时间15分钟，认真读完必有收获。如果您有任何独到的见解或者发现也欢迎联系我们，一起探讨。 UWA QQ群：793972859 UWA 问答社区：answer.uwa4d.com 制作 Q1：我这边做了个测试，把场景中的物件进行StaticBatch，用Lightmap烘焙，并且在烘焙完记录每个物件Renderer的lightmapindex and offset，然后在运行中，我删除了生成的LightingData.Asset，自己设置了Lightmapsetting，并且恢复了每个物体Renderer的Lightmapindex and offset, 结果我发现烘焙出来的场景Lightmap还是不对的。我怀疑是不是LightingData.Asset 还记录了别的东西，想问问看UWA有没有什么经验呢？ 我在answer.uwa4d.com上打包一个测试用例，打开Scene/LightMapTest.unity 这个场景即可。 这个问题还是出在Static Batching上。经过测试我们发现如果去掉场景中物件的“Static Batching”标记，换成手动Batching，即采用StaticBatchingUtility.Combine的方式结果就正确了。 同时，我们发现使用LightingData.Asset时，开启Static Batching与不开启都正确，因此我们认为LightingData.Asset可能记录了与CombinedMesh有关的数据，导致如果仅仅使用gameobject的LightMap参数无法正确读取CombinedMesh的LightMap UV。另外一种可能是Unity的一个Bug。 最后，我们建议采用上述手动Batching的方式，即可解决此问题。 该问题来自UWA问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/59c0d16c5cd7219d3bbfb3b3 制作 Q2：我们场景中有两种Unlit物体，一种是在脚本中通过Mesh顶点色（Mesh.colors）赋颜色值，一种是用Shader属性传递颜色值，在Gamma颜色空间时两种物体的渲染颜色是一致的： 但是切换到Linear空间发现不一样了，如下图，左边是顶点色，右边是Shader属性颜色： 顶点颜色和属性都没改过，只是切换了颜色空间，请问是什么情况？ 我能想到的有两种可能性： 1）顶点色的颜色值在Shader中没有被正确处理； 2）右边使用贴图的导入设置中sRGB的选项有错误。 看上去左边的在线性空间下变亮了，而右侧的方块颜色在两种Space下差别不大，因此推测第一种的可能性比较大，顶点色在很多情况下并不被当作颜色处理，而作为值来存储，所以有可能这里处理有问题。至于为什么变亮了，感觉是值经过了伽马校正变大了。 Unity有接口在两种颜色空间下转换，建议题主可以查一下，在Shader中修改代码来排查下是哪里的问题。 该问题来自UWA 社区，感谢贾伟昊提供了回答，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/59c387de79a00b1e16da7414 UI 制作 Q3：当使用Linear设置时，UI上图片透明度等也跟着变化，出来的效果与美术人员的需求不一样。请问有什么办法可以让UI不使用Linear或者让UI可以在Linear影响下也正常呢？ 推荐题主可以看下这个帖子 https://forum.unity.com/threads/bug-with-bypass-srgb-sampling.282469 “When switching to linear mode it (greatly) changes how blending works, this is because when sampling only the rgb channels are linearised as it is assumed the alpha is a linear scale representation already.” 简单说，这是正常现象，里面有三种解决方法： 1）改资源的 alpha 通道： Reauthor the content for linear blending (this is supported in photoshop). …

技术分享连载（七十六）
type: item
date: 2017-08-22T04:54:00+03:00
description: 本期我们聚集了这些话题：GameObject.Active耗时、Font.CacheFontForText开销过高、Unity 5.X下烘焙Lightmap的UV缩锁定... 我们将从日常技术交流中精选若干个开发相关的问题，建议阅读时间15分钟，认真读完必有收获。如果您有任何独到的见解或者发现也欢迎联系我们，一起探讨。 UWA QQ群：793972859 UWA 问答社区：answer.uwa4d.com 性能优化 Q1：Unity对GameObject.active()这个底层具体做了什么？因为在优化项目的时候看见有些界面active()这个函数造成的开销比较高，我采取的办法是移除摄像机的范围，这是参照UWA以前文章找到的办法，但是我还是想知道Unity对Active底层具体做了哪些操作，否则会有点困惑。 有一点可以明确的是，至少SetActive后，如果GameObject被激活，那么会调用该GameObject和所有子GameObject上的所有组件的OnEnable函数。而各种不同的UI组件的OnEnable中也有各种不同的操作。 如果题主希望深入研究下，可以看一下NGUI或者UGUI的源码，OnEnable具体做了什么都可以看到。同时，针对UI界面而言，还会在同一帧里触发其他的相关函数，出现后续的开销，如UGUI里的SendWillRenderCanvases和NGUI里的UIPanel.LateUpdate。 该问题来自UWA 社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/5996b23886e632f11f9c1582 资源管理 Q2：还是老生常谈的昼夜变换效果，需要两份Lightmap来lerp。开始我认为，只要模型不变，烘培参数不变，如果只改变灯光，Lightmap的分布是一样的（事实上开始测试的几个小场景也的确没问题）。但是在某个大场景烘培2份LM的时候，发现部分物体UV2分布的位置变了。请问，在不手动分uv2的情况下，是否有办法锁定UV2分布？因为资源量比较大，美术人员不希望手动分UV2。 根据我的实践结论，如果场景物体没有移动，没有改变过Lightmap Scale，光罩面板里的分辨率等参数也保持不变，只是灯光位置和参数发生了变化，那么是不会引起物体的光照Index和Scale 这两个参数的变化。但是为了避免多次渲染，最好连续为不同光线条件进行渲染，以防无意移动了某个物体，造成整份渲染无用。另外手动保存Index，Scale两个参数好像也是无效的，因为如果缺少场景同名文件夹内的Lightmapping Asset的那个光照文件，场景光照贴图就无法加载，而且通常我们场景内的物体是要批量静态的，而批量了后的物体是无法手动赋值Index和Scale这两个参数的。 实例：我的项目中 这三套光照贴图都是公用一套"UV"的，在编辑器中还可以自己写个Editor脚本来静态加载调试。 此问答来自于UWA 问答社区，感谢 ID为 Blandon 的朋友提供了相关回答，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/5992e3aae85f22ea2dc0c603 资源管理 Q3：我们在iPhone5c上测试时发现Font.CacheFontForText会造成很严重的卡顿，看了UWA的Blog，了解到可能是因为创建FontTexture导致的开销。那是否可以认为如果我们一开始申请了足够大的Font Texture，后面即便有新的文字，开销也不会很大？ 如果可以这么做，一开始申请使用的字符串是根据自己项目生成一个字典，还是直接使用网上3、4千字的常用字库更好？ 是的，如果Font.CacheFontForText开销较大，那么在无法降低字体数量的情况下，一开始增大Font Texture是较为可行的方法。建议根据自己项目的字体来撑大Font Texture，避免不必要的浪费。 同时，也建议看一下这篇关于字体的精简优化方法。 此问答来自于UWA 问答社区，如您对该问题仍有疑问，可以转至社区进行进一步交流。 https://answer.uwa4d.com/question/59917a6e1ae4fee75dc97e3d 资源管理 Q4：有什么办法可以获取到MemoryProfiler里的Other那项里面的Objects和SerializedFile的详情信息呢？ 目前Unity引擎是没有API来获取这两处的详细信息的。 不过，对于Objects的大小，一般来说不需要去特别注意，因为在真机上是没有的。 而SerializedFile下面主要是AssetBundle的具体使用…

关于Unity中的资源管理，你可能遇到这些问题
type: item
date: 2016-11-08T16:28:00+02:00
description: 关键字 AssetBundle 资源制作 纹理\网格\材质\Shader\音频\动画 Lightmap 一、AssetBundle 相关 Q1：Unity中的SerializedFile是怎么产生的？请问用Unload(false)可以清除吗？因为读取了Bundle里面的内容后已经赋值给其他物体了。而且我把图片都打成了Bundle，然后读取出来，图片的大小应该是超过了这个SerializedFile的大小的？ SerializedFile是AssetBundle加载时产生的序列化信息，一般为LoadFromCacheOrDownload、LoadFromFile和New WWW加载本地AssetBundle文件所致。如果AssetBundle中的资源已经加载，且后续没有依赖该AssetBundle的资源进行加载，那么可以通过Unload(false)将其删除。SerializedFile中记录的是AssetBundle的序列化信息，而不是其包含资源的内容，因此，其大小要小于或远小于资源的实际内存。 Q2：我们现在采取了2种资源管理方式， 我想了解下内存占用问题。 方式A：AssetBundle加载好以后在内存中保留， 如果需要创建对象就通过Instantiate来创建。方式B：AssetBundle加载好以后立刻通过Instantiate实例化一个对象， 然后Unload（false）这个AssetBundle，如果需要，创建对象通过clone来完成。对于方式A，在Profiler中发现 WebStream中有相关AssetBundle文件存在， 我们认为这份内存是多余的, 所以就采取了方式B， 方式B又面临资源卸载不干净的情况。想确认一个问题， 如果采取方式A： 一个 xxx.assetBundle原始文件大小是 1MB， 解压到Webstream内存中是2MB， 最终实际内存占用是2MB 还是3MB 呢？ 如果采取方式A：最终实际内存占用是2MB，而不是3MB，WebStream中已经包含原始AssetBundle的数据。对于没有依赖关系的AssetBundle文件，我们推荐方式B的形式对AssetBundle进行卸载，这样可以免除不必要的内存占用，对于这种方式加载出来的资源，可以通过Resources.UnloadAsset和Resources.UnloadUnusedAssets来进行卸载，如果无法卸载，则该资源一定被缓存了，研发团队可通过检测自己的缓存池/Constainer来进行检测。同时，如果是Unity 5.3以后版本，可尝试通过Memory Profiler来进一步查看。 Q3：打包时候AssetBundle的md5总变化(被打包的东西没变)，请问能怎么解决？有说法是加上DeterministicAssetBundle就可以，但是我尝试后发现md5依然变化。 该方法确实并不受用。对于Unity 4.x版本的AssetBundle文件，其md5值在某些情况下确实会前后不一致（哪怕是完全一样的内容进行打包）。对于该系列版本，仅能建议开发团队建立配置文件来对AssetBundle进行管理。 而对于Unity 5.x版本，则可以在打包时开启 AppendHashToAssetBundleName 选项，这样Unity引擎会在每个AssetBundle文件后生成一个唯一的HashID（显示地放在文件名后），开发团队可以通过该ID来判断对应的AssetBundle文件是否发生改变。 Q4：如果采用依赖打包的话，比如NGUI，图集A作为被依赖包，界面1、2、3作为独立包，分别依赖打包。当图集A重新打包的时候，是不是界面1、2、3也都要重新打包？目前我们是界面打包时清空全部的图集信息再打包，在客户端加载后再动态赋值回来。这样可以实现单独更新图集，但是代价就是加载的性能。请问有什么更好的解决方案呢？ “当图集A重新打包的时候，是不是界面1、2、3也都要重新打包”，这是不需要的，Unity 4.x的依赖打包的限制在于，在重新打一个包时需要将它依赖的包都重新打一次，但不需要重打依赖它的包。 Q5：请问内置的shader怎么打包？我用到了内置材质球，不只是Shader，这时候在Profiler中看到加载的结果中会出现多份，如下图所示 通常有两种方式对内置的Shader进行打包： 将其添加到Graphics Settings中的Always Included Shaders 中，此时添加后的内置Shader就不会被打入AssetBundle包中； 在http://unity3d.com/cn/get-unity/download/archive下载内置的 Shader，将其导入项目，并替换成非内置的材质球，从而可以直接通过脚本来控制其…