Experimenting with Unity’s Asset Bundle Loading in Holographic UWP Projects

NB: The usual blog disclaimer for this site applies to posts around HoloLens. I am not on the HoloLens team. I have no details on HoloLens other than what is on the public web and so what I post here is just from my own experience experimenting with pieces that are publicly available and you should always check out the official developer site for the product documentation.

I wanted to experiment with Asset Bundles from Unity running on HoloLens in the sense that I wanted to make sure that I had the right pieces to dynamically load up something like some 3D models bundled on a web server dynamically at runtime and display them in a scene.

This is, no doubt, a very basic scenario for experienced Unity folks but I hadn’t tried it out on HoloLens so I thought I’d do that and share the write-up here.

Step 1 – Reading the Unity Asset Bundle Docs

I had a decent read of Unity’s docs around asset bundles, serialization graphs and that type of thing all from this set of resources;

A guide to AssetBundles and Resources

and that was pretty useful and led me through to the demo and companion scripts that Unity publishes on this repo;

Asset Bundle Demo Repo

and so I cloned that.

Step 2 – Building Asset Bundles

I then opened up that demo project in Unity and used the Assets menu to make the asset bundles;

image

which dropped the assets out into a folder called Windows;

image

and so I just need to drop these onto a web server somewhere and serve them up. I’ve heard that Azure thing is pretty good at this Winking smile

Step 3 – A Web Server for the Asset Bundles

I popped over to Azure and created a basic web server using the regular ‘Add App Service’ button;

image

and then it turned out that I didn’t actually have the Visual Studio web tools installed (woops, I should fix that) so I just went with the “edit this in the browser” option;

image

and hacked the web.config so as to try and make sure that it would serve up the files in question;

image

and then used the “Upload files” option to upload the files – note that this means that these files live at /AssetBundles/Windows and there’s another file in that folder also called Windows;

image

Step 4 – Trying the Desktop Demo

To see if this was “working” ok, I opened up the AssetLoader scene provided in the demo project, opened up the LoadAssets script associated with the Loader GameObject as below;

image

noting that it is loading the bundle named cube-bundle and the asset named MyCube;

image

and I hacked the accompanying script such that it loaded the asset from my new web site;

image

and, sure enough, I built and ran the desktop app and it displayed the cube as expected;

image

and Fiddler shows me where it’s coming from;

image

and so that’s all good, what about doing this on HoloLens?

Step 5 – Starting with a Blank HoloLens Project

I made a new Unity project much like I do in this video and imported the HoloToolkit-Unity;

Step 6 – Adding in the Asset Bundle Manager

I took some of the scripts from the demo asset bundle project and added them to my project, trying to be as ‘minimal’ as I could be so I brought in;

image

Bringing in the Asset Bundle Manager caused me a slight problem in that there are a couple of functions that don’t build in there on the HoloLens/UWP platform;

    //private static string GetStreamingAssetsPath()
    //{
    //  if (Application.isEditor)
    //    return "file://" + System.Environment.CurrentDirectory.Replace("\\", "/"); // Use the build output folder directly.
    //  else if (Application.isWebPlayer)
    //    return System.IO.Path.GetDirectoryName(Application.absoluteURL).Replace("\\", "/") + "/StreamingAssets";
    //  else if (Application.isMobilePlatform || Application.isConsolePlatform)
    //    return Application.streamingAssetsPath;
    //  else // For standalone player.
    //    return "file://" + Application.streamingAssetsPath;
    //}


    /// <summary>
    /// Sets base downloading URL to a directory relative to the streaming assets directory.
    /// Asset bundles are loaded from a local directory.
    /// </summary>
    public static void SetSourceAssetBundleDirectory(string relativePath)
    {
      throw new NotImplementedException();
      // BaseDownloadingURL = GetStreamingAssetsPath() + relativePath;
    }

one is public and calls the other and nothing seemed to call the public function so I figured that I was safe to comment these out at the moment (as above).

I continued by making a small “UI” with a button on it which would respond to a click;

image

and added some code to respond to the click;

using AssetBundles;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Placeholder : MonoBehaviour
{
  public void OnClick()
  {
    if (!this.loaded)
    {
      StartCoroutine(this.LoadModelAsync());
      this.loaded = true;
    }
  }
  IEnumerator LoadModelAsync()
  {
    AssetBundleManager.SetSourceAssetBundleURL("http://mttestbundles.azurewebsites.net/AssetBundles/");

    var initializeOperation = AssetBundleManager.Initialize();

    if (initializeOperation == null)
    {
      yield break;
    }
    yield return StartCoroutine(initializeOperation);

    var loadOperation = AssetBundleManager.LoadAssetAsync(
      "cube-bundle", "MyCube", typeof(GameObject));

    if (loadOperation == null)
    {
      yield break;
    }
    yield return StartCoroutine(loadOperation);

    var prefab = loadOperation.GetAsset<GameObject>();

    if (prefab != null)
    {
      var cube = GameObject.Instantiate(prefab);

      // Put the cube somewhere obvious.
      cube.transform.position = new Vector3(0, 1.0f, 2.0f);

      // The cube in the asset bundle is quite big.
      cube.transform.localScale = new Vector3(0.2f, 0.2f, 0.2f);
    }
  }
  bool loaded;
}

This code is really just me taking what seemed like the “essential” code out of the Unity sample and seeing if I could get it running on its own here inside of my HoloLens project.

Not surprisingly, I couldn’t Smile The code crashed.

Step 7 – Adding the Platform Name

Fixing the crash wasn’t too difficult – there are two functions in the supplied Utility.cs code file named GetPlatformForAssetBundles (one for the editor and one for the non-editor) and they are just a big switch statement that turns an enumeration for the build platform into a string. They needed me to add;

image

although I can’t be 100% certain that this is the right thing to do but it seemed like a reasonable place to start.

However, this didn’t work either Smile

Step 8 – The Wrong Build Target

With that change in place, my code no longer crashed but I did some debugging and some watching of the Unity debug spew and ultimately I could see that Unity was taking a look at my asset bundle and rejecting it. That is, it was saying (and I quote Winking smile);

The file can not be loaded because it was created for another build target that is not compatible with this platform.
Please make sure to build AssetBundles using the build target platform that it is used by.
File’s Build target is: 5

Ok – so clearly, here, I’ve built the asset bundles using the demo project supplied and they emit some target identifier of “5” into the output and that “5” is not viewed as being compatible with my current build target in my HoloLens project.

I left the assets in the demo project and simply changed the build target to be Windows Store;

image

as the script which does the building (BuildScript) seemed to be making use of EditorUserBuildSettings.activeBuildTarget so that felt like it might work. Because the build platform was now UWP, I needed to make the same changes to the scripts that I’d made in my own project in order to add the “Windows” name for the WSA… runtime platform enumerations.

With that done, I could click “Build Asset Bundles…” and get some new bundles and I overwrote the ones on my web server with these new variants.

That worked out fine and on the HoloLens I can then click the button in order to dynamically pull the cube asset bundle from the web server and display it on the device as below;

20170328_120919_HoloLens

Wrapping Up

With a couple of minor script changes, this workflow around asset bundles seems to work pretty well for the HoloLens. I could perhaps experiment a little further and try out working with different variants of assets and so on but, for my quick experiment, I’m happy that it’s working reasonably well and without too much of a deviation from what the Unity docs say.

What I haven’t yet tried is using the local server that Unity provides and the simulation mode to see if I can get that working for a HoloLens project but it feels like it should work to me…maybe that’s one for another post?

One thought on “Experimenting with Unity’s Asset Bundle Loading in Holographic UWP Projects

Comments are closed.