Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

【Unite 2017 Tokyo】もっと気軽に、動的なコンテンツ配信を ~アセットバンドルの未来と開発ロードマップ

9,733 views

Published on

講演者:大前 広樹(ユニティ・テクノロジーズ・ジャパン合同会社)

こんな人におすすめ
・アセットバンドルを使用するゲームの開発に関わっているプログラマーの方
・Unityで動的なコンテンツ配信を実現したいプログラマーの方
・アセットを使用するエディター拡張等を開発しているプログラマーの方

受講者が得られる知見
・アセットバンドルのツールやAPIが今後どう変化していくか
現在のアセットバンドルの課題がどう解決されていくか
新しいアセットバンドルの環境下で何をUnityが解決し、何をコンテンツ開発者が解決すべき問題となるか

講演動画:https://youtu.be/Aenne9hh2Mw

Published in: Technology
  • Be the first to comment

【Unite 2017 Tokyo】もっと気軽に、動的なコンテンツ配信を ~アセットバンドルの未来と開発ロードマップ

  1. 1. 

  2. 2.
  3. 3.
  4. 4. 問題を解決するときはいつも、もっとも抵抗の少 ない道を選んで行けばたやすく解決しそうに見え る。 しかして、その易しそうな道こそが最も過酷 で残酷なものに変質するのだ… -Winston Churchill
  5. 5. • • • • •
  6. 6. • • • • •
  7. 7. Unityプロジェクト 開発初週 - 直接参照 public class spawnCarFromDirectReference : MonoBehaviour { public GameObject carPrefab; void Start () { if(carPrefab != null) GameObject.Instantiate(carPrefab, this.transform, false); } }
  8. 8. Unityプロジェクト,開発2週目 - Resources.Load public class spawnCarFromResources : MonoBehaviour { public string carName; void Start () { var go = Resources.Load<GameObject>(carName); if(go != null) GameObject.Instantiate(go, this.transform, false); } }
  9. 9. Unityプロジェクト,開発3週目 - Resources.LoadAsync public class spawnCarFromResourcesAsync : MonoBehaviour { public string carName; IEnumerator Start () { var req = Resources.LoadAsync(carName); yield return req; if(req.asset != null) GameObject.Instantiate(req.asset, this.transform, false); } }
  10. 10. そして3ヶ月の時が流れた ...
  11. 11. Resourcesからアセットバンドルへの変更 public class MyBuildProcess { ... [MenuItem("Build/Build Asset Bundles")] public static void BuildAssetBundles() { var outputPath = bundleBuildPath; if(!Directory.Exists(outputPath)) Directory.CreateDirectory(outputPath); var manifest = BuildPipeline.BuildAssetBundles(outputPath, BuildAssetBundleOptions.ChunkBasedCompression, EditorUserBuildSettings.activeBuildTarget); var bundlesToCopy = new List<string>(manifest.GetAllAssetBundles()); // Copy the manifest file bundlesToCopy.Add(EditorUserBuildSettings.activeBuildTarget.ToString()); CopyBundlesToStreamingAssets(bundlesToCopy); } ... }
  12. 12. Resourcesからアセットバンドルへの変更 public class spawnCarFromBuiltinAssetBundle : MonoBehaviour { public string carName; public string carBundleName; IEnumerator Start () { if(!string.IsNullOrEmpty(carBundleName)) { var bundleReq = AssetBundle.LoadFromFileAsync(carBundleName); yield return bundleReq; var bundle = bundleReq.assetBundle; if( bundle != null) { var assetReq = bundle.LoadAssetAsync(carName); yield return assetReq; if(assetReq.asset != null) GameObject.Instantiate(assetReq.asset, this.transform, false); } } } }
  13. 13. そして3ヶ月後 ...
  14. 14. Asset BundlesをCDNからロードするよう書き換え public class spawnCarFromRemoteAssetBundle : MonoBehaviour { public string carName; public string carBundleName; public string remoteUrl; IEnumerator Start () { var bundleUrl = Path.Combine(remoteUrl, carBundleName); var webReq = UnityWebRequest.GetAssetBundle(bundleUrl); var handler = webReq.downloadHandler as DownloadHandlerAssetBundle; yield return webReq.Send(); var bundle = handler.assetBundle; if(bundle != null) { var prefab = bundle.LoadAsset<GameObject>(carName); if(prefab != null) GameObject.Instantiate(prefab, this.transform, false); } } }
  15. 15. Loading Asset Bundles from CDN public class spawnCarFromRemoteAssetBundle : MonoBehaviour { public string carName; public string carBundleName; public string remoteUrl; IEnumerator Start () { var bundleUrl = Path.Combine(remoteUrl, carBundleName); var webReq = UnityWebRequest.GetAssetBundle(bundleUrl); var handler = webReq.downloadHandler as DownloadHandlerAssetBundle; yield return webReq.Send(); var bundle = handler.assetBundle; if(bundle != null) { var prefab = bundle.LoadAsset<GameObject>(carName); if(prefab != null) GameObject.Instantiate(prefab, this.transform, false); } } } こ ん な コ ー ド じ ゃ 無 理 ! !
  16. 16. public class spawnCarFromRemoteAssetBundleWithDependencies : MonoBehaviour { // Simple class to handle loading asset bundles via UnityWebRequest public class AssetBundleLoader { string uri; string bundleName; public AssetBundle assetBundle { get; private set; } public static AssetBundleLoader Factory(string uri, string bundleName) { return new AssetBundleLoader(uri, bundleName); } private AssetBundleLoader(string uri, string bundleName) { this.uri = uri; this.bundleName = bundleName; } public IEnumerator Load() { var bundleUrl = Path.Combine(this.uri, this.bundleName); var webReq = UnityWebRequest.GetAssetBundle(bundleUrl); var handler = webReq.downloadHandler as DownloadHandlerAssetBundle; yield return webReq.Send(); assetBundle = handler.assetBundle; } } public string carName; public string carBundleName; public string manifestName; public string remoteUrl; IEnumerator Start () { var manifestLoader = AssetBundleLoader.Factory(remoteUrl, bundleManifestName); yield return manifestLoader.Load(); var manifestBundle = manifestLoader.assetBundle; // Bail out if we can't load the manifest if(manifestBundle == null) { Debug.LogWarning("Could not load asset bundle manifest."); yield break; } var op = manifestBundle.LoadAssetAsync<AssetBundleManifest>("AssetBundleManifest"); yield return op; var manifest = op.asset as AssetBundleManifest; var deps = manifest.GetAllDependencies(carBundleName); foreach(var dep in deps) { Debug.LogFormat("Loading asset bundle dependency {0}", dep); var loader = AssetBundleLoader.Factory(remoteUrl, dep); yield return loader.Load(); } var carLoader = AssetBundleLoader.Factory(remoteUrl, carBundleName); yield return carLoader.Load(); if(carLoader.assetBundle != null) { op = carLoader.assetBundle.LoadAssetAsync<GameObject>(carName); yield return op; var prefab = op.asset as GameObject; if(prefab != null) GameObject.Instantiate(prefab, this.transform, false); } } }
  17. 17. さらに求められる、アセットバンドルに必要な配慮: • 一番効率的にアセットをバンドルに含める方法 • バンドル内のアセット重複回避 • バンドルに含まれているアセットの管理・確認 • バンドルのロードのメモリ管理
  18. 18.
  19. 19. • 
 • 
 • •
  20. 20. • • • • • T
  21. 21. 
 - heszkeWmeszke
  22. 22. • • • • • • •
  23. 23. • • • •
  24. 24. • • • 

  25. 25. • • • • • • •
  26. 26. • • • • • • • • •
  27. 27. • • • • • • • • • • •
  28. 28. • • • • • • • •
  29. 29. Unity 2017.1b (experimental) https://github.com/Unity-Technologies/AssetBundles-BuildPipeline UnityEditor.Experimental.Build.AssetBundle

  30. 30. Bundle Build Pipeline Overhaul Sneak Peak public static AssetBundleBuildInput GenerateAssetBundleBuildInput( AssetBundleBuildSettings settings) { … } public struct AssetBundleBuildInput { public struct Definition { public string name; public string variant; public GUID[] assets; } public AssetBundleBuildSettings settings; public Definition[] bundles; } * Input generated from asset importer meta data or any other source (external tools, etc.) 

  31. 31. Bundle Build Pipeline Overhaul Sneak Peak public static AssetBundleBuildCommandSet GenerateAssetBuildCommandSet( AssetBundleBuildInput buildInput) { … } public struct AssetBundleBuildCommandSet { public struct Command { public AssetBundleBuildInput.Definition input; public ObjectIdentifier[] objectsToBeWritten; } public AssetBundleBuildSettings settings; public Command[] commands; } Command set generation gathers all dependencies, handles object stripping, and generates full list of objects to write. 

  32. 32. Bundle Build Pipeline Overhaul Sneak Peak public static void SaveAssetBundleOutput(AssetBundleBuildOutput output) { … } Output can be serialized to JSON or any other format as required.
  33. 33. Bundle Build Pipeline Overhaul Sneak Peak public static void SaveAssetBundleOutput(AssetBundleBuildOutput output) { … } Put it all together … // Default build pipeline SaveAssetBundleOutput(ExecuteAssetBuildCommandSet(GenerateAssetBuildComma ndSet(GenerateAssetBundleBuildInput(settings))));

  34. 34. Unity 2017.1b
  35. 35. • • • • • •
  36. 36. • •
  37. 37. • • • • • • • • • •
  38. 38. • • • • • • • •
  39. 39. public class spawnCarFromRemoteAssetBundleWithDependencies : MonoBehaviour { // Simple class to handle loading asset bundles via UnityWebRequest public class AssetBundleLoader { string uri; string bundleName; public AssetBundle assetBundle { get; private set; } public static AssetBundleLoader Factory(string uri, string bundleName) { return new AssetBundleLoader(uri, bundleName); } private AssetBundleLoader(string uri, string bundleName) { this.uri = uri; this.bundleName = bundleName; } public IEnumerator Load() { var bundleUrl = Path.Combine(this.uri, this.bundleName); var webReq = UnityWebRequest.GetAssetBundle(bundleUrl); var handler = webReq.downloadHandler as DownloadHandlerAssetBundle; yield return webReq.Send(); assetBundle = handler.assetBundle; } } public string carName; public string carBundleName; public string manifestName; public string remoteUrl; IEnumerator Start () { var manifestLoader = AssetBundleLoader.Factory(remoteUrl, bundleManifestName); yield return manifestLoader.Load(); var manifestBundle = manifestLoader.assetBundle; // Bail out if we can't load the manifest if(manifestBundle == null) { Debug.LogWarning("Could not load asset bundle manifest."); yield break; } var op = manifestBundle.LoadAssetAsync<AssetBundleManifest>("AssetBundleManifest"); yield return op; var manifest = op.asset as AssetBundleManifest; var deps = manifest.GetAllDependencies(carBundleName); foreach(var dep in deps) { Debug.LogFormat("Loading asset bundle dependency {0}", dep); var loader = AssetBundleLoader.Factory(remoteUrl, dep); yield return loader.Load(); } var carLoader = AssetBundleLoader.Factory(remoteUrl, carBundleName); yield return carLoader.Load(); if(carLoader.assetBundle != null) { op = carLoader.assetBundle.LoadAssetAsync<GameObject>(carName); yield return op; var prefab = op.asset as GameObject; if(prefab != null) GameObject.Instantiate(prefab, this.transform, false); } } }
  40. 40. public class spawnCarFromRemoteAssetBundleWithDependencies : MonoBehaviour { // Simple class to handle loading asset bundles via UnityWebRequest public class AssetBundleLoader { string uri; string bundleName; public AssetBundle assetBundle { get; private set; } public static AssetBundleLoader Factory(string uri, string bundleName) { return new AssetBundleLoader(uri, bundleName); } private AssetBundleLoader(string uri, string bundleName) { this.uri = uri; this.bundleName = bundleName; } public IEnumerator Load() { var bundleUrl = Path.Combine(this.uri, this.bundleName); var webReq = UnityWebRequest.GetAssetBundle(bundleUrl); var handler = webReq.downloadHandler as DownloadHandlerAssetBundle; yield return webReq.Send(); assetBundle = handler.assetBundle; } } public string carName; public string carBundleName; public string manifestName; public string remoteUrl; IEnumerator Start () { var manifestLoader = AssetBundleLoader.Factory(remoteUrl, bundleManifestName); yield return manifestLoader.Load(); var manifestBundle = manifestLoader.assetBundle; // Bail out if we can't load the manifest if(manifestBundle == null) { Debug.LogWarning("Could not load asset bundle manifest."); yield break; } var op = manifestBundle.LoadAssetAsync<AssetBundleManifest>("AssetBundleManifest"); yield return op; var manifest = op.asset as AssetBundleManifest; var deps = manifest.GetAllDependencies(carBundleName); foreach(var dep in deps) { Debug.LogFormat("Loading asset bundle dependency {0}", dep); var loader = AssetBundleLoader.Factory(remoteUrl, dep); yield return loader.Load(); } var carLoader = AssetBundleLoader.Factory(remoteUrl, carBundleName); yield return carLoader.Load(); if(carLoader.assetBundle != null) { op = carLoader.assetBundle.LoadAssetAsync<GameObject>(carName); yield return op; var prefab = op.asset as GameObject; if(prefab != null) GameObject.Instantiate(prefab, this.transform, false); } } }
  41. 41. public class spawnCarFromResourcesAsync : MonoBehaviour { public string carName; IEnumerator Start () { var req = Resources.LoadAsync(carName); yield return req; if(req.asset != null) GameObject.Instantiate(req.asset, this.transform, false); } }
  42. 42. • • • • • •
  43. 43. • 
 • 
 • • •
  44. 44. • •
  45. 45. ✓ 
 ✓ ✓ ✓
  46. 46.
  47. 47. ★ ★
  48. 48.

×