如何优化资源文件过多导致的安装变慢?

栏目: 后端 · 发布时间: 5年前

内容简介:这是第129篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间10分钟,认真读完必有收获。UWA 问答社区:answer.uwa4d.comUWA QQ群:465082844(仅限技术交流)

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

UWA 问答社区:answer.uwa4d.com

UWA QQ群:465082844(仅限技术交流)

资源管理

Q1:我们项目中资源文件有16000多个,导致在安卓手机上安装很慢。为此,我们分析了下其他游戏,发现他们会把所有的文件整合到一个大的文件,然后读取。

我们模仿写了个简单的文件整合,把所有的文件写入到一个大文件,然后通过记录的Pos和Length,Seek读取数据,发现很卡。想请教下,针对这种文件数量过多的,有什么好的解决方案么?

我们的资源大部分对应为Bundle,打成大文件,记录文件头和长度是可以的,但这里要注意两点:

1、不要释放句柄,避免重复开销;

2、public static AssetBundle LoadFromFile(string path, uint crc, ulong offset);Unity提供了AssetBundle读取时offset的接口,可以使用;

3、自维护表头文件提前读取,建立映射关系;

4、支持多文件表头映射,这样可通过分包提高iO速度。

感谢郑骁f@UWA问答社区提供了回答

不知道题主说的安装过程很慢,是apk的安装过程,还是安装好之后第一次启动游戏的资源拷贝过程?

我们游戏的AssetBundle文件的数量大约也有1万多个,也算是一个量级吧。我们在一些安卓设备上apk的安装时间是不快,但是因为这个只是给我们测试的时候带来一些时间上的影响,没有纳入玩家体验的统计上,所以目前并不知道具体花费多久。在安装好apk之后,我们没有选择解压,所以这块是没有时间消耗的。

整合到一个大文件,是一种常见的做法,不过我个人感觉是如果可以在C++底层直接做这件事情是最好的,相当于一套虚拟文件系统,而在C#层做这件事情,我觉得会比较绕,从而可能导致很多无意义的内存占用以及CPU消耗。一方面个人不太建议这来做,另外一方面题主也可以在Profiler里看下具体这块的消耗是在哪里,也许有提升和改进的空间。

如果想用一个大文件,基于offset的读取又没有发现优化空间,也可以考虑压缩成一块/几块大的文件,然后第一次运行的时候进行解压,不过感觉还不如安装时间稍微长一些。

另外,题主考虑下目前的包体有多大,尽量进行一些合理的合并,在控制Patch大小的情况下,也可以减少AssetBundle的数量。如果是1GB包体,接近2万个文件,平均每一个也就50KB,算很小了,合并到1万个AssetBundle文件左右,也就是100KB的均值,都是可以接受的。

当然,也感谢题主提了这样一个问题,让我注意到apk的安装时长和文件数量可能存在关系。

感谢贾伟昊@UWA问答社区提供了该问答

该问答来自UWA问答社区,欢迎转至社区交流:

https://answer.uwa4d.com/question/5b97b348670c1a61c64d6d65

Shader

Q2:我们项目中的Shader使用了Shader_feature,会产生多个变体。在编辑器模式下面运行一切正常。但是打包到Android上面,会出现Shader丢失的情况。 推测原因是,当AssetBundle打包的时候,我把Shader独立设置了名字,模型在收集的时候,没有管Material上面是否有宏的设置,导致这个Shader本身是被引用到了,但是模型却用的是变体导致丢失。

也尝试过其他办法,比如把Shader放入Always Included Shaders中,这样会导致编译漫长,包体变大,因为Shader所有的变体都会独立被编译一次放入apk包中,这样确实能解决问题。其次,也尝试过使用ShaderVariantCollection,版本是Unity 5.6.4p4,感觉没有效果,我在Collection中设置了需要的参数,然后将它和Shader一起打包,上真机测试后Shader还是会丢失,感觉就是完全没有生效。

