インベントリでアイテムプレビューを表示したい！

タイトルの通りです。解説している記事が見つからなかったので作ります。

# 編集 2022/4/12
コルーチンを使用しない簡単な方法による実装。

# 概要
Unityでゲームを作っていると**インベントリ**などで「アイテムプレビュー」を表示したいときってあると思います。
しかし、UIに3Dオブジェクトを表示させる方法が分からないかったりするのではないでしょうか。

この記事ではRenderTextureを用いることでアイテムの3Dオブジェクトを画像に変換し、RawImageというUI要素に設定することで3DオブジェクトをUIとして表示する方法について紹介します。

# 準備
### プレビュー用の親オブジェクトを作る
まずはプレビューを作るための環境を準備しましょう
まずヒエラルキー左上の＋ボタン＞Create Emptyで親となるオブジェクトを作成します。
名前はてきとうに「PreviewShowroom」などにしてください。

### アイコン撮影用の3Dモデル、カメラを配置
次にそのオブジェクトを右クリック＞Cameraでカメラを配置しましょう。
このカメラがプレビューを表示するためのカメラになります。
カメラを配置したら、てきとうな3Dオブジェクトをカメラに映るような形で配置します。
**3Dオブジェクトは2つ以上用意し、「ItemA」「ItemB」という名前にしてください。のちのち役に立ちます。**
![Screenshot 2022-04-12 21-03-42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496596/b4d7e873-e25c-2454-cd86-05c218021beb.png)


### カメラコンポーネントの変更
カメラコンポーネントをアイコン撮影用に変更します。
背景はいらないので**Clear Flags**を**Depth only**にします。これを行うことで3Dオブジェクトのみが描画されるようになります。

### レイヤーの作成
先ほど作成したカメラで複数の3Dオブジェクトの撮影を行うのですが、そのままでは**アイテムＡのアイコンに関係ないアイテムＢのオブジェクトが写りこんでしまいます**。
カメラに**撮影するレイヤーに設定する**ことでアイテム一つづつの撮影が可能になります。
具体的な例で示すと、アイテムAを撮影するときはアイテムAを撮影レイヤーに、アイテムBをそれ以外のレイヤーに。
アイテムBを撮影するときはアイテムBを撮影レイヤーに、アイテムAをそれ以外のレイヤーに設定することで、カメラに特定のアイテムのみを写すことができます。
レイヤーは右上のLyaer＞Add Layerから増やすことができます。空いている部分に**Preview**レイヤーを追加しましょう。
![Screenshot 2022-04-12 20-31-24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496596/bd8c371d-7620-ef58-6035-6a4e1614388f.png)
作成したらカメラに撮影レイヤーを設定します。**Culling Mask**を一度**Nothing**にした後、**Preview**を選択しましょう。
最終的なカメラコンポーネントの値はこのようになります。
![Screenshot 2022-04-12 20-58-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496596/16e492f3-6de3-cf13-5d1e-b5909f4025ee.png)


### アイコンとなるUIの作成

ヒエラルキー左上の＋ボタン＞UI＞Raw Imageを作成しましょう。
UnityはUIはCanvasというオブジェクトの子として作成され、めちゃめちゃでかい空間に配置されます。まぁそういうものだと思ってください。ヒエラルキー上でオブジェクトを**ダブルクリック**すると位置が分かるので、それで調整してください。

### これで準備は完了

# スクリプト

プロジェクトウィンドウ(ファイルがあるウィンドウ)で右クリック＞Create＞C# Scriptでスクリプトを作成し、名前を「Preview」にしてください(名前が一致しないと動きません)。ファイル内容は全て消し、以下のコードをコピペ(Shift+A, Ctrl+X, Ctrl+C, Ctrl+V)してください。
```cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Preview : MonoBehaviour
{
    [SerializeField] ItemType itemToBeIcon = ItemType.ItemA;
    [SerializeField] GameObject itemShowroom;
    [SerializeField] List<RawImage> icons = new List<RawImage>();

    // Start is called before the first frame update
    void Start()
    {
        icons[0].texture = GetItemIcon(itemToBeIcon);
    }

    RenderTexture GetItemIcon(ItemType item)
    {
        const int previewLayer = 3;
        Camera previewCam = itemShowroom.transform.Find("Camera").GetComponent<Camera>();
        Transform tryItem = itemShowroom.transform.Find(item.ToString());
        if (tryItem == null) return null;
        RenderTexture icon = new RenderTexture(250, 250, 24);
        tryItem.gameObject.layer = previewLayer;
        previewCam.targetTexture = icon;
        previewCam.Render();
        tryItem.gameObject.layer = 0;
        return icon;
    }

    public enum ItemType
    {
        ItemA,
        ItemB,
        ItemC,
    }
}
```

# 再生
てきとうにScriptと言う名前のGameObjectをつくり、Previewスクリプトをドラッグアンドドロップでアタッチします。
次に変数**Item Showroom**に「ItemShowroom」オブジェクト、**Icons**に先ほど作成したRawImageのiconをドラッグアンドドロップします。
再生すると次のようになります。

![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496596/8cd2b1e8-bd81-3705-f73e-9ca7ff12d386.gif)


# 完成！
おつかれさまでした。あとは頑張ってください。
だいたいどうしたらいいかは掴めるはずです。

### 動かない場合
- ヒエラルキーの親子関係が間違ってませんか？
- スクリプトはアタッチしましたか？
- スクリプトの２つの変数に作成したオブジェクトを割り当てましたか？
- レイヤーの設定はできていますか？
- カメラコンポーネントは正しく設定されていますか？