角色固定部位闪白的实现方案

角色固定部位闪白的实现方案

1)角色固定部位闪白的实现方案
2)LoadFromStreamAsync加载报错
3)Separate Axes设置的影响
4)特效在贴近摄相机时明显变卡
5)不透明渲染开销中的粒子耗时


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

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

Rendering

Q:前提:有一个3D模型,只有一个Skinned Mesh Renderer,只用一个Material。我想实现在运行时,左手部受击,左手部闪白效果。整个模型闪白效果已经简单实现了,针对局部闪白效果,现在想到的有3种方案:

1、出一张局部遮罩图,与UV对应,如:这张图只有左手部分是黑色的,其它部分是白色的。修改Shader,可以用这张图与MainTex做运算,实现运行时修改左手部分颜色。
2、建模时在左手刷顶点颜色,Shader加入顶点颜色处理。
3、建模时不刷顶点颜色,但是在运行时用脚本修改左手上所有顶点颜色,也是要修改Shader加入顶点颜色处理。

想用第3种方案,但是有一个问题,怎么能在运行时高效修改模型指定部位的所有顶点颜色?网上有一种方法,通过指定bone来修改,如下:

void Highlight(Transform bone) {
        Debug.Assert(smr != null);
        var idx = GetBoneIndex(bone);
        var mesh = smr.sharedMesh;
        var weights = mesh.boneWeights;
        var colors = new Color32[weights.Length];

        for (int i = 0; i < colors.Length; ++i) {
            float sum = 0;
            if (weights[i].boneIndex0 == idx && weights[i].weight0 > 0)
                sum += weights[i].weight0;
            if (weights[i].boneIndex1 == idx && weights[i].weight1 > 0)
                sum += weights[i].weight1;
            if (weights[i].boneIndex2 == idx && weights[i].weight2 > 0)
                sum += weights[i].weight2;
            if (weights[i].boneIndex3 == idx && weights[i].weight3 > 0)
                sum += weights[i].weight3;

            colors[i] = Color32.Lerp(regularColor, highlightColor, sum);
        }

        mesh.colors32 = colors;
    }

这只是指定一个bone的,但是模型的一个部位有很多个节点,如:

一个手臂有这么多。上面的方法计算量有点大。请问有更好的方案可以实现修改指定部位颜色的需求吗?

A:优化的常规思路就是空间换时间,如果你要采用第三种方法,而且每次闪白的位置固定,可以把要闪白的顶点离线存储下来,或者运行时计算过一次存储在内存中。

个人感觉,如果题主需求下闪白的位置是固定的,那第三种方法未必是一种效率最好的方式:

1、如果要运行时修改,Mesh需要可以读写,内存会占用两份;
2、运行时修改的Mesh,每次修改之后都要重新提交给GPU,这也会占用一些时间和带宽;
3、如果网格较为密集,顶点数量较多,这种计算本身就更加适合GPU去做,除非你明确是GPU瓶颈,要优化到CPU,常规思路下是不太推荐的。

第一种方法多一张贴图的内存消耗,也多一次采样过程,但是可以控制得更加细致,尤其在顶点较为稀疏的情况下;第二种方法减少了贴图的消耗,增加一些顶点的数据,个人感觉已经是一种很不错的做法了。

运行时修改顶点色,我能够想到的就是为了方便控制区域,比如:不固定的任何区域都需要有各自亮起来的需求,这样要根据受击或者攻击的触碰位置来做计算,固定的情况下,我觉得还是离线做好数据比较好。

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


加载

Q:我们最近为了AssetBundle包加密,使用了LoadFromStreamAsync接口加载,Unload(true) 卸载,并使用了C#的FileStream作为二进制文件的读取方式,但是在Android手机上资源一加载多了就会报Too many open files错误,如图所示:

我们的FileStream是在AssetBundle卸载的时候释放的,释放方式如下所示:

mFs.Close();
mFs.Dispose();
mFs = null;

同时我们用adb shell ulimit查看了手机的句柄上限是1024,我们当时加载的AssetBundle数量是500左右,在网上没有找到类似的信息,想问下有没有人遇到过类似的问题,感谢。

补充:我们用adb看了进程实际使用的句柄,并与之前使用LoadFromFile不报错的包做了对比,发现每个AssetBundle都多出来一个句柄,而之前的方式是没有的。现在我们的FileStream流是在Unload以后释放,是否应该在加载完成后就释放?但是这样,后续再加载这个AssetBundle里的东西就会报错,下图是多出来的句柄的截图:

