• Unity3D性能优化之资源原理科普篇


    一、Unity的资源(Asset)和对象(UnityEngine.Objects)

    资源(Asset)是硬盘中的文件,存储在Unity工程的Assets文件夹内。例如,纹理(Texture),材质(Material)和FBX文件等,它们都是资源。一些资源的数据格式是Unity原生支持的,例如材质。有些资源则需要转换为原生的数据格式后才能被Unity使用,例如FBX文件。
    对象(UnityEngine.Object)代表序列化数据的集合,表示某个资源的具体实例。它可以是Unity引擎使用的任何类型的资源,例如网格,Sprite,音频剪辑或动画剪辑。所有的对象(Object)都是UnityEngine.Object基类的子类。

    几乎所有的对象(Object)类型都是内建的,其中有两种比较特殊的类型。

    ScriptableObject为开发者提供了一套便捷的系统,供开发者自定义数据类型。这些类型可以被Unity直接序列化或反序列化,并在Unity编辑器的检视器窗口中进行操作。
    MonoBehaviour提供了链接MonoScript的容器。MonoScript是一种内部数据类型,Unity用它保存对某个特定程序集和命名空间中特定脚本类的引用,MonoScript本身不包含任何实际的可执行代码。

    资源(Asset)与对象(Object)是一种一对多的关系,即一个资源文件可能会包括多个Object。

    二、对象之间的引用

    所有UnityEngine.Objects都可以引用其他的UnityEngine.Objects。这里“其他的Object”可能存在于相同的资源文件中,或需要从其他资源文件导入。例如,一个材质Object通常有一个或多个纹理Object的引用。这些纹理Object一般是从一个或多个纹理资源文件中导入的(例如PNG或JPG文件)。

    序列化后,这些引用由两部分数据组成:文件GUID和本地ID。文件GUID用于识别资源(Asset)文件中目标资源(Resource)的存储位置。而本地唯一的ID负责识别单个资源文件中的Object,因为一个资源文件可能会包含多个Object。

    比如一个特效做成的Prefab,直接用文本打开prefab和prefab.meta后缀的两个文件。

    GUID:存储于.meta文件中。Unity会在首次导入资源文件时生成.meta文件,并和资源文件一起存储在相同的目录中。GUID提供了文件存储位置的抽象,这样一个文件GUID就对应一个具体的文件,因此我们才能随意移动这个文件而不破坏所有相关Object对这个文件的引用。

    fileFormatVersion: 2
    guid: 87160fe309c6cd4458c5f56188b57684
    timeCreated: 1568165766
    licenseType: Pro
    NativeFormatImporter:
      externalObjects: {}
      mainObjectFileID: 100100000
      userData: 
      assetBundleName: 
      assetBundleVariant: 
    

    本地ID:是唯一的,使用文本编辑器打开prefab文件,可以看下关于这个预设的所有属性都在配置里面,100100000就是本地ID。任何资源(Asset)文件中都可能含有(或通过导入产生)多个UnityEngine.Object资源(Resource),因此需要一个本地ID来对其中的Object做明确区分。一个大的预设里面会有多个gameobject,相当于总的预设会记录子物体的本地ID,这样才能关联到每一个子物体。

    %YAML 1.1
    %TAG !u! tag:unity3d.com,2011:
    --- !u!1001 &100100000
    Prefab:
      m_ObjectHideFlags: 1
      serializedVersion: 2
      m_Modification:
        m_TransformParent: {fileID: 0}
        m_Modifications: []
        m_RemovedComponents: []
      m_ParentPrefab: {fileID: 0}
      m_RootGameObject: {fileID: 1891991147743598}
      m_IsPrefabParent: 1
    --- !u!1 &1053155390742798
    

    总结:Guid相当于指向一个资源路径;本地ID相当于指向于具体的游戏对象Object

    三、资源引用分析

    我们知道了资源和对象的关系后,对资源引用过程已经清楚了。那么怎么分析资源的引用关系呢?

    AssetDatabase.AssetPathToGUID(path)
    
    AssetDatabase.GUIDToAssetPath(guid)
    

    看代码就大概了解,这两个方法可以将guid和path进行互相转换,因此可以根据预设里引用到的所有guid值,进而可以找到这个资源所引用到对象。

    四、Unity资源引用的机制

    我们在Unity如果创建一个Materials,然后指定一个有两张图片属性的Shader,接着引用了两张纹理。这时候打开材质可以看到是有引用到两个纹理m_Texture。可以看下原先的属性:

    %YAML 1.1
    %TAG !u! tag:unity3d.com,2011:
    --- !u!21 &2100000
    Material:
      serializedVersion: 6
      m_ObjectHideFlags: 0
      m_PrefabParentObject: {fileID: 0}
      m_PrefabInternal: {fileID: 0}
      m_Name: 5400_fangkuai
      m_Shader: {fileID: 4800000, guid: b5f72fe4d91f50b47920a7498eeaf32a, type: 3}
      m_ShaderKeywords: 
      m_LightmapFlags: 4
      m_EnableInstancingVariants: 0
      m_DoubleSidedGI: 0
      m_CustomRenderQueue: -1
      stringTagMap: {}
      disabledShaderPasses: []
      m_SavedProperties:
        serializedVersion: 3
        m_TexEnvs:
        - _AmitTex:
            m_Texture: {fileID: 2800000, guid: 35a133778d8d5f64788367aa21dd2589, type: 3}
            m_Scale: {x: 0.5, y: 1}
            m_Offset: {x: 0, y: 0}
        - _FlowTex:
            m_Texture: {fileID: 2800000, guid: 4cccfa2e1ba52a342b545da00de76a29, type: 3}
            m_Scale: {x: -2, y: -2}
            m_Offset: {x: 0, y: 0}
        m_Floats:
        - _AmitIntensity: 2
        - _FlowIntensity: 4
        - _FlowTexUSpeed: 0.5
        - _FlowTexVSpeed: -0.8
        m_Colors:
        - _Color: {r: 0.32352942, g: 0.5521299, b: 1, a: 1}
        - _FlowColor: {r: 0, g: 0.28539556, b: 0.61764705, a: 1}
    

    如果这时我改一下Shader,而且这个Shader只引用一张纹理,我不赋值。这个材质引用的纹理就变成了三张,前面Shader引用到的纹理依旧在引用。

    m_TexEnvs:
        - _AmitTex:
            m_Texture: {fileID: 2800000, guid: 35a133778d8d5f64788367aa21dd2589, type: 3}
            m_Scale: {x: 0.5, y: 1}
            m_Offset: {x: 0, y: 0}
        - _Amitex:
            m_Texture: {fileID: 0}
            m_Scale: {x: 1, y: 1}
            m_Offset: {x: 0, y: 0}
        - _FlowTex:
            m_Texture: {fileID: 2800000, guid: 4cccfa2e1ba52a342b545da00de76a29, type: 3}
            m_Scale: {x: -2, y: -2}
            m_Offset: {x: 0, y: 0}
    

    总结:这个引用机制就是每次改变时,只增加新的引用,旧的引用不会去删除。

    这个机制的好处:是当又改成之前的shader时,会自动引用到纹理和设置属性。

    这个机制的坏处:资源会导致冗余,打包时会打到多余的资源对象,加载时也会加载多余的资源对象。

    五、Unity资源冗余

    我们知道了引用机制,那么可以发现一些应该避免和注意的问题。

    • 当有对象被删除时,引用此对象的依赖依然存在,应该处理。
    • 材质:材质会引用纹理,而纹理是根据材质所引用的Shader决定,所以应该针对所有材质进行处理纹理的引用。
    • 粒子系统(Particle System):粒子系统可以引用FBX和材质,在Renderer中可以引用到FBX网格,这部分也会引起FBX和纹理引用冗余。

    六、资源打包冗余

    打包冗余是指相同的对象,比如纹理被重复打进多个AB包,这样会造成包体变大,加载重复资源的问题。

    所以我们应该根据这些特性或者说机制,来分析资源引用的关系,再来进行引用的优化。所以针对这种情况会不同的资源先进行分析,最后再根据分析的情况来进行优化。

  • 相关阅读:
    C# 对XML操作-实例
    XML
    得到一个随机数组的方法
    Node Redis 小试
    Hexo快速搭建静态博客并实现远程VPS自动部署
    substr.js 字符串切割
    GraphicsMagick 学习笔记
    store.js 跨浏览器的localStorage
    bodyParser中间件的研究
    Sublime Text 使用指南
  • 原文地址:https://www.cnblogs.com/wwhhgg/p/12937944.html
Copyright © 2020-2023  润新知