第0079回 / WaterSystemをVR&プロシージャル地形生成環境で使いたい | HK-87@UEのブログ

HK-87@UEのブログ

UE4で理想のVRゲームを作るまでの軌跡

川を作りたい。
水の表現をどうしようか?

以前試した TrueSky の水面は VR に対応していなかった。
および TrueSky はまだ 4.26 に対応されていない。

4.26 の WaterSystem の水面も、どうやら VR に対応していない、
かつ、どうにも思うように動いてくれない。
なぜだ?


※River のパスに高低差を付けているのに、平面のまま、の図

4.26 の WaterSystem はソースも公開されているし、
少し改良すれば使えるようにならないだろうか?

ということで WaterSystem の調査を始める。

----
まず VR の対応について。

・・・

どうやら Instanced Stereo を OFF にすれば描画はされるようだ。
Instanced Stereo への対応も、少しシェーダーをいじれば対応できるんじゃないだろうか?
いつか試してみよう。

ひとまず Instance Stereo は OFF にして先に進む。

----
Water Body River を置いてみる。

・・・

いくらパス形状を変形したり、Actorを動かしたりしても水面の高さが変わらない。
なぜだろうか?

・・・

どうやら原因が分かった。
WaterSystem は LandscapeBlueprintBrush にかなり依存している。

つまり Landscape を動的に生成しているような現状の環境ではまともに動かない。

 

これも少し改良すれば改善できそうな気がするので調べよう。


まず Water Body River のメッシュ形状が、どんな仕組みで作られているか、について。

タイルごとの Bounds.Max.Z に配置された平面のメッシュ形状をベースとして
マテリアル内で World Offset を利用して高低差をつけている。

具体的には /Water/Materials/WaterSurface/Water_Material マテリアルのこの部分
WaterHeightMappingVS で頂点の高さを移動している。


実際、この Enable Water VS Mapping を false にすると形状が変わる。


で、この WaterHeightMappingVS は何を元に高さを決めているか?
 -> WaterVelocityAndHeight というテクスチャパラメータを参照している。

このテクスチャは Water Mesh Actor が所有しているテクスチャで、
テクスチャフォーマットは TSF_RGBA16F
各チャンネルの意味は以下。

RG: Velocity
B: 水面の高さ
A: Landscapeの高さ (最大~最小を0.0~1.0)

なるほど。

----
加えて、以下の情報をパラメータとして使用する。

マテリアルパラメータコレクション /Water/Materials/MPC/MPC_Water の
 ・LandscapeLocator
 ・LandscapeWorldSize
 ・TerrainMaxZ
 ・TerrainMinZ
マテリアルパラメータコレクションは WaterSubsystem からアクセスできる。

----
まず上2つ。
LandscapeLocator と LandscapeWorldSize。

これらの値を設定している場所は・・・

・・・
UWaterMeshComponent::UpdateWaterMPC()
ここだ。

この関数は WaterMesh のパラメータが変更された時等、メッシュのリビルドが必要な時に呼ばれる。
設定される値は、SetLandscapeInfo() で外部から与えられているので、これで設定すればよさそう。

SetLandscapeInfo() が呼ばれるのは AWaterBrushManager::SetMPCParams() から。
ゲーム中には呼ばれない。

よし、結論
・WaterMeshActor->SetLandscapeInfo() を呼んで、LandscapeLocator, LandscapeWorldSize を設定すべし。

----
次。
TerrainMinZ と TerrainMaxZ。

・・・
これらは設定しているところがない。デフォルト値っぽい?
(-10000, 10000)

----
最後、
肝心の WaterVelocityAndHeight のテクスチャは・・・

AWaterBody::SetDynamicParametersOnMID() で WaterMesh->WaterVelocityTexture を設定している。
この関数が呼ばれるのは・・・
BeginPlay() や OnConstruction() 主に生成時かマテリアル割り当て時。

このテクスチャは WaterMesh が持っているものでなくてはいけないのだろうか?
 -> 大丈夫そう。

このテクスチャにアクセスしているのは、ここ以外ではエディタ専用のコードのみ。
ゲーム起動時に別のテクスチャに差し替えて主問題なさそう。

テクスチャの所持者は WaterMesh で構わない。
プロシージャル対応する場合は、起動時にここにテクスチャを生成して、
地形が生成される度に、このテクスチャをシステムが書き換えればよいのではないだろうか。


----
よしこれで必要な情報はあつまった。

対応内容は・・・
(1) システム初期化時に、WaterMesh->WaterVelocityTexture のテクスチャを作成する。
(2) 地形を更新したときにテクスチャを書き換える。
(3) WaterMeshActor->SetLandscapeInfo() で適切な LandscapeLocation と LandscapeWorldSize を設定する。

この3つの対応でいけそう?
実装してみよう。

・・・
出来た!