Linear Rendering在移动设备上的支持率

Linear Rendering在移动设备上的支持率

本期我们聚集了这些话题:Linear Rendering的支持率、通过蓝图/C++在运行时修改MeshData粒子系统的Mesh、PSS增长定位、优化Lua逻辑代码产生的内存...


这是第135篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间10分钟,认真读完必有收获。

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


渲染

Q1:在此篇博客里,有提到Linear Space Color这个特性在安卓机上的支持率是61%,在苹果机上是71%。
不过这个数据是2016年的数据,已经不适用于现在了,我们希望能知道Linear Rendering这个特性在现在安卓机和苹果机上的支持率,当然,如果能区分地区(例如大中华区和东南亚各自的支持率)和更加细节(例如OpenGL ES 2和OpenGL ES3占有率、Vulkan支持率、iOS Metal的支持率等)就更好了。

另外,如果我们在Gamma颜色空间下,使用PBR流程制作手机游戏想要有更好的表现效果,有什么好的策略和方法吗?现在我们使用的是Metal-Roughness贴图,Shader是参考下面这篇博客,修改Standard的Shader代码写成的。

占有率这个东西,不同的统计渠道可以得出不同的统计结果,我这里没有具体的数据,只能提供个人的建议——2019年上市的3D游戏,除非特别小型,在国内市场,我个人认为是不用去考虑OpenGL ES 2.0的设备了。三四年前的千元机已经支持OpenGL ES 3.0了(比如红米Note2、小米2A),何必为了这点市场份额而额外增加那么多限制呢?(Alpha通道拆分、自己在Shader中做线性空间处理、Shader要注意贴图采样数量限制等等)
另外大致看了下题主贴的文章,其实是在Gamma的设置下自己在Shader中实现Linear Space的计算过程而已,这种方式有两个小问题:
1)增加GPU额外计算量,比基于硬件的方式消耗更大一点点;
2)最终的从线性空间转换到伽马空间的过程,注意最理想的是在最后一步来进行,如果有多个Pass,这里的计算过程在效果上可能有错误(单个Pass,没有后处理的情况下看上去是一致的)。当一个Pass输出的颜色会作为下一个Pass的输入时,也要将颜色转换回线性空间来计算才正确。
还有就是不仅仅albedo贴图,所有是颜色的贴图/通道都需要做这样的计算才是正确的。
使用链接中的方式可以实现线性空间的效果,比较老的游戏也通常是这样做的,但是我个人会倾向于直接使用Unity内置好的功能,性能上和便利性上都会更好一些。
另外,个人观点,基于PBR流程的话,在做好基准效果之后,程序能做的事情不多,毕竟都是物理计算的,后面的效果大都依赖于美术对于PBR的理解以及制作经验了。
感谢贾伟昊@UWA问答社区提供了回答

最近项目刚切到线性空间去,查了些资料,Linear Rendering需要支持OpenGL ES 3.0 ,Android版本参考4.3, 以下是一份Android版本参考数据,参考版本数据大致可以推出占比 :
https://blog.csdn.net/qq_29428215/article/details/80847211
iOS参考iOS 7的iPhone 5s。
经过我查看的资料和调研,我跟楼上观点一致,直接切线性空间。
感谢赵林@UWA问答社区提供了回答

该问答来自UWA问答社区,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5bd7df711ea0b505053cc4ee


逻辑代码

Q2:控制Lua逻辑代码产生的内存,如何回收才能避免内存峰值过大?
C#和Lua都可以在回收的时候被标记为null,从UWA报告中的曲线可以看出,C#的回收机制是一段时间自行回收,Lua却没有,可以理解在堆内存管理上是有区别的?如果避免这样的内存泄露问题,控制内存暴涨,有什么更好的回收方法?
请输入图片描述
请输入图片描述

补充理解:
手动回收内存:Lua内存回收调用Collect,C#调用GC;
自动回收内存:C#申请的内存置空或Clear可以回收掉,而Lua描述中也是置空可以让其自动回收,但是下面的Lua变化曲线没有锯齿线的变化,这有点不明白了,是否我理解错了?

自动回收的说法可能有点问题,Clear或者置空只能认为是解除对对象的引用,并没有回收对象的内存。
回收的时间点总是发生在GC时的,只是有些是手动调用的,有的是自动触发的。上面C#和Lua的曲线不同,应该只是GC触发的规则和时间点不同(C#的频率高,而且每次是全量的GC,一次性回收;Lua的规则会复杂些,而且还可能是分代的)。
然后也可能是C#层的堆内存分配的比较快,量比较大,所以看上去GC就比较频繁了。
调用Collect是可以触发回收的,通过lua_gc的第二个参数还能控制是否分步进行。不过从曲线上看,Lua部分的内存有泄漏的风险,才会出现峰值越来越高的现象,所以建议还是先尝试定位下泄漏问题。
该回答由UWA提供

