推しと一緒に写真を撮りたい！Unityで作る「推しCAM」

# はじめに
こんにちは。ponponnsanです。最近はジムと着物の着付けを始めて人生が充実しています。
やはり人生を豊かにしてくれるのは趣味ですね。

さて今回は、[アドベントカレンダー2024のクソアプリ](https://qiita.com/advent-calendar/2024/kuso-app)企画記事です。

# 目標
推しの画像(png透過済み)と、webカメラを起動させて、unity上で写真を撮るところまでをゴールとします。

# 宣伝
:::note info
冬コミでサークル参加します！
**ふんわりaiラボ**
**12/30　東Z 38a**

以下お品書き
- 生成AIを使ったゲームの作り方
- 生成AIで作成したキャラクターと一緒に写真を撮ろう
当日参加される方はよろしくお願いします！
:::

サークルのアカウント↓

https://x.com/kaggle_RUMIKO

本当はアプリでカメラで背景と推しの画像を撮れればいいのですが、App Storeに開発者として登録するのにお金が一万円くらいかかります。

そこで！冬コミに参加することにしました。あと単純に参加してみたかった。
ここでお金が稼げば次のステップへ行くことができるので、もしよければ立ち寄ってみてください。

え？もう既存のアプリがある？そういうことじゃないんです。作りたいんです、クソアプリ。

# 初めてのUnity
初めてUnityを触る方は以下の通りに設定すれば大丈夫です。
ちなみに私はmacを用いているので、mac用のインストール方法を説明したいと思います。


## インストール
まず、macでUnity6をインストールするための要件を表にまとめました。満たしていない場合、不具合等の原因になるのでPCに合わせてに適切なバージョンをインストールしてください。

| 項目               | 要件                                                                 |
|--------------------|----------------------------------------------------------------------|
| **オペレーティングシステム** | macOS Big Sur 11.0または後世代                                  |
| **CPU**            | Apple M1または後世代、Intel x64 architecture (SSE2命令セットサポート) |
| **グラフィックスAPI** | Metal-capable IntelとAMD GPU                                          |
| **メモリ**         | 16GB以上                                                             |
| **ストレージ**     | SSD推奨、10GB以上の空き容量                                          |


インストールする手順としては以下の通りです。

1. Unity hubをインストールする
2. Unity IDを作成する
3. Unityをインストールする

それぞれ追っていきましょう。

### Unity hubをインストールする
Unity hubとは、Unityのプロジェクトとバージョン管理を中心にしたツールです。古いバージョンと最新のバージョンのインストールが同じPCで管理できたり、バージョン違いのプロジェクトを簡単に切り替えられたりできます。

Unityはアップデートされることも多いため、バージョンが変わることで開発中に動かなくなるトラブルを防ぐことができます。

[こちら](https://unity.com/download)のサイトに行き、ダウンロードボタンをクリックすると自動的にmac用のUnity hubがダウンロードできます。

<img width="700" alt="Hierarchyウィンドウ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159060/bc888a70-5420-4577-4923-aa4b20a1fc51.png">


### Unity IDを作成する
次はUnity IDの登録です。Unityの使用やアセットストアでの購入、ライセンス登録にも使用されます。

MacにインストールしたUnity hubをクリックすると、下記の画面が表示されます。

<img width="700" alt="Hierarchyウィンドウ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159060/225f6a73-d211-601a-18c0-c33a8479c0ec.png">

初めての場合は`create account`を押し、アカウントを作成します。
googleアカウントとの連携ができるので、私はgoogleアカウントで作成しました。

### Unityをインストールする

UnityIDでログインしたら、続いてUnityをインストールします。
`Install`から`Install Editor`を選択すると、以下の画面が出てきます。

<img width="700" alt="Hierarchyウィンドウ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159060/1188f4c9-284d-4e5a-bc36-40ab938df6cd.png">

`🍎Sillicon`と記載のあるUnityエディターを選択してインストールを実施してください。
以下のように表示されていればOKです。

<img width="700" alt="Hierarchyウィンドウ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159060/66c53a02-5969-1e8e-2db9-c4581fb8a52b.png">

これでUnityのインストールは完了です！

# 推しCAM
Unityを初めて触る人は大変だったかもしれませんが、ここからが本番です。推しと一緒に写真を撮っていきましょう！

## セットアップ

メイン画面の`Projects`から`New Project`をクリックします。

<img width="700" alt="Hierarchyウィンドウ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159060/95117a60-31d7-105b-4ea1-ac56d314c946.png">

そこで、`All templates`から`Universal 2D`を選択し、任意のプロジェクト名と保存場所を設定してください。
`Unity Organization`はデフォルトで問題ないと思います。

### 推しの画像の用意
さて、一番楽しい推し画像の選別です。
選りすぐりの推し画像を選んでください！

今回は冬コミに参加するのもあり、サークル公式キャラクター「華操るな」と一緒に写真を撮りたいと思います。通称るなちゃんです。
ちなみに、Stable Diffusionで作成しています！

<img width="500" alt="Hierarchyウィンドウ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159060/fdd59fa4-9d3d-a804-792a-9a9e46f60a93.png">
    
:::note warn
用意する画像について
pngの背景透過画像であることが前提です。

たまにキャラクターを含めた全ての範囲に対して透過をかけている画像があります。
この場合は、下記の方法で操作してもカメラでキャラクターが表示されなかったりするので、注意してください！
私の場合はこれでなかなか画像が表示されず3日ほど進捗がなかったです。
:::


## ウェブカメラの設定

1. **HierarchyウィンドウにRawImageを追加**:
   - Hierarchyウィンドウで右クリックして、`UI` > `RawImage` を選択して、シーンにRawImageを追加します。
   <img width="500" alt="Hierarchyウィンドウ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159060/97213aec-982a-e266-f96e-7cdbf3a4a07e.png">




2. **WebCamTextureを使用するスクリプトを作成**:
   - 新しいスクリプト（例： `WebCamController`）を作成し、以下のコードを入力します。
   スクリプトは、Assetsで右クリックして、`Create` > `Scripting`　> `Empty C# Script`から空のファイルを作成します。
   <img width="700" alt="Hierarchyウィンドウ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159060/1490885b-767e-f726-4aac-31c4f1149b1a.png">

   
   ```csharp
    using UnityEngine;
    using UnityEngine.UI;
    
    [RequireComponent(typeof(RawImage))]
    public class WebCamController : MonoBehaviour
    {
        WebCamTexture webcamTexture;
        RawImage rawImage;
    
        void Start()
        {
            WebCamDevice[] devices = WebCamTexture.devices;
            webcamTexture = new WebCamTexture(devices[0].name, 1920, 1080, 30);
            this.rawImage = GetComponent<RawImage>();
            this.rawImage.texture = webcamTexture;
            this.rawImage.enabled = true; // ここではtrueに設定して、カメラ映像を表示します。
            webcamTexture.Play();
        }
    
        void TakeShot()
        {
            // 以下は、写真を撮影してTexture2Dに変換するためのコードです。
            Texture tex = this.rawImage.texture;
            int w = tex.width;
            int h = tex.height;
            RenderTexture currentRT = RenderTexture.active;
            RenderTexture rt = new RenderTexture(w, h, 32);
            Graphics.Blit(tex, rt);
            RenderTexture.active = rt;
            Texture2D result = new Texture2D(w, h, TextureFormat.RGBA32, false);
            result.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
            result.Apply();
            RenderTexture.active = currentRT;
    
            // ここで、撮影した画像をゲームオブジェクトに適用します。
            GameObject plane = GameObject.Find("Plane"); // Planeオブジェクトを探す
            if (plane != null)
            {
                plane.GetComponent<MeshRenderer>().material.mainTexture = result;
            }
        }
    
        private void Update()
        {
            if (Input.GetMouseButtonDown(0))
            {
                TakeShot();
            }
        }
    }

   ```

このスクリプトをRawImageオブジェクトにアタッチします。

アタッチ済みのRaw Image Inspectorは以下の通りです。
<img width="400" alt="Hierarchyウィンドウ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159060/faa67c17-b014-2c9e-4393-9a2893f9fa71.png">



## ウェブカメラ映像上に透過画像を表示
ウェブカメラ映像上に透過PNG画像を重ねるには、**Canvasを使ってUI要素として画像を配置する方法**が一般的です。以下の手順で実装を試してみてください。

1. **Canvasを設定する**  
   - Hierarchyで`Canvas`を右クリックして追加し、`Render Mode`を`Screen Space - Overlay`に設定します。
   <img width="400" alt="Hierarchyウィンドウ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159060/22fe9d67-34fa-d66a-3baa-0c289e79f066.png">

   - `Canvas`に、`RawImage`（ウェブカメラ映像用）と`Image`（透過画像用）を子要素として追加します。
       ```
       Canvas
       ├── RawImage (ウェブカメラ映像用)
       └── Image (透過PNG用)
       ```

2. **透過PNG画像用のImage設定**  
   - `Image`オブジェクトを選択し、Inspectorで`Source Image`に表示したい透過PNG画像を設定します。  
   - 位置や大きさを調整して、カメラ映像に重ねる形に配置します。
   

    <img width="400" alt="Hierarchyウィンドウ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159060/92081b14-7649-2ddd-b55a-1abf01e54114.png">
    

3. **ウェブカメラの映像をRawImageに表示**  
   すでに作成した`WebCamController`スクリプトを使用して、ウェブカメラの映像を`RawImage`に表示します。
   `RawImage`に`WebCamController`スクリプトがアタッチされているか再度確認してください。


次は、写真撮影です。

## 透過画像の撮影設定

1. **Unity Recorderのインストール**:
   - `Window` > `Package Manager`を開き、`In Project`から`Recorder`をインストールします。
   <img width="500" alt="Hierarchyウィンドウ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159060/e936f5b1-6cba-5e5b-9b6c-0627f2253697.png">


2. **カメラの背景設定を変更**:
   - `Main Camera`の`Clear Flags`を`Skybox`から`Solid Color`に変更し、背景色を透明度MAX（黒や白など）に設定します。これにより、背景が透過されるようになります。

3. **Recorder Windowの設定**:
   - `Window` > `General` > `Recorder` > `Recorder Window`を開きます。
   - `Add Recorder` > `Image Sequence`を選択し、以下の設定を行います。
     - `Recording Mode`を`Single Frame`に変更
     - `Source`を`Texture Sampling`に変更
     - `Media File Format`を`PNG`に変更
     - `Include Alpha`にチェックを入れる。

    <img width="500" alt="Hierarchyウィンドウ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159060/1f5488a6-5aff-e855-4f46-3c054523a57c.png">


4. **撮影**:
   - `Main Camera`を選択し、シーンビューで好きな視点に調整します。
   - Recorderウィンドウで再生ボタンを押して撮影を開始します。Gameウィンドウをクリックすると、画像が指定したファイルに保存されます。

実行ボタンを押したはいいが、どこに保存されているか確認したいですよね。
Unity Recorderを使用して撮影した画像や動画は、以下の方法で保存先を指定および確認できます。

## デフォルトの保存先

- デフォルトでは、保存されたファイルはプロジェクトのフォルダ以下の`Recordings`フォルダに保存されます。ファイラーでここまで辿って開くことも可能です。

    recordingフォルダは、プロジェクトの階層構造で表すと以下に位置しています。
    VScodeなどで確認してみてください。
    ```
    ProjectName
    ├── Assets
    ├── Library
    ├── Logs
    ├── Packages
    ├── ProjectSettings
    ├── Recordings # ここ！
    ├── Temp
    └── UserSettings
    ```

## 保存先の指定

- Recorderウィンドウで、`Output File`セクションにある`Path`フィールドを使用して保存先のフォルダを指定できます。ここで「…」ボタンをクリックして、任意のフォルダを選択できます。

<img width="700" alt="Hierarchyウィンドウ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159060/88eee61f-2d7e-86b2-7fe4-a461236da624.png">


実際にRecordingsフォルダに保存されていましたが、
撮影した際のpngの画像は以下の通り、何も写っていないというものでした。
<img width="500" alt="Hierarchyウィンドウ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159060/7ed3a7a9-fe22-0a98-485c-3b52b4276177.png">



Recorderウィンドウで、SourceをGame Viewに変更します。
<img width="500" alt="Hierarchyウィンドウ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159060/f6f61c57-f382-14a2-2978-17522dc50ad1.png">


無事、撮ることができました！


![Image Sequence_021_0000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1159060/f9d0a0a8-0488-145d-c803-6623c570c022.png)

このように風景と一緒に撮ると聖地巡礼とかでも活躍しそうです！！

# まとめ

- ウェブカメラの映像をRawImageで表示し、撮影ボタンを押すと、`TakeShot`メソッドが呼ばれて、撮影した画像をTexture2Dに変換し、ゲームオブジェクト（例： Canvas）に適用します。
- 透過画像の撮影は、Unity Recorderを使用して、背景が透過された状態で撮影します。



# 参考文献
https://cad-kenkyujo.com/unity-mac/

https://zenn.dev/imasaka0909/articles/09973aaaf45b87

https://nn-hokuson.hatenablog.com/entry/2021/10/11/102433

https://docs.unity3d.com/ja/2017.3/Manual/windowsholographic-photocapture.html

https://note.com/teya3_sedum794/n/n1f3b8e554e8d

https://note.com/omake13/n/n9ceb4a604896

https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q11305435091

https://docs.unity3d.com/ja/560/Manual/windowsholographic-photocapture.html

https://note.com/npaka/n/nbaa0e466b0de

https://wataameko.com/workbook/unity2018-recorder/

https://soredemo-apparel.net/vfx-and-3dcg/howtouse_unity_recorder

https://miyukifueda.hatenablog.com/entry/unity-recorder-screenshot

https://qiita.com/Nekomasu/items/dcdf73f221fd64875ef0