A1:建议使用 LoadFromFile 测试,看是否有问题。这里是使用 LoadFromFile + File offset 加密的方案,可参考Unity AssetBundle高效加密案例分享

4.5.4. iOS file handle overuse
Current versions of Unity are not affected by this issue.
In versions prior to Unity 5.3.2p2, Unity would hold an open file handle to an AssetBundle the entire time that the AssetBundle is loaded. This is not a problem on most platforms. However, iOS limits the number of file handles a process may simultaneously have open to 255. If loading an AssetBundle causes this limit to be exceeded, the loading call will fail with a “Too Many Open File Handles” error.

This was a common problem for projects trying to divide their content across many hundreds or thousands of AssetBundles.

For projects unable to upgrade to a patched version of Unity, temporary solutions are:

Reducing the number of AssetBundles in use by merging related AssetBundles

Using AssetBundle.Unload(false) to close an AssetBundle’s file handle, and managing the loaded Objects’ lifecycles manually

Assets, Resources and AssetBundles - Unity Learn
感谢狂飙@UWA问答社区提供了回答

A2:可以先加载完就释放FileStream流试试,看看句柄数是否减少。但我个人认为很可能是LoadFromStream本身就会产生2个句柄,不过没有做过测试,题主可以试试看。

LoadFromStream现在用的团队已经非常少了,一般都是用于加密所致,但是否确实需要对每个AssetBundle都加载,这个需要研发团队考虑一下了。同时,如果LoadFromStream确实需要,那么后续可能最为现实的方式就是减少内存中驻留的AssetBundle数量了。

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


Particle

Q:这个问题是项目从Unity 5.6升级到2018时发现的,目前怀疑是Unity 2017/2018引入的粒子系统Bug。

发生了什么:

1、使用的版本是Unity 2018.4.9 LTS(测试了Unity 2017 LTS也会出现同样的问题,而Unity 5.6是正确的);
2、粒子由两层组成,back是triangles的一个sub-emitter(继承了size),勾选了Size over Lifetime,但只给了一个常数(一条1.0的直线);

triangles

  • back

3、若不勾选|Separate Axes|,则一切正常,画面显示为三角形粒子带着一个正方形的背景,符合预期(见图中蓝色粒子);

4、若勾选|Separate Axes|,并且将三个轴都设置成一条1.0的直线,画面显示为三角形粒子带着一个很扁的矩形背景,完全不正确(见图中红色粒子)。

按照我的理解,是否勾选|Separate Axes|不应该会影响显示结果,因为三个轴都设置同样的曲线(1.0的直线)。需要说明的是,这个情况仅当back是triangles的sub-emitter才会发生,如果是独立的ParticleSystem,简单测试下来行为是正确的(显示均为正方形)。

如何重现:

  • 下载附件中的Any3D工程(可在原问答获取)
  • 打开Scenes/SampleScene场景
  • 点击'Play'即可重现
  • 场景中蓝色和红色粒子有且仅有Separate Axes设置不同,其它设置都完全相同

希望得到大家的帮助,看看是否是哪里设置错了,或者如何避免这个问题。感谢不尽!

A:把back_red的3D Start Size勾上,发现X和Y轴缩放不一样,如果都改成2就好了。同样把back_blue的3D Start Size勾上,发现效果和back_red一样了。个人感觉3D Start Size和Separate Axes起同样的作用,所以要保持一致。

感谢一天到头困来的@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5d84a37391262623a9fc76ff


Optimize

Q:自由视角游戏,某些技能离Camera较远的时候看正常,但当Camera贴近特效中心的时候,游戏整体有很明显掉帧的情况,而在Profiler中却未发现有什么明显的异常。请问可能的原因会有哪些?

A:很可能是GPU端的计算压力太大,靠近特效时,Overdraw一定是大幅增加的。

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


Particle

Q:如图所示,这样的情况是正常的吗?以我的理解粒子的开销是在Render.TransparentGeometry之下的,为什么会在Render.OpaqueGeometry这里也有体现?这说明了什么问题呢?

A:这个和你的粒子的材质的Render Queue有关;queue是Transparent,那自然就是在 Render.TransparentGeometry下,queue是Geometry,那就在 Render.OpaqueGeometry下了。

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

封面图来源:Volumetric Lighting


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

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