最后尝试了一种办法,自己收集使用这个变体Shader的所有Material,然后把所有Material和Shader打成一个AssetBundle,这样就不会丢失,但是又有一个问题,如果我一个Material需要设置一个Keyword,需要一个新的变体Shader,如果当前打包的Material中没有产生这个Shader,那么同理也会丢失。

希望遇到过这个问题,或者有解决方案的朋友不吝赐教。

UWA:关于ShaderVariantCollection,这个问题里有一些讨论:

https://answer.uwa4d.com/question/5af11b260e95a527a7a81cf0

简单说,就是高版本(Unity 2018)能正常使用,其他情况下使用Dummy Material比较稳定。

至于“如果我一个Material需要设置一个Keyword,需要一个新的变体Shader,如果当前打包的Material中没有产生这个Shader,那么同理的也会出现丢失”这个问题,似乎也没有什么好办法,因为这种方式的缺点就是维护起来比较麻烦。

该回答由UWA提供

ShaderVariantCollection不仅可以自动收集,也可以手动设置Keyword,所以,首先要确认所有变体和美术使用到的所有变体,建议让美术使用前就限制好,避免后续发生问题。另外进行Shader代码分离,Lightmap相关Shader和角色分离,无Light和有Light分离,1个Light和2个Light分离,尽量通过代码减少变种,限制美术使用Shader的范围。

感谢郑骁@UWA问答社区提供了回答

该问答来自UWA问答社区,欢迎大家转至社区交流:

https://answer.uwa4d.com/question/5ba08012f31d7a33f3469a37

OpenGL

Q3:之前项目Android Graphics API一直是选择的强制OpenGL ES 2.0,近期想做优化就试着选择成了Auto。切完后,在大部分手机上都跑的正常,测试后性能也稍有提升,但现在遇到一个奇怪的现象。现象如下:

1)在OPPO R9, MEIZU m2e 两台手机上会发现特效会出现粒子乱闪、粒子被放大、粒子消失等多种奇怪现象,而且只有特效有问题,其他的画面表现都正常;

2)同样的资源,切换回之前强制的OpenGL ES 2.0下就是好的;

3)出问题的特效都是放到UI上的特效,包括纯UI面板特效,以及用RenderTexture方式实现的UI模型上绑的特效,同样的模型特效在场景上播放是正常的。

我们用的是Unity 5.3.6版本,想问下有没有人遇到过类似问题,或者哪方面有可能导致这个问题。

https://en.wikipedia.org/wiki/OpenGL_ES

OES_vertex_half_float是OpenGL ES2.0的一个扩展

感谢凯奥斯@UWA问答社区提供了回答

现在很多机型包括高端机都出现了精度问题,建议在可以使用float的情况下,使用float再逐步优化。

感谢郑晓@UWA问答社区提供了回答

结下帖,经过认真思考反复观察,终于发现了出问题特效的共同点:位置出现了问题,然后跑去看特效Shader顶点计算部分,发现大部分特效顶点的属性都只给了half精度,再对比了下场景特效和UI特效的区别,发现UI特效的世界坐标都比场景特效大很多,于是第一直觉是half精度在这些手机上出问题了,改half为float,重新打包验证,问题解决。

感谢题主提供了回答

该回答来自UWA问答社区,欢迎大家转至社区进一步交流:

https://answer.uwa4d.com/question/5b972198670c1a61c64d6d44

Shader

**Q4:Shader中,实际计算未使用的参数,是否会进入GPU,假如在一个如下Shader中。Property里面定义了一个贴图_MainTexture,并且有赋值。然后SubShader里面也定义了参数_MainTexture,但是实际运算流程并没有使用这个贴图。**

是不是CPU仍然会将该贴图推入显存,造成CPU和显存消耗?如果保持Property存在,但是不在SubShader中定义Sampler2D,是不是就可以避开这个消耗?

