LoginSignup
1
2

【UE5】WaterSystemのメッシュ生成フローについて

Last updated at Posted at 2024-03-01

概要

UE4の後半で追加されたWaterSystemですが、UE5.1辺りでまた大きく実装が変わりました。この記事では、現在のWaterSystemがどうメッシュを生成しているかを解説します。また、後半には調整するうえで引っ掛かりやすい点の紹介などもまとめています。

この解説を元に、意図したメッシュが出ない場合にどこを確認/調整したらいいのかの一助になれば幸いです。

なお、この記事は UE5.3 で調査して書かれています。

フロー概略

image.png
上図のようなWaterBodyRiverを例にまずは概略から説明します。

WaterBodyRiverの場合、情報の起点はSplineComponentになり、以下のようなデータを経由して最後は、表示されているWaterZoneMeshが生成されています。

SplineMeshComponent → コリジョンメッシュ

WaterBodyInfoMesh

WaterInfoTexture

WaterMesh(WaterZone)

SplineMeshComponent → コリジョンメッシュ

まずはコリジョン生成から紹介します。
image.png
上図はViewModeをプレイヤーコリジョンに変更した結果です。分かりやすくするため、WaterZoneMeshも非表示にしています。

このように、スプラインセグメント(スプラインポイントの間)当たり4枚の三角形で構成されています。これはスプラインがどんな曲率を持っていても変わりません。

左図のように、中央部を大きく盛り上げてもスプラインセグメントごとのコリジョンメッシュが分割されることはありません。

その結果、スプラインの曲線と乖離することがあり、見た目とコリジョンの相違につながる場合があります。

セグメント当たりのポリゴン数が決まっているので、これを回避するにはスプラインポイントを増やすしかありません。

これは、コリジョンメッシュが
Engine/Plugins/Experimental/Water/Content/Meshes/RiverMesh.uasset
というアセットに依存しているためです。このアセットには左図のようにコリジョンが設定されていて、それが使われています。

なお、このアセットはエンジンプラグイン内にあり、またプラグインのソースコードから直指定されていますので、エンジン改造をしない限り変更はできません。

(プラグインなので、プロジェクトプラグインにコピーして改造するという裏技は使えます)

SplineMeshComponent → WaterBodyInfoMesh

image.png
まず、WaterBodyInfoMeshとは何か。最終的に表示されるメッシュではなく、Waterの基本形状(波などの影響はない状態)を定義した中間データです。

出来るだけSplineMeshComponentの形状に沿うようにポリゴン分割されたメッシュが作られます。

ポリゴン分割の処理は、
USplineComponent::DivideSplineIntoPolylineRecursiveWithDistances()
で行われています。

ざっとアルゴリズムを書くと、

  1. スプラインセグメント間の線形補間での中間点(点A)の座標を求める
  2. スプラインセグメント間のスプライン補間での中間点(点B)の座標を求める
  3. 点Aと点Bの距離が一定(WaterBodyRiverの場合は5.0)以上なら、分割する

という処理を繰り返します。

この処理により、スプライン形状に即したメッシュが生成され、次のWaterInfoTextureへの描画に使われます。

WaterBodyInfoMeshのデバッグ表示について

コンソールコマンドで r.Water.WaterInfo.ShowSceneProxies 1 と入力することで確認できるようになります。前項で貼った図では、さらに 表示フラグ>詳細設定>メッシュエッジ を有効にしてWireframeも表示しています。(ライティングされていないメッシュは形状が分かりずらいので…)

r.Water.WaterInfo.ShowSceneProxies はUE5.3からの機能です。

UE5.2では r.Water.VisualizeWaterInfoSceneProxies と少し違うコンソールコマンドで実装されていて、選択されたWaterBodyのWireframeだけが表示されるようになっています。

WaterBodyInfoMesh → WaterInfoTexture

image.png
次はWaterInfoTextureへの描画です。WaterBodyInfoMesh をRenderTextureに描画する際、Velocityや水深に関する情報など、WaterSystemにかかわる情報をまとめてテクスチャに描画します。
image.png
ここで重要になるのがWaterZoneの設定で、RenderTargetResolutionとZoneExtentです。

WaterZoneの位置からZoneExtentの範囲を、RenderTargetResolutionで指定したテクスチャに描画しますので、ZoneExtentの外側にWaterBodyがはみ出していると正常に描画されません。
広大なZoneExtentに対してRenderTargetResolutionが十分でないと、このようにWaterが地形に対してはみ出したりします。
以前は、WaterZoneがワールドに一個しか置けなかったため、広大なワールドを扱う場合はメモリか解像度かのトレードオフが発生していました。

