UnityのGameObjectにAWS S3にある画像をテクスチャとして貼り付けたい話

# はじめに

〜AWSさんに届け〜
S3のサンプルに画像を扱うものもあるとヒヨコには嬉しいです。ぐぐると探している人もいるようでした。

日本語でドンピシャな情報にたどり着けなかったのでメモっておきます。
UnityのテクスチャにAWSの画像を使いたい話です。

# ３行で要点だけ欲しい人向け情報

1. SDKをダウンロードしてきてUnityにインポート
2. AWS側の準備する(S3,Cognito,Cognito用IAMロール)
3. サンプルを修正して（サンプルだと文字の読み取りなので画像の処理に変更して）動かす

# やったこと詳細

## 環境

- Unity 2017.3.1f1(64bit)
- Mac利用

## SDKをダウンロード＆インポート

- 公式手順： https://docs.aws.amazon.com/ja_jp/mobile/sdkforunity/developerguide/setup-unity.html
 - zipをダウンロードして来て適当に展開する
 - UnityのプロジェクトにS3の`AWSSDK.S3.3.3.18.2.unitypackage`をインポートする
 - unitypackageの名前のとおりですが、自分が使ったバージョンは`aws-sdk-unity_3.3.281.0`でした

## AWS側の準備する

### S3の準備

- bucketを用意する
- 適当な画像ファイル（自分はPNGを利用しました）をアップロードしておく
- bucket名、ファイル名はあとで使います

### Cognitoの設定（IAMロールの設定）

- `Manage Federated Identities`から新規で作成
- IAM ROLEを設定、S3の必要な権限を追加しておく(ひとまず試したいのであれば`S3FullAccess`をくっつけておくと間違いないはず)

### Unityに準備したAWSの情報をいれていく

- サンプルの `Assets/Exapmles/S3Example` を開いて編集していく
- `S3`というGameObjectがHierarchy内にあるので、選択してInspectorタブで`S3 Example(Script)`を見つけて先ほど作ったS3とCognitoの情報を入れ込む
 - Tokyoリージョンは`ap-northeast-1`デスヨ

## サンプルを修正して動かす

### とりあえず、疎通確認する

- サンプルなのでそのまま動くだろうと安易にPlayしてみましょう。そして、画像を取ってくるのが目標なので、`Get Object`をポチる。自分はここが動きませんでした:frowning2:
- 動かない理由が自分と同じ`InvalidOperationException: Cannot override system-specified headers
UnityEngine.Networking.UnityWebRequest.SetRequestHeader (System.String name, System.String value) (at /Users/builduser/buildslave/unity/build/Modules/UnityWebRequest/Public/UnityWebRequest.bindings.cs:424) ... `であれば、Start関数内を以下を参考に修正してください（２行目が追加されています）
 - 理由はこちら： https://aws.amazon.com/jp/blogs/mobile/unity-v3-support-in-the-aws-sdk-for-net-is-out-of-preview/

```C#:S3Example.cs
        void Start()
        {
            UnityInitializer.AttachToGameObject(this.gameObject);
            AWSConfigs.HttpClient = AWSConfigs.HttpClientOption.UnityWebRequest; //added
            GetBucketListButton.onClick.AddListener(() => { GetBucketList(); });
            PostBucketButton.onClick.AddListener(() => { PostObject(); });
            GetObjectsListButton.onClick.AddListener(() => { GetObjects(); });
            DeleteObjectButton.onClick.AddListener(() => { DeleteObject(); });
            GetObjectButton.onClick.AddListener(() => { GetObject(); });
        }
```
- 再トライ。エラーが出ずに、ファイル名が表示されるようになればOKです。別のエラーなどは、AMIロールの権限かbucket名、ファイル名を確認してみてください


### GetObjectのところを画像を取得して貼り替えるものに変更する

- ソースコードを以下のとおり変更

```C#:S3Example.cs
public GameObject imagebox = null; // added 画像を貼り付けるオブジェクトとして利用

private void GetObject()
{
    Client.GetObjectAsync(S3BucketName, SampleFileName, (responseObj) =>
        {
            MemoryStream stream = new MemoryStream();
            responseObj.Response.ResponseStream.CopyTo(stream);
            Texture2D tex = new Texture2D(4, 4);
            byte[] results = stream.ToArray();
            tex.LoadImage(results);
            imagebox.GetComponent<Renderer>().material.mainTexture = tex;        
        }
    );
}
```

- 保存するとCopyToのところで`Assets/Examples/S3Example.cs(130,49): error CS1061: Type `System.IO.Stream' does not contain a definition for `CopyTo' and no extension method `CopyTo' of type `System.IO.Stream' could be found. Are you missing an assembly reference?`がでますが、今回は設定を変更して回避
 - Edit > Project Settings > Player で、Other Settings内のConfigurationのScripting Runtime Versionを`Experimental(.NET 4.6 Equivalent)`に変更して再起動
- Hierarchy内に適当なCubeなどのオブジェクトを追加
 - S3オブジェクトのスクリプトで追加したimageboxに紐付け
- 実行。GetObjectのボタンを押すと、ログのところを消してしまったので、Game画面上は変化ないですが、SceneビューのCubeに画像が貼り付けられます

# オワリ

Windowsでも動きました。回り道してたので、なにかもっとズバッといけるところあれば教えてください・・・