Shader "Test/DummyTex"
{
    Properties
    {
        _Color ("Main Color", Color) = (1,1,1,1)
        _MainTex ("Base (RGB)", 2D) = "white" {}
    }

    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100
        
        Pass {  
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata_t {
                float4 vertex : POSITION;
            };

            struct v2f {
                float4 vertex : SV_POSITION;
            };

            fixed4 _Color;
            sampler2D _MainTex;
                
            v2f vert (appdata_t v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }
                
            fixed4 frag (v2f i) : COLOR
            {
                fixed4 col = _Color;
                return col;
            }
            ENDCG
        }
    }
}

UWA:题主可以尝试将Unity的Shader编译成OpenGL或者DX的Shader看一看,我们以OpenGL ES 2.0为例。点击下Shader的Inspector面板里面的Compile and Show Code按钮,就可以显示了。我把题主给出的Shader编译GLES 2.0版本如下:

//////////////////////////////////
  //                              //
  //      Compiled programs       //
  //                              //
  //////////////////////////////////
//////////////////////////////////////////////////////
No keywords set in this variant.
-- Vertex shader for "gles":
Shader Disassembly:
#version 100

#ifdef VERTEX
attribute vec4 _glesVertex;
uniform highp mat4 unity_ObjectToWorld;
uniform highp mat4 unity_MatrixVP;
void main ()
{
  highp vec4 tmpvar_1;
  tmpvar_1.w = 1.0;
  tmpvar_1.xyz = _glesVertex.xyz;
  gl_Position = (unity_MatrixVP * (unity_ObjectToWorld * tmpvar_1));
}


#endif
#ifdef FRAGMENT
uniform lowp vec4 _Color;
void main ()
{
  gl_FragData[0] = _Color;
}


#endif

可以看到由于Unity的Shader代码中没有使用纹理采样,最终生成的GLSL也没有纹理采样的变量(被优化掉了)。所以在编译、使用这个GLSL代码的时候也无需给它指定一个纹理单元的变量。不会有纹理内存的开销。

另外,纹理在GPU中显存开销取决于有没有Shader使用它,并不是所有Shader使用纹理都会造成新的纹理内存开销。例如:ShaderA使用纹理A,之后ShaderB也使用了纹理A,那么纹理A并不需要上传到GPU两次,而是只需要一次就可以了。

该回答由UWA提供,欢迎大家转至社区进一步交流:

https://answer.uwa4d.com/question/5b9b55e5670c1a61c64d6dce

资源管理

Q5:请问Unity3D引擎运行时,如果我们使用的是采用了某个压缩格式的纹理,则纹理是在载入时解压并按照位图的RGBA32位的格式保存在内存,还是在内存中也是压缩格式的数据,并在提交渲染时由GPU自行解压并采样纹素。为何经常看到文章说GPU硬件支持某些图片或者视频流的压缩格式呢?这个处理流程大概是什么样的?

其实这是两个概念,图片压缩和纹理压缩(术语可能使用的不准确,请大神指正)。jpg和png这种是图片压缩,ETC、PVRTC、ASTC这种是纹理压缩。图片文件从硬盘读取到内存,解压缩成为纹理,再传给GPU,GPU再进行解压缩变成具体的RGB色彩值。如果没有开Read&Write,纹理会从内存中卸载掉。

感谢凯奥斯@UWA问答社区提供了回答

该问答来自UWA问答社区,欢迎大家转至社区交流:

https://answer.uwa4d.com/question/5b9c7a20f31d7a33f34699e9

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

官网:www.uwa4d.com

官方技术博客:blog.uwa4d.com

官方问答社区:answer.uwa4d.com

官方技术QQ群:465082844(仅限技术交流)


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Algorithms for Image Processing and Computer Vision

Algorithms for Image Processing and Computer Vision

Parker, J. R. / 2010-12 / 687.00元

A cookbook of algorithms for common image processing applications Thanks to advances in computer hardware and software, algorithms have been developed that support sophisticated image processing with......一起来看看 《Algorithms for Image Processing and Computer Vision》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换