しかし、UE5.1からはWaterZoneが複数置けるようになっていますので、必要な範囲に必要な解像度を割り当てることがしやすくなっています。さすがに、WaterZoneとWaterBodyを一対一で割り当てるのは無駄ですが、エリア単位に区切ってWaterZoneを配置していくとメモリも処理負荷も軽減できそうです。

WaterInfoTextureの確認方法

WaterInfoTextureはWaterZoneの詳細パネルにあり、一時的なテクスチャですがダブルクリックすることでテクスチャビュワーで確認が可能です。

image.png
なお、各チャンネルには

  • R → Velocity.x
  • G → Velocity.y
  • B → 正規化された地面の高さ
  • A → 正規化された水面の高さ

が格納されています。

WaterInfoTexture → WaterMesh(WaterZone)

image.png
生成したWaterInfoTextureを元に、表示に使うWaterMeshを生成します。設定の仕方は

公式ドキュメントにまとまっているのでそちらを参照してください。

調整方法の例

WaterMeshはテッセレーションで分割されるので、元の形状が少々分かりづらく調整がややこしく感じます。そこで、以下の対応をして形状を確認しやすくしていました。

  • r.Water.WaterMesh.ShowWireframe 1 でWaterMeshをWireFrame表示にする
  • WaterZone>レンダリング>TessellationFactorを1にする
    • Tessellationによる分割を無効にする
  • Landscapeを非表示にする
    • Landscapeに埋もれている部分が見えないので

image.png
この結果が上図になります。この状態で基本となるTileSizeを調整し、その後ZoneExtentを更新するとExtent in Tilesが自動計算されます。

コリジョンと表示メッシュ(WaterMesh)が一致しない場合

開発をしていると、WaterSystemのコリジョンと表示メッシュが一致しないという問題に遭遇することがあります。前段までの説明の通り、コリジョンと表示メッシュの間には中間データがいくつも挟まっており、問題の切り分けをしないとどのパラメータを調整すべきか見えてきません。

次の項からはよくある差が出るポイントと、対処方法を紹介します。

SplineMeshComponentとコリジョンメッシュの差

image.png
SplineMeshComponent → コリジョンメッシュの項目でも紹介しましたが、コリジョンメッシュはセグメント当たり4枚の三角形で構成されています。(正確には厚みもありますが…)

そのため、スプラインの設定によっては上図のようにスプラインとコリジョンの間に大きな差が生まれることがあります。

調整方法

image.png
スプラインセグメント当たりのポリゴン数が決まっているので、スプラインポイントを増やしてやれば差を少なくすることができます。ただ、接線をいじっている場合は、増やしたスプラインポイント含めて接線の再設定をしないと同じ形状にはなりませんし、ちょっと形状を調整したい場合でもスプラインポイントが少ない状態より手間が増えます。

WaterBodyInfoMeshとWaterMeshの差

解像度が足りている状態 解像度が不足している状態
image.png image.png

WaterBodyInfoMesh → WaterInfoTexture の項で触れましたが、WaterInfoTextureの解像度が足りないとWaterBodyInfoMeshとWaterInfoTextureの差が大きくなります。上図はちょっと極端な例ですが本来はLandscapeの溝に沿って水面が置かれるはずが、Landscapeの下に潜ってしまったり、溝からはみ出したりしてしまっています。

調整方法

これは単純に解像度調整をするしかありません。デフォルトでは、100.0(=1m)あたり1pixelの解像度になっているのでそれが基準になると思います。

WaterZoneの中心からZoneExtentのサイズの範囲を扱いますので、関連するWaterBodyがあるエリアの中心にWaterZoneを置いて、ZoneExtentの大きさを必要最小限にすることで適切な解像度を得やすくなります。

また、複数のWaterZoneを配置できるようになっていますので、無理に広い範囲をカバーする必要はなく、WaterZoneは適宜分割することをお勧めします。

あとがき

今回はWaterBodyRiverをベースに説明を書きましたが、他のWaterBodyLakeやWaterBodyOceanも似たような手順でメッシュを生成しています。
WaterBodyInfoMeshの存在は意外と気づかないので、そこに気づくと意外と調整もはかどるのではないかと思います。

ただ気を付けてほしいのは、Waterプラグインはまだ Experimental であることです。この記事も最初UE5.2で書こうと思って資料を用意していたんですが、「やっぱり最新のUE5.3にしとくか」と思って確認したら、WaterBodyInfoMeshのデバッグ描画がごっそり変わっていました。

次のUE5.4でも、また大きく変わっているかもしれません。ただ、着実に使いやすくなっていることは確かで、そろそろベータぐらいにはなってくれないかなと思ってます。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2