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

2021-01-15 00:15

阅读:631

标签:game   ide   而且   导入   base   userdata   create   name   工程   

一、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包,这样会造成包体变大,加载重复资源的问题。

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

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

标签:game   ide   而且   导入   base   userdata   create   name   工程   

原文地址:https://www.cnblogs.com/wwhhgg/p/12937944.html


评论


亲,登录后才可以留言!