UnityでLive2DのモデルデータをURLからWEB経由で非同期で読み込む方法

Live2D SDKによる"ランタイムでモデルを読み込む"では、Web経由でLive2Dモデルデータを読み込む事はできません。ですがSDKに少し手を加えることでWeb経由で読み込むことが可能になります。

Live2DモデルをUnityで展開するために必要なファイルは４つ。

- model3.json
- moc3
- cdi3.json
- png

pngファイルだけはファイル名+拡張子ではなくtexture0.pngという名前で別なフォルダに保存されていますが、ファイル名.pngという名前にリネームして同じ場所にアップロードします。

これらを個別に読み込んでLive2Dモデルデータに展開します。

まずSDKのCubismModel3Json.csの一部を書き換えます。

```C#:CubismModel3Json.cs　294行目
private Texture2D[] _textures;
```

のprivate Texture2D[] _textures;のprivateをpublicに

```C#:変換後 
 public Texture2D[] _textures;
```
```C#:CubismModel3Json.cs　199行目
        public byte[] Moc3
        {
            get
            {
                return LoadReferencedAsset<byte[]>(FileReferences.Moc);
            }
        }
```

をコメントで囲み、public byte[] Moc3という変数を新たに作ります。

```C#:変換後
        /*public byte[] Moc3
        {
            get
            {
                return LoadReferencedAsset<byte[]>(FileReferences.Moc);
            }
        }*/
        public byte[] Moc3;
```
準備は以上です。

この準備さえしておけば以下のソースコードのFileUrlにファイルをアップロードしたURL、Filenameに拡張子を省いたファイルの名前を記述することでLive2Dモデルデータがweb経由で読み込み出来ます。


```C#:CubismLoader.cs
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Networking;
using UnityEditor;

using Live2D.Cubism.Framework.Json;
using Live2D.Cubism.Core;

public class CubismLoader : MonoBehaviour
{

    public string FileUrl = "https://www...";
    public string FileName = "L2DModel";

    public CubismModel3Json ModelJson;
    public CubismModel Model;

    private string[] extension = new string[] { ".model3.json", ".moc3", ".cdi3.json", ".png" };
    public void LoadModel()
    {
        StartCoroutine(CoLoadModel());
    }
    IEnumerator CoLoadModel()
    {
        string Model3Json = "";
        byte[] Moc3 = default;
        string Cdi3Json = "";
        Texture2D texture = default;

        for (int i = 0; i < 4; i++)
        {
            yield return null;
            string Path = FileUrl + FileName + extension[i];

            using (UnityWebRequest www = UnityWebRequest.Get(Path))
            {
                www.SendWebRequest();
                while (true)
                {
                    yield return null;
                    if (www.isHttpError || www.isNetworkError)
                    {
                        //Error
                        Debug.Log("ERORR!!\n" + www.error);
                        yield break;
                    }
                    if (www.isDone)
                    {
                        switch (i)
                        {
                            case 0:
                                Model3Json = www.downloadHandler.text;
                                break;
                            case 1:
                                Moc3 = www.downloadHandler.data;
                                break;
                            case 2:
                                Cdi3Json = www.downloadHandler.text;
                                break;
                            case 3:
                                byte[] bytewidth = www.downloadHandler.data.Skip(16).Take(4).Reverse().ToArray();
                                byte[] byteheight = www.downloadHandler.data.Skip(20).Take(4).Reverse().ToArray();

                                int width = System.BitConverter.ToInt32(bytewidth, 0);
                                int height = System.BitConverter.ToInt32(byteheight, 0);

                                texture = new Texture2D(width, height, TextureFormat.RGBA32, true);
                                texture.LoadImage(www.downloadHandler.data);
                                break;
                        }
                        break;
                    }
                }
            }
        }

        //Initialize
        ModelJson = JsonUtility.FromJson<CubismModel3Json>(Model3Json);
        ModelJson.Moc3 = Moc3;

        ModelJson._textures = new Texture2D[1];
        ModelJson._textures[0] = texture;

        Model = ModelJson.ToModel();

        //Model位置調整
        Model.transform.parent = transform;
        Model.transform.localPosition = Vector3.zero;
        Model.transform.localScale = Vector3.one;

    }
}
#if UNITY_EDITOR
//CustomEditor
[CustomEditor(typeof(CubismLoader))]
public class CubismLoaderCustom : Editor
{

    public override void OnInspectorGUI()
    {
        CubismLoader Content = target as CubismLoader;
        base.OnInspectorGUI();
        if (GUILayout.Button("LOAD MODEL"))
        {
            if (Application.isPlaying)
            {
                Content.LoadModel();
            }
        }
    }
}
#endif
```