[UE5] Bindless Resourcesを試してみる

# はじめに
この記事はUnreal Engine (UE) Advent Calendar 2024 シリーズ1 12/24(火)としての投稿です

https://qiita.com/advent-calendar/2024/ue

当日夜に枠見てみたら「おっ空いてんじゃーん」ということで書いてみました。

UE5.5でBindless Resourcesの対応プラットフォームが拡充されたということでBindless Texture(Texture Collection)を試してみます。

# Bindless Resourcesについて

Bindless ResourcesはBindless Renderingの機能の一つです。
大量のテクスチャをマテリアル内で動的に切り替えて使用したりできるようになります。

https://portal.productboard.com/epicgames/1-unreal-engine-public-roadmap/c/1709-bindless-rendering

説明があまりないのでChatGPTに聞いてみました
>Unreal Engine 5（UE5）におけるバインドレスリソース（Bindless Resources）は、シェーダー内でリソースをより柔軟かつ効率的にアクセスするための機能です。従来のスロットベースのバインディングモデルでは、各リソース（テクスチャやバッファなど）を個別にバインドする必要がありましたが、バインドレスリソースを使用すると、これらのリソースを事前に大規模なテーブルとしてGPUに提供し、シェーダー内でインデックスを使用して動的にアクセスできます。

ですね。

# 設定
まず設定を変更してBindless ResourcesとBindless Sampersを有効化しておきます。
プロジェクト設定からは変更できないため直接 _Config\DefaultEngine.ini_ に以下の記述追加してください。

~~~Config\DefaultEngine.ini
[PCD3D_SM6]
BindlessResources=Enabled
BindlessSamplers=Enabled
~~~

![99_config.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624395/349f52fb-b5ce-bde2-d27d-89c8e3dcd948.png)

ちなみに以下みたいな記述だとマテリアル作業中にエディタがハングしたので _Enabled_ で記述する必要があります。
_BindlessResources=1_
_BindlessSamplers=1_

# TextureCollectionデータアセット

Bindless Resourcesでテクスチャのインデクスアクセスを行う場合、TextureCollectionデータアセットを作りそこに登録しておく必要があります。

データアセットの作成を選択し、インスタンスクラスは _Texture Collection_ を選んで「選択」
作成されたデータアセットにテクスチャを登録してください。

![00_data_asset.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624395/5a8ffbd9-974a-b892-719c-1d46fcd6dfde.png)
![01_data_asset.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624395/55c0c7d6-2886-396b-d996-f087a8d8bd6f.png)
![02_data_asset.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624395/110b8381-d502-bd6e-dc22-c27df36313ad.png)
![10_textures.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624395/4fd7f3e7-0fcd-dfc1-bb61-276c6118c160.png)

# マテリアル
## マテリアルノード

主に使用するマテリアルノードは以下になります。
* TextureCollectionParameter
* TextureObjectFromCollection
* BindlessSwitch

![20_material_node.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624395/51326ae5-990c-dcf7-0cc1-b85c5a7d29b7.png)

名前から大体察していただけると思うので説明は省きます。

## マテリアル例

機能を確認するためのマテリアルを組んでみました。
IdTextureの内容でTextureCollectionの中から使用するテクスチャを動的選択する内容です。

![30_material.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3624395/4daccd94-8098-05ca-59dd-1d3483ae27f4.png)

補足説明しますと
* TextureCollectionParameterにTextureCollectionデータアセットを設定してください
  * マテリアルインスタンスで差し替え可能  
* TextureObjectFromCollectionのCollectionIndex入力へはFloatToUIntなどを挟んでInt化する必要があります
  * Int化しないと接続できません
* TextureObjectFromCollection出力を入力したTextureSampleは _Sampler Source_ をSheredのどれか使用するように変更が必要です

# 使用用途

主な用途としては今までTexture2DArrayでないと出来なかったテクスチャのインデクス選択の置き換えだと思います。
Texture2DArrayだと複数テクスチャのどれか1枚でも差し替えた別セットを持とうとすると、他も重複して複製するする必要がありメモリを圧迫しました。Bindless Resourcesならピンポイントで差し替えしつつインデクスアクセスを実現できるためメモリ効率が向上します。

ソレイユさんの講演などでもあったスマートマテリアルが扱いやすくなると思います。

https://www.docswell.com/s/EpicGamesJapan/KXREYK-UE_UFE22W_SQEX_Soleil#p34

# 後期
GDCでのUE4やUE5タイトルのセッション内でBindless Textureを自前対応したという話がちょくちょく出てきていました。公式の対応広がって手が出しやすくなったと思います。

あと、実はNanite描画内で自動的にスマートマテリアルみたいにDraw Callをまとめる仕組みが入っているらしいと聞いたのでそれも確認しておきたいですね。

# 参考

https://sites.google.com/site/monshonosuana/directx%E3%81%AE%E8%A9%B1/directx%E3%81%AE%E8%A9%B1-%E7%AC%AC187%E5%9B%9E