Please explain BuildPipeline.PushAssetDependencies

I've read the docs on BuildPipeline.PushAssetDependencies and gone through the example code several times and it just doesn't make sense to me. Can someone explain it in more detail and clearer language?

For instance, when you call PushAssetDependencies, what gets pushed, and onto where?

In the example code at http://unity3d.com/support/documentation/ScriptReference/BuildPipeline.PushAssetDependencies.html what does that first call to PushAssetDependencies do? Does it cause Lerpz.unity3d, explosive.unity3d, and AdditiveScene.unity3d to depend on shared.unity3d? (i.e. if you didn't call PushAssetDependencies then lerpzuv.tif would get duplicated into each asset bundle?)

If so, why is every build after that preceded by a push and followed by a pop? I read the comment that says, "By pushing and popping around the asset bundle, this file will share resources but later asset bundles will not share assets in this resource" but I don't understand that sentence. This file will share which resources? Does share mean "make available" or "take from somewhere else"? How does the push and pop accomplish that?

Are there some unnecessary calls to push and pop in the example?

I'll give a shot at answering this based on my own understanding, though please chime in if I have this wrong in some way...

Push and PopAssetDependencies let you control which asset bundles are dependent on another (ie which assets can be excluded). When you call PushAssetDependencies, it instructs BuildPipeline to exclude assets in the next bundle it builds that were already included in the previous one. Dependent asset bundles have to be built in order and then loaded in order. For PushAssetDependencies to work you have to build all of your asset bundles in one script as there's no way (as far as I know) to build an asset bundle with dependencies to a pre-existing bundle.

Here's an example. Suppose you want to create 2 bundles (Bundle1 and Bundle2) and you want Bundle2 to reference assets in Bundle1, instead of including them twice separately. For the sake of visualization, let's say that there's a huge texture file "humungous.png" used by both bundles, but you really only need to have it included in Bundle1. Here's how you would build the bundles with an editor script:

var mode : int = BuildAssetBundleOptions.CollectDependencies |
        BuildAssetBundleOptions.CompleteAssets |
        BuildAssetBundleOptions.DeterministicAssetBundle;
var path : String = Application.dataPath+"/Bundle1.assetbundle";

BuildPipeline.PushAssetDependencies();
BuildPipeline.BuildAssetBundle(AssetDatabase.LoadMainAssetAtPath("Assets/Prefabs/myObject1.prefab"), null, path, mode, BuildTarget.iPhone);

path = Application.dataPath+"/Bundle2.assetbundle";
BuildPipeline.PushAssetDependencies();
BuildPipeline.BuildAssetBundle(AssetDatabase.LoadMainAssetAtPath("Assets/Prefabs/myObject2.prefab"), null, path, mode, BuildTarget.iPhone);
BuildPipeline.PopAssetDependencies();

BuildPipeline.PopAssetDependencies();

Because PushAssetDependencies was called before building Bundle2, the "humungous.png" file would be in Bundle1, and Bundle2 would only store a reference to it.

Even if you don't need to redistribute Bundle1, it needs to be rebuilt in the script to correctly prepare Bundle2's dependencies. Each call to PushAssetDependencies tells the BuildPipeline to exclude the shared dependencies of the previous asset bundle in the one created next. While PopAssetDependencies removes the exclusion. The Push and Pop commands are hierarchical, meaning you can nest dependencies. For example, consider if you had a complex project with a bundle for base assets, then other sets of bundles of shared assets for specific environments. Using Push and Pop you can create 'layers' of dependencies.

The use of DeterministicAssetBundle means that each time asset bundles are created, the same internal IDs for objects will be used. This ensures that when you build bundles, the assets are referenced the same way every time. If you don't use DeterministicAssetBundle, then there's a risk that there will be conflicts with new bundles and previously distributed bundles.

Hopefully that helps some.

We have prepared a tutorial about building asset bundles with our uTomate build tool. This tutorial also covers the asset bundle dependency stack and how Pushing and Popping from it affect what ends up in your asset bundles, so it’s probably going to help you understand the PushAssetDependencies and PopAssetDependencies commands even if you don’t use uTomate for building: http://docs.ancientlightstudios.com/display/UT/How+to+build+Asset+Bundles+with+uTomate