避免内存峰值过大,如果只是交给自动GC很难满足。
一般来说,是结合手动触发GC,甚至设置合理的步进。在一些特定的场景,比如说战斗场景,在内存准许的情况下还可能采用的策略是停掉自动GC以防止自动GC引起卡顿,然后出来场景做一次手动全回收并且开启GC。
防止内存泄露同样是要特别注意的问题,比如说Local不小心处理成了Global无法释放,被table表强引用等情况导致无法释放,导致内存占用越来越大。
感谢赵林@UWA问答社区提供了回答

该回答来自UWA问答社区,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5bdbb80f73c493238df34080


虚幻&粒子系统

Q3:求助虚幻4大佬们的帮助:
1)有可能在蓝图中或者C++中对粒子系统的Mesh进行修改吗?
请输入图片描述
2)或者说有可能把蓝图创建的Procedural Mesh赋值给粒子系统的Mesh吗?
Procedural Mesh的创建方法参考的是:

http://orfeasel.com/creating-procedural-meshes

回答如下:
1)首先,题主要先确定需要Runtime修改的是单个ParticleSystemComponent实例的Mesh还是整个ParticleSystem(资源模板)的Mesh。两者都比较容易达成,引擎在渲染动态对象的时候,会每帧通过PrimitveSceneProxy的GetDynamicMeshElements收集实际的MeshBatch,ParticleSystem会根据Emitter的实际Instance类型,调用对应类型的GetDynamicData获取需要的数据。所以只需要给ParticleSystemComponent添加接口暴露给蓝图,用来设置新的StaticMesh,并且在接口实现中,传递给实际的FParticleEmitterInstance,FParticleEmitterInstance基类中新增SetMesh的接口,什么都不做,在继承类FParticleMeshEmitterInstance中,增加UStaticMesh*类型的成员变量,作为PerInstance的override用的Mesh数据,重载基类的SetMesh接口中把传入的Mesh复制给自己的Override用的Mesh,并在FParticleMeshEmitterInstance::GetDyanmicData接口最后NewEmitterData->Init的第三个参数改成 EmitterInstanceMeshOverride ? EmitterInstanceMeshOverride : MeshTypeData->Mesh。至于要改整个ParticleSystem模板的Mesh就更简单了,直接在SetMesh接口中换掉自己MeshTypeData->Mesh就行了。要做的完整需要对resourcesize,getmaterials以及计算bounds的相应接口做一些简单的调整。

2)用ProceduralMesh会比较麻烦,当然也不是不行,但这里有一些概念题主需要清楚:普通的StaticMesh是Assets,而实际的Component可以看成是使用某种Assets的实例。所以在Mesh Data中设置的其实是资源,在实际生成实例的时候,会利用资源的数据来生成对应的数据。而ProceduralMesh比较特殊,并不存在资源,只存在实例,如果想实现需求,需要把ProceduralMesh的各种stream(position,normal,tangent,vertexcolor等)转成Particle的FMeshParticleVertexFactory中的实际数据格式,参考FMeshParticleVertexFactory::FDataType和ProceduralMesh中对应的数据的结构关系。

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


内存

Q4:请教个问题,内存快速增长该如何确定是哪些导致的?我们的UWA测评报告中显示切场景的时候多了差不多两百兆。
请输入图片描述

UWA:这个是PSS内存增长,这块内存的进一步定位有两种方式:第一种是在UWA GOT Assets模式中,查看主流资源(纹理、网格、RenderTexture等)的增幅情况;第二种是传到UWA网站,进行线上深度测评,通过线上报告除主流资源外,可以进一步看到此处的提升是Unity自身增长,还是Gfx增长,如果是前者,则根据AssetBundle加载相关,如果是后者,则跟Texture、Mesh、ShaderLab相关,这样就可以比较清晰地定位了。
但是,需要注意的是,PSS的内存增幅要快于Unity引擎的实际内存增幅,即App中加载一个4MB的纹理,引擎增加的记录是4MB,而PSS可能增加6MB、8MB甚至更多,这个是由其OS和Driver来决定的。

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


内存

Q5:Unity 5.6.6版本下,在PlayerSetting中改变了Logo和背景,如图一直在内存中 ,请问该如何处理呢?
请输入图片描述

UWA:恰好整过一样的问题,当时绕过的方法是在首场景中添加一个脚本,然后把splashimage挂上去,在这个脚本的 Start 中通过 Resources.UnloadAsset() 把 splashimage 卸载掉,后续应该就不会再出现了。题主也可以一试。

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

今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。

官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
官方技术QQ群:793972859(原群已满员)