【Unity】UI Toolkitでデジタルサイネージを作ってみよう

![画面収録 2024-12-11 19.42.19.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213392/ad4e4fa5-5e80-2113-21e7-35dcf2a48785.gif)


# はじめに
本記事は、[QualiArts Advent Calender 2024](https://qiita.com/advent-calendar/2024/qualiarts)の12日目の記事になります。

Unityで上記画像のようなサイネージを作るとき、どのような方法があるでしょうか？
これはUIを3D空間上に表示すれば実現できます。

## Canvasを使用する方法
UIを3D空間に表示する一般的な実現方法はCanvasを使用して、World Spaceで配置する方法だと思われます。

![スクリーンショット 2024-12-11 21.36.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213392/a264e920-b4c1-c253-7f72-f5e315b02c65.png)


しかしこの方法には2つの問題があります。

### 問題1: ライティングができない
World Space Canvasはライティングができません。

![画面収録 2024-12-11 19.35.29.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213392/e00401f0-fc1e-8aa5-54ee-dd0afb58ec70.gif)



### 問題2: 平面以外の描画ができない
World Space Canvasは平面に描画されるため、曲面に描画するようなことができません。

![画面収録 2024-12-11 19.40.20-lossy.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213392/ad25f5e7-e253-11cd-1680-db6a4385041f.gif)


## 解決: メッシュに描画する
これらの問題を解決するための方法として、メッシュに描画する方法があります。
メッシュのマテリアルにテクスチャを指定するだけの一般的な方法です。
マテリアルにはRenderTextureも指定することができるため、UIをRenderTextureにレンダリングして、メッシュに描画することで、上記の問題を解決することができます。


![スクリーンショット 2024-12-11 21.21.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213392/b8b2df3f-9d68-d2a5-28e5-c2f6b3719b4e.png)


## UI ToolkitでRenderTextureに描画する
UI ToolkitではUIをRenderTextureにレンダリングすることができます。

これを活用してクリスマスまでカウントするシンプルオブジェクトを作成しましょう。

### 必要なアセット
UI ToolkitでUIをRenderTextureに描画するには3つのアセットと1つのシーン上のコンポーネントが必要になります
| 名称 | 配置場所 | 説明|
| - | - | - |
|UI Documentアセット |アセット | UIの内容を定義するアセット |
|RenderTexture|アセット |UIを描画するRenderTexture|
|Panel Setting Asset|アセット |UI Documentの描画方法を設定するアセット|
|UI Document|シーン |UI Toolkitを実際に描画するコンポーネント|

#### UI Documentアセットの作成
Projectを右クリックして`Create→ UI Toolkit → UI Document`からUI Documentを作成します。 

![スクリーンショット 2024-12-11 19.53.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213392/b36d74ad-4f65-6997-cb28-a93ae66e2ef1.png)

#### 解像度の設定
作成したUI DocumentをダブルクリックするとUI Builderが立ち上がるのでSizeを1200x400にします。

![スクリーンショット 2024-12-11 19.54.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213392/3f589e75-99a8-07e7-0c86-057d356c226f.png)

##### UIの作成
ラベルを使って以下のUIを作成します。
カウントダウン秒数の部分は後ほスクリプトから設定するため、一旦適当な文字列を入れておきます。

::: note
UI Builderの使い方に関しては、以下のマニュアルを参考にしてください。
https://docs.unity3d.com/6000.0/Documentation/Manual/UIBuilder.html
:::

![スクリーンショット 2024-12-11 20.54.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213392/056c2bab-908b-f8ef-5584-3ba67a947b32.png)



#### RenderTextureの作成
UIを描画するRenderTextureを作成します。

Projectを右クリックして`Create→ Rendering → Render Texture`からRenderTextureを作成します。

![スクリーンショット 2024-12-11 19.58.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213392/cc8833d4-0aff-ebe2-7dc1-88a09ba16f23.png)

解像度はUI Builderと合わせて1200x400に設定します。
![スクリーンショット 2024-12-11 19.59.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213392/ccdf669a-8dc4-dfc4-76af-d8a156497539.png)

#### Panel Settings Assetの作成
Panel Settingsを作成して
Projectを右クリックして`Create→ UI Toolkit → Panel Settings Asset`からPanel Settings Assetを作成します。

![スクリーンショット 2024-12-11 20.42.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213392/517066e5-f514-37ef-0989-4902d229093f.png)


- Target TextureにRender Textureを指定
- Scale ModeをConstant Pixel Sizeに設定
- ScaleMode ParametersのReference Sprite Pixel Per Unitを100に設定
![スクリーンショット 2024-12-11 20.44.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213392/6d9663dc-c76c-70d9-8631-42868c1bc3dd.png)

#### シーンにUI Documetを配置
適当なオブジェクトに`UI Document`を追加し、先ほど作った`Panel Settings`と`UI Document`を指定します。

![スクリーンショット 2024-12-11 21.58.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213392/2350edb4-5fd8-f9e2-bf20-fe164a094a5c.png)


これで作成したRenderTextureにUI Documentの内容が表示されます。

![スクリーンショット 2024-12-11 20.50.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213392/d643cb6d-4f80-ef50-8508-4422a4251d95.png)


このRenderTextureをPlaneのEmissionMapに指定するとPlaneにカウントダウンが表示されます。

![スクリーンショット 2024-12-11 20.52.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213392/29d4ff03-c6a1-3200-c587-a01be1a456cc.png)


## Runtime Bindings APIでUI Toolkitの表示をコントロールする。
カウントダウンを行うため、Labelとデータのバインドを行います。
今回はUnity 2023.2で追加されたRuntime Bindings APIを使います。

::: note
Runtime Bindings APIの概要はこちらの動画が参考になります。
https://learning.unity3d.jp/10438/
:::

まずはバインドするクラスを作成します。
```csharp
public class CountdownData
{
    public string text;
}
```

次にUI Builderからカウントダウンを表示するラベルのTextのAdd Bindingを選択

![スクリーンショット 2024-12-11 21.12.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213392/8df2ed98-f771-a287-8979-8d1a2b709e9e.png)

表示されたWindowで
- Data SourceをTypeに設定
- Select Typeボタンを押し`CountdownData`を選択
- DataSourcePathで`text`を選択

![画面収録 2024-12-11 21.09.56-lossy.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213392/bf47f10a-01c0-3a29-e6bf-02e91f98408b.gif)

これでカウントダウンの文字は`CountdownData.text`を参照するようになります。

### バインドする
最後にMonoBehaviourからVisualElementのdataSourceとしてCountdownDataのインスタンスを設定します。

```csharp
using UnityEngine;
using UnityEngine.UIElements;

public class CountdownBehaviour : MonoBehaviour
{
    public UIDocument uiDocument;
    private CountdownData _countdownData;

    private void Start()
    {
        // CountdownDataの作成
        _countdownData = new CountdownData();

        // VisualElementの取得
        var root = uiDocument.rootVisualElement;

        // VisualElementにCountdownDataをバインド
        root.dataSource = _countdownData;
    }

    private void Update()
    {
        // カウントダウンの計算
        var now = System.DateTime.Now;
        var target = new System.DateTime(now.Year, 12, 24, 0, 0, 0);
        var diff = target - now;
        _countdownData.text = $"{diff.Days}日{diff.Hours:00}時間{diff.Minutes:00}分{diff.Seconds:00}秒";
    }
}
```

## 完成
Unityを実行するとクリスマスまでのカウントが始まります。

![画面収録 2024-12-11 19.42.19.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213392/ad4e4fa5-5e80-2113-21e7-35dcf2a48785.gif)