AssetBundle vs. Resource.Load

I’m currently working on slimming down an application for the web. We’ve got a fair amount of dynamic content which we’re loading using the Resources.Load method.

Our use of Resources.Load is heavily dependent on keeping the directory structure as a way of keeping similarly named assets separate from each other.

i.e. resource/ships/shipA/maintexture.png vs resource/ships/shipB/maintexture.png

We’re trying to convert the project to using AssetBundles, so that we can both add content dynamically, and so that we can reduce the footprint of the initial web app. However, when I create an AssetBundle, it does not appear to preserve any information about that asset’s directory structure.

Is there a preferred way to get the usefulness of the path structure in Resources.Load with the flexibility of the AssetBundle?

Some ideas off the top of my head are:

  1. Rename the asset during the BuildPipeline process using the AssetDatabase.GetAssetPath
  2. Export only one asset per AssetBundle, and name the bundle after the asset’s path
  3. Group assets by directory, and export the AssetBundles into a similar directory structure, so that you can use the URL passed to the WWW class as a kind of key.

Is there a better or ‘official’ way to deal with this?

Alternatively, is there a way to bundle assets so that when you load them, they’re auto-magically [sic] available to the Resources class? That would give you the best of both worlds.

With the release of Unity 2.5 I was able to come up with a solution. Perhaps it’s possible to get something that will work with 2.1, but that’s probably a moot point now. It’s a proof of concept, and could benefit from some bulletproofing, but I hope it conveys the general idea.

There are three scripts in the zip file

  1. AssetBundleManager - The runtime interface for using assets bundles like the Resource.Load function
  2. ExportBundle - The editor script which packages resources into asset bundles for the AssetBundleManager
  3. AssetBundleManifest - Helper class used by the previous two scripts

The basic idea is this. Getting the asset bundle interface is fast once the package has downloaded. However, it’s very slow to instantiate all the assets within the bundle (AssetBundle.LoadAll()) in order to access them. Also, you cannot preserve any useful file path information in the object name.

This set of scripts solves this problem by doing the following.

  1. Renames all selected resources for export with unique (to the bundle) names.
  2. Creates a resource name based on the asset path, relative to the selected resources common root directory.
  3. Saves the resource name in an AssetBundleManifest object, which is turned into a prefab, and saved as the mainAsset of the asset bundle.
  4. Restores the names of the assets to their pre export state, preserving the project’s setup.

The asset bundle manager then loads asset bundles, and uses the AssetBundleManifest to build references so that one can instantiate assets by path name.

The AssetBundleManager can either be added to a game object to provide a list of assets to start streaming on instantiation, or it can be used purely as a static class object. In that case it will create a GameObject that survives level transitions to contain itself.

I couldn’t get this to work in unity 2.1 because the RenameAsset method did not exist. Simply renaming an asset before exporting I guess causes a difference between the name of the resource, and it’s asset path, which causes it to improperly load.

Or put another way, if you change Object.name before exporting it, the following code will fail when the asset bundle is loaded.

Object[] objs = bundle.LoadAll();
foreach( Object obj in objs )
{
  Object obj2 = bundle.Load( obj.name ); // obj2 will be null
}

This is too bad, because it would be much easier to simply rename the resource as it’s pathname (i.e. obj.name = “package/textures/sample01”), and be able to call bundle.Load( “package/textures/sample01” ) without it returning null.

133870–4943–$assetbundlemanager_182.zip (4.35 KB)