【UE】Widgetを曲げる

## 初めに
Unreal Engineを使って開発をしていると、平面ではなく曲面のWidgetを使いたくなる場合があると思います（ありますよね？）。そういったときに平面のWidgetではなく曲がった（カーブした）Widgetの作成方法を紹介します。

## 環境情報
Windows 11
UE 5.3.2

## 作成手順
### ①Widget Blueprintを作成する
まずは曲げる大元になるWidget Blueprintを用意します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/b8987dcd-6899-d2e7-993b-c73372734b78.png)

制限は特にないので今回のサンプルにはBorderの上にボタンを3つほど用意してみました。

### ②Widget用のアクターを用意する
Blueprintでアクターを設定してクラスを作成します。
左の「Add」でWidget Componentを追加します。
「Details」内の「Widget Class」に①で用意したWidgetを指定します。
「Draw Size」は必要に応じて調整してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/c02ade3c-a3cb-c48a-7a31-5abf8756240d.png)

### ③曲げる設定を行う
「Details」内の「Geometry Mode」がデフォルトでは「Plane」になっているところを「Cylinder」に変更します。
「Cylinder Arc Angle」の数値を変更することで1.0～180.0の間で曲げる角度を調整できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/de6d7baa-e193-346c-b0dc-0689f3dee891.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/9ee82622-6090-33b6-812e-9eb0732dd730.png)

これで無事にWidgetを曲げることができました。と、言えなくもないのですがいくつか補足させてください。
この方法でWidgetを曲げるのは凹側にしか曲げられません。「Cylinder Arc Angle」マイナスの値を入れれば凸側に曲げられるのではないかと思いましたが、マイナスの値を入れても1.0に戻されてしまいます。「Geometry Mode」に好きなメッシュの形を割り当てられないかとも思ったのですがそれもできないみたいです。

なので凸側に曲げるのは不可能かと思いきや、一応可能ではあります。ただボタンなどを配置すると問題が発生するので非推奨です。あくまで操作するUIが存在せず、表示用のUIとして凸側に曲がったWidgetを作成する方法と考えていただきたいです。

## 凸側にWidgetを曲げる方法
マテリアルを改造してWidgetを無理やり逆側に曲げていく方法になります

### ①Widgetに使われているマテリアルを見つける
Widget componentにはデフォルトで「Widget3DPassThrough_Masked_OneSided」というマテリアルインスタンスが割り当てられています。このマテリアルインスタンスの親であるマテリアルを見つけます。
フォルダーに虫眼鏡がついているアイコンを押すと、Editorでマテリアルインスタンスが格納されている場所に移動できます（別ウィンドウ化していると切り替わっているのに気づきにくいので注意）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/b500a718-1f88-1189-8e77-c419b14dc998.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/dcea2c7b-8019-5cd5-21d8-c36e8539dbf6.png)

マテリアルインスタンスを開いて親マテリアルを確認してみると「Widget3DPassThrough_Opaque」が割り当てられており、こちらもマテリアルインスタンスなので再度親マテリアルを探します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/bf990ca4-fd93-83d1-8f66-f5f51c477832.png)

またまたマテリアルインスタンスなので再度親マテリアルを探します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/b8f4f547-63e2-5c42-c0d7-0ae6f30626b9.png)

ようやく親マテリアルが見つかりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/a5ef5310-8940-0ebf-791e-231acec97a07.png)

関係としては「Widget3DPassThrough」→「Widget3DPassThrough_Opaque」→「Widget3DPassThrough_Masked_OneSided」の順番でマテリアルインスタンスが生成されています。
「Widget3DPassThrough」の中身を直接編集してしまうと他に影響が出てしまうのと、エンジンをアップデートした際に上書きされてしまうので「Widget3DPassThrough」、「Widget3DPassThrough_Opaque」、「Widget3DPassThrough_Masked_OneSided」それぞれのコピーを作成する方が無難かと思います。

今回は下記のようにそれぞれコピーしたマテリアルを用意します。
「Widget3DPassThrough」→「Widget3DPassThrough_reverse」
「Widget3DPassThrough_Opaque」→「Widget3DPassThrough_Opaque_reverse」
「Widget3DPassThrough_Masked_OneSided」→「Widget3DPassThrough_Masked_OneSided_reverse」

### ②Widget3DPassThrough_reverseに変更を入れる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/047f5afe-6914-2e8c-c7e0-3aff790056d3.png)
■SlateUIに対して
・TextureCoordinateを追加
・CustomRotatorを追加
・Constantを追加して値を0.5にする

図のように接続してSlateUIのUVsにつなげる

■World Position Offsetに対して
・ActorPositionWSを追加
・WorldPositionを追加
・Subtractを追加
・Multiplyを追加
・Constantを追加して値を-1.0にする
・OneMinusを追加

図のように接続してWorld Position Offsetにつなげる

### ③コピーしたマテリアルインスタンスの親マテリアルを変更する
コピーしたマテリアルインスタンスにはそれぞれコピーする前のマテリアルが親に設定されているので、コピーしたものに入れ替えます。

・Widget3DPassThrough_Opaque_reverse
「Widget3DPassThrough」→「Widget3DPassThrough_reverse」

・Widget3DPassThrough_Masked_OneSided_reverse
「Widget3DPassThrough_Opaque」→「Widget3DPassThrough_Opaque_reverse」

### ④Widget Componentのマテリアルを変更する
Widget Componentに割り当てられているマテリアルをコピーしたマテリアルに変更します。
「Widget3DPassThrough_Masked_OneSided」→「Widget3DPassThrough_Masked_OneSided_reverse」

これを行うことで無事に凸側にWidgetを曲げることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498810/edb3f88d-8181-400c-ccf5-d3ab105ccd48.png)

### 注意事項
凸側にWidgetを曲げることができましたが、これはどうやら見た目上凸側に見えているだけであり、実態は凹側に曲がっているようです。なのでボタンなどインタラクション行う部品を押そうとすると見た目と実態がずれてしまい、見た目上押せそうなのに押せなかったり別の部分を押してしまうことが発生します。曲げる角度が緩やかでボタンなども十分大きい場合はそこまで問題ないかもしれませんが、やはり表示用のWidgetとして使うのが無難かと思います。

個人的にはエンジンのアップデートで「Cylinder Arc Angle」の値を変更すれば凸側にも凹側にも自由に曲げられるようにしてほしいところです。