【UE5】Geometry Scripting：UVプロジェクション関数のTransformの使いかた

:::note info
UE5.2.1時点での内容です
:::

:::note info
Geometry Scriptingを使うには、Geometry Scriptプラグインを有効にする必要があります。
:::

# Set Mesh UVs from 〇〇 Projection関数

Geometry Scriptingに用意されている Set Mesh UVs from 〇〇 Projection関数は、その名の通り、Box投影などでDynamic MeshのUVを決めてくれる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/8db8b0f9-5a4b-9ede-d92d-e5ba514d6510.png)
ところが、例えば以下のように、Boxポリゴンを作って、UVをBoxプロジェクションで決めようとすると…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/dfff6e7b-fb59-48c7-883b-e82fb8055264.png)
まるでバグったような絵になってしまう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/f276c16b-497d-dc78-e6bf-96981c94696e.png)
思わず「まだExperimentalだし、この関数はもういいか…」と諦めてしまいそうだ。

# Transformに与える値がキモだった

エンジンソースを見たり、試行錯誤をしたりした結果、引数Transformに適切な値を与えるとうまく動くことが分かった。

## Scale値には「実際の大きさ」を入れる

まず何はともあれ、Transform型の引数を右クリックして「Split Struct Pin」する。そして、Scale値に「実際の大きさ」を入れる。つまり、Unreal単位(1cm単位)での数値を入れる必要がある。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/57c14ec5-c6d0-2858-1f99-2a388f84a818.png)
そうすると、非常にまともな絵になってくれる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/4c15ad9b-473f-47b8-4697-1b5f347a38fb.png)
この例はシンプルなBoxなので、大きさを変数で持っている。そのため、その変数をそのままScaleに代入すればよい。
一方、色々足したり引いたりしてできた複雑な形状の場合は、そのサイズを変数に取っておけたり、計算で求めたりすることができない場面もあるだろう。その時はTarget MeshのBounding Boxからサイズを求めると良いだろう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/5c9f0f56-9849-b1d6-f725-64c6fc91b74b.png)

:::note info
Scale値には「必ず実際のサイズを入れなさい」という決まりはない。実際のサイズは単なる基準値である。
例えば、メッシュのサイズの２倍の値を入れれば、UVは0.5倍のスケールになる(拡大される)。逆に、メッシュのサイズの0.5倍の値を入れれば、UVは2倍のスケールになる(縮小される)。
:::

## Locationは「UVの原点に相当する点を3D空間中のどこに置きたいか」を指定する

先ほどのBoxは、よく見るとUVの原点が Box各面の中央に来ている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/93c672ce-f4cd-c2bf-737c-bc8bf4ed08ec.png)
「a01」がテクスチャの(0,0)付近にあるのだが、この「a01」ブロックが面の中央付近にある。
TransformのLocationに(0, 0, 0)を与えた場合、3D座標の(0, 0, 0)にUVの原点(0, 0)を置いた状態でプロジェクションされる。結果として、UV=(0, 0)はBoxの面の中央に来る。
もし、UVの原点(0, 0)をBoxの頂点に合わせたい場合は、TransformのLocationにいづれかのBoxの頂点の座標を入れればよい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/814eebf2-d260-7fa4-6b7c-6584d645a8a9.png)
例えば、Bounding BoxのMinがBoxの頂点にあるはずなので、それをLocationに代入する。
そうすると、UVの原点(0,0)がBoxの頂点に合った絵になってくれる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/7f335071-fdc0-cc07-5f81-40367102ae6c.png)

# Cylinder Projectionの場合

Cylinder Projectionの場合も考え方は同じで、Scaleに実際のサイズを入れると、円柱をまるっと包んだUVになってくれる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/d97a9a95-a2e1-d262-af4a-f461a1e2fdfc.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/d02a4d8e-7634-250e-42af-34dc3889cd41.png)
ただし、円柱の上下面は中心がUV=(0, 0)になってしまう。
これに対処しようとして、TransformのLocation値のX, Y値をずらしてしまうと、円柱の側面のUVがおかしくなる。例えば、Location=(Radius, Radius, 0)とすると以下のような絵面になる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/e4d44d46-477b-4cd8-1c67-37e66ad85f1c.png)
円柱の上下面のUVは狙い通りだが、円柱の側面のUVが意図しないものになっているのが分かる。
Set Mesh UVs from Cylinder Projection単独で、この問題を回避することはできない。結局、TransformのLocationのX, Yにはゼロを入れておく必要がある。

:::note info
Set Mesh UVs from Cylinder ProjectionのTransformのLocationのX, Yはゼロにしておいて、その後、①上下面を選択する、②Translate Mesh UVsで選択した面のUVをずらす、とすれば、上下面のUVだけ調整することは可能である。
:::