Open maopotcha opened 4 months ago
以前同様の取り込みをした際には、元データはLAS形式であり、下記のツールに解像度を調整するパッチを当てたものを使ってheightmapに変換し、それをTerrainに反映していた。 https://github.com/jhawthorn/las2heightmap
レーザー計測(LAS形式)ではない、写真計測(SfM)に関しても最近はツールが充実している。 以下のチュートリアルの後半にSfMで地形モデルを作成し、heightfield(heightmap)を生成するまでの手順が解説されている。 http://topography.csis.u-tokyo.ac.jp/resources/171029_gisa_sfm/SfM-MVS_photogrammetry_basic_v2.pdf
@yosuke ありがとうございます。 取り急ぎ、以前に作成いただいたDX実験フィールドの航空写真測量データをTerrainに設定してみていただけますでしょうか。 建機の動作などに問題なければ、一旦はデフォルトTerrainをこちらにしてしまおうかと考えております。
@maopotcha
了解です。
DXフィールドのTerrainはかなり大きく、前回設定した時にはTerrainを格子状に分割して、重機の周りだけ有効化することであまり遅くならないようにするなどしていたのですが、もしかしたら最近有効化した Broadphase Type
の設定で、格子への分割と同じ効果があるかもしれないので、まずはシンプルな形でやってみます。
とりあえずheightmapをインポートしてみた(textureについてはまだ)。 最高解像度の設定でインポートするとやはりかなり遅くなる(fps 1前後)ようなので、要調整。
textureこみのインポートについても無事に成功。textureが付くとかなりリアルになる。 残るはパフォーマンスの問題。
安息角のcompute shader計算を無効化したところ、fpsが大きく改善した。毎フレームに実行しないなど工夫をすると良いかもしれない。
compute shader計算が有効な場合も、heightmap resolutionを下げるとfpsが大きく改善する。 1025 x 1025まで下げると120 fps程度の実用的な値になった。
heightmap resolutionが最高解像度の4097 x 4097だと遅い理由は、開発に使っているRTX3060ビデオカードのCUDAコア数が3,584基で4097より少ないためと思われる。
解像度が高い状態でもcomputer shaderの並列度設定を調整するとfpsは100を超える。並列度の調整後もきちんと計算できているかを確認後に再度採用を検討。 解像度が高いとheightmapをterrainに反映させるsync処理がかなり遅くなるので、最初の一回のみ適用する(以降は建機の周囲のみsyncする)処理に変更するのが良いと思われる。
syncの頻度を調整すると実用的な速度になるが、地面を掘る局面では頻繁なsyncが必須になる。terrain全体ではなくバケットの周辺だけのsyncをするように実装しているはずなのだが、動作がかなり遅い。 syncの挙動については詳細を調査したほうが良いとかねてから思っていたので、この機会に調査を実施。 ソースコードは下のURLから閲覧できる。 https://github.com/Unity-Technologies/UnityCsReference/blob/master/Modules/Terrain/Public/TerrainData.GPUCopy.cs
sync関係のAPIの呼び出しにcallbackを登録できる仕組みになっており、変なcallbackが登録されていると遅くなる可能性があるが、比較的新しい機能のようなので使っている依存プラグインは少なさそう。 https://github.com/Unity-Technologies/UnityCsReference/blob/b44c4cc9e4ce3dfa0bab2fe4bf7efae880c5a175/Modules/Terrain/Public/TerrainData.GPUCopy.cs#L152
syncの実体部分はネイティブコードで実装されており中を見ることができない。 unity純正のterrainの利用を諦めて自分で実装する人も多いらしい(AGXUnityも自分で実装したterrainクラスを使っている)が、もう少し調査を継続。
プロファイラを見たところ、Terrain.RecomputeInvalidPatches
という関数が非常に大きく時間を食っており、遅くなる原因となっている。
小さな部分だが、Phisics.UpdateVehicles
が時間を食っているのも気になった。この部分については、DiffDriveController上で、substepを100から30に減らしたところ改善。シミュレーション精度の大きな低下もなさそうなのでこの設定を採用予定。
Terrain.RecomputeInvalidPatches
は、heightmapの解像度がある程度大きくなると急に大きく遅くなるとのこと。
https://forum.unity.com/threads/syncheightmaps-and-applydelayedheightmapmodification-performance.658675/#post-4422712
CPUからGPUに転送する際のバス幅の問題であろうとのこと。
terrainを小さなグリッドに切り分けるのが有効な対策。
terrainのグリッド分割、以前はサードパーティーツールを使ったのだが、今は公式のツールがあるとのこと。 https://qiita.com/Cova8bitdot/items/4f465672886728a9f6ad
公式ツールによるグリッド分割、heightmapは綺麗に分割してくれるが、テクスチャは分割してくれないので別途対処の必要あり。
Unity公式のterrain toolはグリッド分割されたterrainに対するペイントや変形操作もできる、という情報も見つけたのだが、実装を見てみるとペイントや変形は一部機能しか対応していないようで、無い部分は自分で作る必要がある。
テクスチャは、terrainタイル毎にオフセットを設定するとグリッド分割されていても適切に表示できる。タイル数が多いと手動で設定するのが大変なので、簡易な設定ツールを作るのが良いと思う。
一番大きな問題は、掘削時に地面の変形が起こった際のheightmapの管理。heightmapのterrainへのsyncが遅いだけで、heightmap自体はワールド全体で1枚でも問題ないため、安息角を使った地面の崩壊の計算などを単純化するために、マスタのheightmapを1枚にして持っておくのが良いと思う。 heightmapをテクスチャ・アセットとして保存しておき、terrainタイルと別途ロードするのが良いか。 https://qiita.com/k7a/items/df6dd8ea66cbc5a1e21d#resourcesload
今後、DXフィールド以外のワールドも使いたい、というリクエストもありそうで、ユーザ側でタイル分割などのオペレーションをするのは大変なので、terrainのデータは通常のterrainとして1枚で持っておいて、シミュレーション開始時に動的に分割する方が良いかもしれない。
ユーザ側には通常のterrainとして見せておき、各種編集を可能にしつつ、タイル分割については内部処理として隠蔽化してしまう。
heightmapのマップタイルへの分割は以下の部分で実装されており、かなり単純な処理。 https://github.com/needle-mirror/com.unity.terrain-tools/blob/71917f5adb362efcc699668415a0516f732cef71/Editor/TerrainToolbox/TerrainToolboxCreateTerrain.cs#L997-L1006
heightmapをフル解像度で作成するとassetファイルが100MBを超えるためLFSを使わないとgithubにpushできない。 ユーザ側でのLFSの導入には若干の手数がかかり、敷居の高さにもつながるので、データサイズを小さくできないか試行中(サイズが100MBを少しだけ超えている状況)。
control textureの解像度を小さくしたところassetのサイズが小さくなってくれた。control textureはマテリアルの挙動の解像度に関わるが、今回はマテリアルについては複雑なことをしていないので、問題ないはず。
terrainの自動分割処理のスクリプト実装完了。かなり早くなって良いのだが、分割後のマップタイル間に筋ができてしまう問題があり修正中。
概要
建設DXフィールドの地形データをTerrainに反映できるようにする
目的
建設DXフィールドにおける動作の事前トライアルができるようにする
やること