これは「MIERUNE Advent Calendar 2023」の17日目の記事です。昨日は、@kntoshiya さんによる「NetworkXで地理院ベクトルタイルの道路データを使ってネットワーク解析」でした。
突然ですが、
CesiumJSで、カメラの高さを現在地点の標高+アルファで、地形に追従したカメラ高さにしたいという場面が有りました。
=カメラの高さが、標高+アルファで一定になるようにする
標高取得 初期コード一部抜粋
const cartographicPosition = Ellipsoid.WGS84.cartesianToCartographic(viewer.camera.position)
let level = 11 // 任意のLODレベルを指定
sampleTerrain(viewer.terrainProvider, level, [cartographicPosition]).then(function (
updatedPositions
) {
console.log(updatedPositions[0]);
if(updatedPositions[0].height === undefined) return
const demHeight = updatedPositions[0].height
Cesiumで移動先の高さを地形から取得して見ました。
しかし、cameraMoveイベントで行っていると
偶にいや、よく8割位、高さ(demHight)の取得に失敗しました。
おそらく、マウスで動かすと、移動イベントがかなり、多く発生するため
地形からの高さ取得が間に合わないのだと推測します。
単発でやるとうまく出来るのに、高頻度で地形からの標高取得が出来ない事が頻発します。
→標高+アルファにしているはずなのに、適切なカメラ高さが設定できず、移動していると山にめり込む事が頻発。
対策をいろいろやってみました。
- カメラ移動イベントが前回位置より一定距離移動後、カメラの高さ変更を行う。
→頻度は減るが、まだ多い
(GPSの処理だと、一定距離移動したあとイベント発生させる機能が有ったので効果あるかなと思った) - カメラ移動終了イベントで、カメラ高さを変える
マウスでカメラを動かしている最中はスムーズに動いているのに、止まった直後高さが変わる。
→追従性が悪い
今回やりたかったのは、マイクラの移動のような動きなので、どうしたら良いか悩んだ結果
移動の方法をマウスではなく
-
キーボードで特定キー(WASD)で移動方向を指示して、1キーで5m毎に移動するようにして、地形から標高を取得するイベント数を減らした。
-
移動先の標高値を取得できたら、移動するようにした。
単発での標高取得は元々問題なかったので、キーを押すくらいの頻度で、高度を取得すのも問題なかった。
これでCesium上でマイクラのような移動が出来るようになりました。
ちなみに、カメラの、heading,pitchも本来は、マウスもしくはナビゲーションパネルでやる操作でしたが、こちらも十字キーに割り当てて、キーを押すたびに一定量角度が変わるようにしました。
サンプルの画像は、33.42301280235916、131.07503658735817の位置(場所に意味はないです)
地形は:地理院の5mDEMを、CesiumIonで地形に変換して使用
タイル画像は、地理院の衛星写真を使用しています。
まとめ
Cesiumで地形から標高を取得できるのは、すばらしい機能なのですが、高頻度で地形から高度を取得するのは、耐えられないのだと思いました。
(そりゃそうですね)
Cesiumがシームレス&スムーズに3D地球儀を表現できている&移動できるが故の悩みでした。
もし、もっとスムーズにやりたいのであれば、Cesiumではなくゲームエンジンの分野に任せた方が良い気がします。