LandscapeLODの選択で意図しないLODが混ざる問題について

いつもお世話になっております。

今回は、LandscapeLOD選択において、カメラが近づいているのに粗いLODが混ざってしまう問題について、お伺いします。

添付のLandscapeLOD.mp4に再現した時の状況を撮りました。

このようにLandscapeに対してカメラを近づけてると、LODレベルが粗くなるような方向に補間が入ります。

本来であれば、カメラを近づけているのでLOD0のままでいて欲しいのですが、LOD1が混ざることで目の前で地形が変わってしまうため、現在開発中のプロジェクトにおいて問題視されています。

問題のLandscapeの設定を確認しつつ再現プロジェクトを作りましたが、Landscapeの設定で、LOD Distribution>LOD 0 Screen Sizeをデフォルトの0.5から1.25に変更すると発生することが分かりました。

(デフォルトの0.5では再現していません)

LODの補間に問題がありそうということで、シェーダでLOD補間の計算をしている箇所の Engine\Shaders\Private\LandscapeVertexFactory.ush(118)

float CalcLOD(uint ComponentIndex, float2 xyLocalToSubsection, float2 Subsection)

の関数を確認しました。

この関数の最終出力のLODCalculatedに対して、CenterLodのみを渡すと問題は起きず、NeighborLodのみを渡すとカメラが近づいているのにLODレベルが粗くなっていたので、隣接セクションのLOD計算に問題がありそうです。

各LandscapeComponentのLOD計算は、

float FLandscapeComponentSceneProxy::ComputeLODForView(const FSceneView& InView) const

で行われているようなのですが、まだ確たる不具合の要因を見つけられずいます。

疑わしいのは、ComputeBoundsScreenRadiusSquared()の計算で、screen-space projected radiusを求めるのにViewOriginとBoundsOriginとの距離で除算している点です。

ViewSpaceのZで除算すべきじゃないかと思うのですが、そのように修正してもまだ問題が起きる場合があるため、推測が間違っているかもしれません。

この問題について、何か既知の不具合情報など無いでしょうか?

Steps to Reproduce

  1. 添付ファイル内のLandscapeSplineMesh.uprojectを開く
  2. tile_X00_Y00のサブレベルをロード
  3. Alt+2を押すなどしてWireframe描画に変更
    1. 結果を確認しやすくするためなので、再現に必須ではありません
  4. ロードした時のカメラの向きで、カメラを正面に移動させる
  5. カメラはLandscapeに近づく方向なのに、LODが粗くなるような描画結果になる

LandscapeのLOD計算は各ランドスケープセクションのバウンズの中心とビューの中心との三次元距離でバウンズ球を除算したものをベースに計算されます。

つまりスクリーンスペースにおける深度だけを見ているわけではないため、ご指摘のようなセクションの中心から離れたエッジ部分を表示した時にスクリーンサイズは小さくなります。今回はLOD 0 Screen Sizeを1.25に増加させているため、スクリーンサイズがかなり大きいうちから積極的にLODが低下します。この計算と設定の組み合わせにより結果として高レベルのLODが表示されていると考えられます。

デフォルトのLOD 0 Screen Size=0.5では、十分近い距離であれば計算結果でLOD0が割り当てられるため問題が起きません。

LOD 0 Screen Size=1.25はかなり極端な設定といってもよいかと思いますので、表示上十分に近いと判定される距離では最小LODが維持されるような設定に調整されることをお勧めいたします。

>この関数の最終出力のLODCalculatedに対して、CenterLodのみを渡すと問題は起きず、NeighborLodのみを渡すとカメラが近づいているのにLODレベルが粗くなっていたので、隣接セクションのLOD計算に問題がありそうです。

レベル内のご指摘された位置はランドスケープの端であり、NeighborLodはクランプされてCenterLOD同じセクションを参照しているはずです。

実際にushファイルのCalcLOD関数内のコードを

float LODCalculated = (1-LB) * CenterLod + LB * CenterLod;と書き換えて表示に変化があるかを確認しましたが少なくともご指摘の座標では表示内容は変化しなかったことをご報告させていただきます。

ご回答ありがとうございます。

>この関数の最終出力のLODCalculatedに対して、CenterLodのみを渡すと問題は起きず、NeighborLodのみを渡すとカメラが近づいているのにLODレベルが粗くなっていたので、隣接セクションのLOD計算に問題がありそうです。

申し訳ありません。この状況は、再現プロジェクトではなく問題の起きたプロジェクトでの結果でした。

回答いただいた内容を元に精査したところ、問題の原因が「Landscapeに近づくこと」ではなく、「隣接コンポーネントから離れること」であることが分かりました。

そのため、再現プロジェクトは似たような症状ですが、状況が異なるため再現プロジェクトとしては不適切でした。

Distributionに極端なパラメータが設定されていることを要因として、カメラの位置によって隣接LandscapeComponentのLOD選択が変わり、それが注視しているエリアに影響を及ぼしていました。

LOD選択の計算の起点はLandscapeComponentの中心のようなので、角のあたりだと高レベルLODが選択されやすい(極端なパラメータのせいもありますが)というのも要因としてはあるようです。

添付動画は、問題の起きたプロジェクトでの状況を収めたものです。このように、カメラの位置が少し変わるだけで隣接LandscapeComponentのLODレベルが急激に変わる状況でした。

その結果、手前の注視しているエリアにもブレンド処理で影響があり、LODレベルが粗くなります。

問題の起きたプロジェクトでは、動画のカメラを基準にすると真後ろぐらいのカメラ方向で報告が上がっていたので、動画とは反対でLandscapeに近づく(=前に進む)とLODレベルが粗くなり、離れるとLODレベルが細かくなる。という結果になっていました。

ちなみに担当者にヒアリングしたところ、今回のようなパラメータを設定しているのは、描画負荷を下げるために遠めのLODの切り替えを早めたかったからだそうです。

パラメータのせいと言っていいと思いますので、この問題はクローズしてください。

今回も迅速な回答、ありがとうございました。