Unity3D游戏在启动时都默认加载哪些资源

我们都知道使用Unity3D引擎制作的游戏在冷启动时会加载一些默认的资源,包括纹理资源、Shader、Mesh等,这些资源都是Unity3D引擎默认需要的。
那么我们如何知道这些默认资源到底是哪些呢?为了深入理解这个主题,我们把这个问题分解成以下两个子问题:

  1. Unity3D引擎会包含哪些默认资源?
  2. Unity3D引擎在从冷启动到开始加载第一个场景(Scene)时,需要加载哪些资源呢?

第一个问题也就是游戏的包体中会包含哪些非用户添加的资源,这些资源是Unity3D引擎自动添加的资源,最终也会打包进游戏里面,占用包体大小。
第二个问题是游戏在运行时,从用户点击游戏开始冷启动,到显示启动屏(Splash Screen),直到开始加载第一个游戏场景前,Unity3D引擎需要把哪些资源加载到内存中?我们称之为冷启动时需要加载哪些资源,这些冷启动需要加载的资源直接影响游戏的冷启动时间。

Unity3D引擎会包含哪些默认资源

分析这个问题,我们可以用Unity3D创建一个新的空工程,只有一个场景,场景上不挂在任何GameObject(把默认添加的MainCamera等删除掉)。这样的空工程可以保证工程里面没有任何用户引入的资源,保证工程的干净,方便我们分析。然后,我们可以导出一个Android的APK包。
这个APK包已经是Unity3D引擎最小的包体大小了,我们可以看到这个包体仍然有 21.5MB 之大,而我们使用AndroidStudio创建一个空的工程,导出的APK只有 1.8MB ,相比而言,Unity3D的包体还是蛮大的。
APK就是一个zip压缩包,把后缀 .apk 替换为 .zip ,就可以把APK包解压出来,从包体里面我们就可以看到有哪些资源了。如果你使用Mac,那么你可以使用 tree 命令来得到如下的图示:

我们可以看到 assets/bin/Data/ 目录下面有Unity3D引擎的 .dll 文件,以及 lib/ 目录下的 .so 文件,这些都是Unity3D引擎的代码文件,剩下的那些就是Unity3D引擎引入的资源文件。我们重点关注上图中划红线的 unity_builtin_extraunity default resources 这两个文件,它们在文件大小上是资源文件中最大的。
从文件名的命名上我们可以猜想这些应该就是Unity3D引擎引入的默认资源,那么我们怎么才能看到这些资源到底是什么呢?由于这些文件是类似于AssetBundle的文件格式,所以我们需要首先把这两个文件进行拆包,然后才可以看到其内部结构。
我使用的 DevXUnityUnPack 这个工具进行拆包操作,这个工具很强大,可以直接对APK文件进行拆包。

我们重点关注 unity_builtin_extraunity default resources 这两个文件里面有哪些资源:



你会看到 unity_builtin_extra 里面都是Shader文件,而 unity default resources 里面则包含纹理、默认的Arial字体、材质、Shader等。

Unity3D引擎冷启动时需要加载哪些资源

我们如何分析哪些资源被加载了呢?我们可以使用Resources.FindObjectsOfTypeAll 方法来列出来哪些文件被加载了,它会把内部的对象以及被Disable的对象也列出来。
我们在场景上新建一个 obj1 GameObject, 并挂在 Test.cs 脚本, Test.cs 代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System;

public class Test : MonoBehaviour
{
    void Start ()
    {
        string str = "";
        var objs = Resources.FindObjectsOfTypeAll<UnityEngine.Object>();

        str += "total objs length = " + objs.Length + "\n";
        foreach(var obj in objs)
        {
            Type type = obj.GetType();
            str += "name = " + obj.name + ", type = " + type;
            str += "\n";
        }

        string path = Path.Combine(Application.persistentDataPath, "logs.txt");
        File.WriteAllText(path, str);
    }
}

游戏场景结构如下所示:

我们在Android手机上运行游戏( 注意:一定要在真机上运行,在Editor里面运行得到的信息是不准确的,会把Unity3D Editor加载的资源也列出来 ),可以得到下面的 logs.txt 信息:

total objs length = 216
name = NavMeshSettings, type = UnityEngine.Object
name = OcclusionCullingSettings, type = UnityEngine.Object
name = , type = UnityEngine.Material
name = UnityNHxRoughness, type = UnityEngine.Texture2D
name = UnityDitherMask3D, type = UnityEngine.Texture3D
name = UnityDitherMask2D, type = UnityEngine.Texture2D
name = UnityDefaultCube, type = UnityEngine.Cubemap
name = UnityDefault2DArray, type = UnityEngine.Texture2DArray
name = UnityDefault3D, type = UnityEngine.Texture3D
name = UnityDefault2D, type = UnityEngine.Texture2D
name = UnityBlackCube, type = UnityEngine.Cubemap
name = UnityAttenuation, type = UnityEngine.Texture2D
name = UnityHalo, type = UnityEngine.Texture2D
name = UnityGrayscaleRamp, type = UnityEngine.Texture2D
name = UnityGrey, type = UnityEngine.Texture2D
name = UnityRed, type = UnityEngine.Texture2D
name = UnityRandomRotation, type = UnityEngine.Texture2D
name = UnityBlack, type = UnityEngine.Texture2D
name = UnityWhite, type = UnityEngine.Texture2D
name = UnityNormalMap, type = UnityEngine.Texture2D
name = InternalIdentityTransform, type = UnityEngine.Transform
name = InternalIdentityTransform, type = UnityEngine.GameObject
name = PlayerSettings, type = UnityEngine.Object
name = InputManager, type = UnityEngine.Object
name = BuildSettings, type = UnityEngine.Object
name = GraphicsSettings, type = UnityEngine.Rendering.GraphicsSettings
name = Hidden/Internal-DeferredShading, type = UnityEngine.Shader
name = Hidden/Internal-DeferredReflections, type = UnityEngine.Shader
name = Hidden/Internal-ScreenSpaceShadows, type = UnityEngine.Shader
name = Hidden/Internal-PrePassLighting, type = UnityEngine.Shader
name = Hidden/Internal-DepthNormalsTexture, type = UnityEngine.Shader
name = Hidden/Internal-MotionVectors, type = UnityEngine.Shader
name = Hidden/Internal-Halo, type = UnityEngine.Shader
name = Hidden/Internal-Flare, type = UnityEngine.Shader
name = Legacy Shaders/Diffuse, type = UnityEngine.Shader
name = Hidden/CubeBlur, type = UnityEngine.Shader
name = Hidden/CubeCopy, type = UnityEngine.Shader
name = Hidden/CubeBlend, type = UnityEngine.Shader
name = Sprites/Default, type = UnityEngine.Shader
name = UI/Default, type = UnityEngine.Shader
name = Hidden/VideoDecode, type = UnityEngine.Shader
name = Hidden/VideoDecodeAndroid, type = UnityEngine.Shader
name = Hidden/Internal-StencilWrite, type = UnityEngine.Shader
name = Hidden/Internal-CombineDepthNormals, type = UnityEngine.Shader
name = Hidden/BlitCopy, type = UnityEngine.Shader
name = Hidden/BlitCopyDepth, type = UnityEngine.Shader
name = Hidden/Internal-GUITextureClip, type = UnityEngine.Shader
name = Hidden/Internal-GUITextureClipText, type = UnityEngine.Shader
name = Hidden/Internal-GUITexture, type = UnityEngine.Shader
name = Hidden/Internal-GUITextureBlit, type = UnityEngine.Shader
name = Hidden/ConvertTexture, type = UnityEngine.Shader
name = Hidden/VR/BlitCopyFromTexArray, type = UnityEngine.Shader
name = Sprites-Default, type = UnityEngine.Material
name = QualitySettings, type = UnityEngine.QualitySettings
name = RuntimeInitializeOnLoadManager, type = UnityEngine.Object
name = Hidden/InternalErrorShader, type = UnityEngine.Shader
name = Soft, type = UnityEngine.Texture2D
name = DeveloperConsole, type = UnityEngine.TextAsset
name = GUISkin, type = UnityEngine.TextAsset
name = TagManager, type = UnityEngine.Object
name = AudioManager, type = UnityEngine.Object
name = ScriptMapper, type = UnityEngine.Object
name = Legacy Shaders/VertexLit, type = UnityEngine.Shader
name = Skybox/Procedural, type = UnityEngine.Shader
name = MonoManager, type = UnityEngine.Object
name = AudioSpatializerMicrosoft, type = UnityEngine.TextAsset
name = SpatialMappingBase, type = UnityEngine.TextAsset
name = SpatialMappingCollider, type = UnityEngine.TextAsset
name = SpatialMappingRenderer, type = UnityEngine.TextAsset
name = HoloLensInput, type = UnityEngine.TextAsset
name = HoloLensInputModule, type = UnityEngine.TextAsset
name = PlaymodeTestsController, type = UnityEngine.TextAsset
name = PlayModeRunnerCallback, type = UnityEngine.TextAsset
name = CallbackExecutor, type = UnityEngine.TextAsset
name = Placeholder, type = UnityEngine.TextAsset
name = AnalyticsTracker, type = UnityEngine.TextAsset
name = NetworkAnimator, type = UnityEngine.TextAsset
name = NetworkBehaviour, type = UnityEngine.TextAsset
name = NetworkDiscovery, type = UnityEngine.TextAsset
name = NetworkIdentity, type = UnityEngine.TextAsset
name = NetworkLobbyManager, type = UnityEngine.TextAsset
name = NetworkLobbyPlayer, type = UnityEngine.TextAsset
name = NetworkManager, type = UnityEngine.TextAsset
name = NetworkManagerHUD, type = UnityEngine.TextAsset
name = NetworkMigrationManager, type = UnityEngine.TextAsset
name = NetworkProximityChecker, type = UnityEngine.TextAsset
name = NetworkStartPosition, type = UnityEngine.TextAsset
name = NetworkTransformChild, type = UnityEngine.TextAsset
name = NetworkTransform, type = UnityEngine.TextAsset
name = NetworkTransformVisualizer, type = UnityEngine.TextAsset
name = AsyncUtil, type = UnityEngine.TextAsset
name = NetworkAnimator, type = UnityEngine.TextAsset
name = NetworkBehaviour, type = UnityEngine.TextAsset
name = NetworkDiscovery, type = UnityEngine.TextAsset
name = NetworkIdentity, type = UnityEngine.TextAsset
name = NetworkLobbyManager, type = UnityEngine.TextAsset
name = NetworkLobbyPlayer, type = UnityEngine.TextAsset
name = NetworkManager, type = UnityEngine.TextAsset
name = NetworkManagerHUD, type = UnityEngine.TextAsset
name = NetworkMigrationManager, type = UnityEngine.TextAsset
name = NetworkProximityChecker, type = UnityEngine.TextAsset
name = NetworkStartPosition, type = UnityEngine.TextAsset
name = NetworkTransformChild, type = UnityEngine.TextAsset
name = NetworkTransform, type = UnityEngine.TextAsset
name = NetworkTransformVisualizer, type = UnityEngine.TextAsset
name = EventSystem, type = UnityEngine.TextAsset
name = EventTrigger, type = UnityEngine.TextAsset
name = UIBehaviour, type = UnityEngine.TextAsset
name = BaseInput, type = UnityEngine.TextAsset
name = BaseInputModule, type = UnityEngine.TextAsset
name = PointerInputModule, type = UnityEngine.TextAsset
name = StandaloneInputModule, type = UnityEngine.TextAsset
name = TouchInputModule, type = UnityEngine.TextAsset
name = BaseRaycaster, type = UnityEngine.TextAsset
name = Physics2DRaycaster, type = UnityEngine.TextAsset
name = PhysicsRaycaster, type = UnityEngine.TextAsset
name = Button, type = UnityEngine.TextAsset
name = Dropdown, type = UnityEngine.TextAsset
name = Graphic, type = UnityEngine.TextAsset
name = GraphicRaycaster, type = UnityEngine.TextAsset
name = Image, type = UnityEngine.TextAsset
name = InputField, type = UnityEngine.TextAsset
name = Mask, type = UnityEngine.TextAsset
name = MaskableGraphic, type = UnityEngine.TextAsset
name = RawImage, type = UnityEngine.TextAsset
name = RectMask2D, type = UnityEngine.TextAsset
name = Scrollbar, type = UnityEngine.TextAsset
name = ScrollRect, type = UnityEngine.TextAsset
name = Selectable, type = UnityEngine.TextAsset
name = Slider, type = UnityEngine.TextAsset
name = Text, type = UnityEngine.TextAsset
name = Toggle, type = UnityEngine.TextAsset
name = ToggleGroup, type = UnityEngine.TextAsset
name = AspectRatioFitter, type = UnityEngine.TextAsset
name = CanvasScaler, type = UnityEngine.TextAsset
name = ContentSizeFitter, type = UnityEngine.TextAsset
name = GridLayoutGroup, type = UnityEngine.TextAsset
name = HorizontalLayoutGroup, type = UnityEngine.TextAsset
name = HorizontalOrVerticalLayoutGroup, type = UnityEngine.TextAsset
name = LayoutElement, type = UnityEngine.TextAsset
name = LayoutGroup, type = UnityEngine.TextAsset
name = VerticalLayoutGroup, type = UnityEngine.TextAsset
name = BaseMeshEffect, type = UnityEngine.TextAsset
name = Outline, type = UnityEngine.TextAsset
name = PositionAsUV1, type = UnityEngine.TextAsset
name = Shadow, type = UnityEngine.TextAsset
name = EventSystem, type = UnityEngine.TextAsset
name = EventTrigger, type = UnityEngine.TextAsset
name = UIBehaviour, type = UnityEngine.TextAsset
name = BaseInput, type = UnityEngine.TextAsset
name = BaseInputModule, type = UnityEngine.TextAsset
name = PointerInputModule, type = UnityEngine.TextAsset
name = StandaloneInputModule, type = UnityEngine.TextAsset
name = TouchInputModule, type = UnityEngine.TextAsset
name = BaseRaycaster, type = UnityEngine.TextAsset
name = Physics2DRaycaster, type = UnityEngine.TextAsset
name = PhysicsRaycaster, type = UnityEngine.TextAsset
name = Button, type = UnityEngine.TextAsset
name = Dropdown, type = UnityEngine.TextAsset
name = Graphic, type = UnityEngine.TextAsset
name = GraphicRaycaster, type = UnityEngine.TextAsset
name = Image, type = UnityEngine.TextAsset
name = InputField, type = UnityEngine.TextAsset
name = Mask, type = UnityEngine.TextAsset
name = MaskableGraphic, type = UnityEngine.TextAsset
name = RawImage, type = UnityEngine.TextAsset
name = RectMask2D, type = UnityEngine.TextAsset
name = Scrollbar, type = UnityEngine.TextAsset
name = ScrollRect, type = UnityEngine.TextAsset
name = Selectable, type = UnityEngine.TextAsset
name = Slider, type = UnityEngine.TextAsset
name = Text, type = UnityEngine.TextAsset
name = Toggle, type = UnityEngine.TextAsset
name = ToggleGroup, type = UnityEngine.TextAsset
name = AspectRatioFitter, type = UnityEngine.TextAsset
name = CanvasScaler, type = UnityEngine.TextAsset
name = ContentSizeFitter, type = UnityEngine.TextAsset
name = GridLayoutGroup, type = UnityEngine.TextAsset
name = HorizontalLayoutGroup, type = UnityEngine.TextAsset
name = HorizontalOrVerticalLayoutGroup, type = UnityEngine.TextAsset
name = LayoutElement, type = UnityEngine.TextAsset
name = LayoutGroup, type = UnityEngine.TextAsset
name = VerticalLayoutGroup, type = UnityEngine.TextAsset
name = BaseMeshEffect, type = UnityEngine.TextAsset
name = Outline, type = UnityEngine.TextAsset
name = PositionAsUV1, type = UnityEngine.TextAsset
name = Shadow, type = UnityEngine.TextAsset
name = AudioSpatializerMicrosoft, type = UnityEngine.TextAsset
name = SpatialMappingBase, type = UnityEngine.TextAsset
name = SpatialMappingCollider, type = UnityEngine.TextAsset
name = SpatialMappingRenderer, type = UnityEngine.TextAsset
name = HoloLensInput, type = UnityEngine.TextAsset
name = HoloLensInputModule, type = UnityEngine.TextAsset
name = Test, type = UnityEngine.TextAsset
name = TimeManager, type = UnityEngine.Object
name = DelayedCallManager, type = UnityEngine.Object
name = PhysicsManager, type = UnityEngine.Object
name = ResourceManager, type = UnityEngine.Object
name = NetworkManager, type = UnityEngine.Object
name = MasterServerInterface, type = UnityEngine.Object
name = NavMeshProjectSettings, type = UnityEngine.Object
name = Physics2DSettings, type = UnityEngine.Object
name = CloudWebServicesManager, type = UnityEngine.Object
name = UnityAnalyticsManager, type = UnityEngine.Object
name = UnityConnectSettings, type = UnityEngine.Object
name = PerformanceReportingManager, type = UnityEngine.Object
name = , type = UnityEngine.Object
name = , type = UnityEngine.Object
name = Default-Skybox, type = UnityEngine.Material
name = , type = UnityEngine.Cubemap
name = , type = UnityEngine.LightProbes
name = obj1, type = UnityEngine.GameObject
name = obj1, type = UnityEngine.Transform
name = RenderSettings, type = UnityEngine.RenderSettings
name = LightmapSettings, type = UnityEngine.LightmapSettings
name = obj1, type = Test

我们会发现这么简单的一个场景,在冷启动时,足足需要加载216个对象!是不是有点吃惊呢。这些对象有Shader、Texture2D、TextAsset等,比如GraphicsSettings、UnityNormalMap、Sprites/Default等, 很大一部分都是Unity3D引擎默认需要的。我们重点来关注我们自己引入的对象:

name = Test, type = UnityEngine.TextAsset
...
...
name = obj1, type = UnityEngine.GameObject
name = obj1, type = UnityEngine.Transform
name = RenderSettings, type = UnityEngine.RenderSettings
name = LightmapSettings, type = UnityEngine.LightmapSettings
name = obj1, type = Test

Test.cs 代码本身就是一个 TextAsset,需要在启动时进行加载。 obj1 是场景里面的 GameObject 的名字,它所挂载的 Transform 组件也需要被加载。
即使代码脚本没有被使用,它也会在冷启动时加载,所以,如果一个大型项目里面有很多的代码文件,那么这些代码文件都需要被加载,这将会影响游戏的冷启动时间。所以,如果有很多的代码文件,可以考虑把这些代码文件打包成一个 .dll 文件,这样可以减少碎片化文件的加载时间,从而减少冷启动时间,加快游戏启动速度。