🦁

3D都市モデルから高さの情報を処理していた話 (3D都市モデル Project PLATEAU Advent Calendar 2023)

2023/12/21に公開

本記事は 3D都市モデル Project PLATEAU Advent Calendar 2023 の21日目の記事です。

今年仕事で使う機会があって入門したPlateau初心者です。枠が空いてたので書きました。

背景

あるとき、Google Street Viewと同じ景色を、Plateauのモデルが整備されている地域で再現できないか?ということを検討していました。

やりたいことのイメージ図は、こういう感じです。

ストリートビューの風景 3Dモデルの風景 (目標)

やったことの紹介

BlenderかUEを使うと良いのですが、僕自身はBlenderの世界にPlateauモデルを置いて遊ぶことが多かったです (手元のPCで動くのがBlenderだった…)。

データは公式サイトなどからダウンロードして利用します。僕が説明するよりそちらを読んだ方が正確ですね。

https://www.mlit.go.jp/plateau/

Blender世界を作った

公式サイトからLOD1の箱を取ってきてインポートすると、箱がたくさん置けます。

上のイメージ図では更に東京タワーも置いています。東京タワーの比較的詳細なモデルですが、LOD2のデータから、東京タワー周辺を手作業で残した上で、FBXに一度エクスポートして用意しました (データをある程度かためておくため)。

こうして作った世界がこちらです。

Blender

Plateauのデータから読み込んできたBLDがたくさん読み込まれています。

Blender-bld

けど…

ここまでは良かったのですが、建物が浮いているに気づきませんでした。なんとなく建物が置かれているところが Z=0 かな?と思っていたのですが、そんなことはなかったです。

画像4

ゲーム画面でも浮いてますね。

画像3

ここで「困ったなぁ」となり、高さ情報も取得するようにしました。

数値標高モデルの導入

土地の情報が必要になる気がします。そこで調べてみると、数値標高モデルというものがあり、このデータも使えるようでした。

数値標高モデルの解説です。

https://www.gsi.go.jp/KIDS/KIDS16.html

https://club.informatix.co.jp/?p=1342

最近データも増えてきている様子ですね。

https://www.gsi.go.jp/gazochosa/gazochosa61002.html

PlateauのデータでもこのDEMデータはダウンロードできたので、世界に導入してみました。地面データができたのでそれっぽくなってきましたね。

blender-dem

ここまで来ると、建物が浮いておらず、ある程度の土地情報もあり、この世界をソコソコ使えそうな状態になりました。

高さ情報を取得する

実際に作ったプチ世界の上でデータ処理をやってみた話をします。

最初に、Google Street Viewの画像と、Blenderで作った世界との対応関係について述べました。似たようなデータ処理で、Google Mapなどの位置情報をBlenderの世界と対応付けたいときがあります。

Google Mapの座標値(緯度経度)とBlenderの直交座標の対応付けは、公式サイトにpyprojなどを使った処理が紹介されています。Blenderに内蔵されているPythonにpyprojをインストールすると、自動処理で使うことができます。

https://www.mlit.go.jp/plateau/learning/tpc03-4/

例えばLOD2モデルの東京タワー周辺の道路ネットワークから取得した地点を考えます。

import pyproj
import json

# WGS84 -> plane 9
trans = pyproj.Transformer.from_crs(6697, 6677)

# ここに地点が入っている
fn = "###"
data = json.load(open(fn, "r"))
N = len(data["nodes"])
for i in range(N):
    lat_i, lon_i = data["nodes"][i]
    # FBXを読み込むときに縮尺が0.01にしたので0.01倍する
    new_y_i, new_x_i = trans.transform(lat_i, lon_i)
    new_x_i *= 0.01
    new_y_i *= 0.01

    # 処理

まずはMatplotlibで可視化してみます。

画像

各地点(◯)の高さを取得できるのかやってみます。頂点の(X, Y)座標から、Z軸のマイナス方向に光線を打ち、情報をファイルに書き出します。

# ray to bottom (適当な高さから下へ)
depsgraph = C.evaluated_depsgraph_get()
vec_point = Vector([new_x_i, new_y_i, 0.2])
dir = Vector([0, 0, -0.01])

# 当たれば(x, y, z)を適当なfpへ保存する
ray = C.scene.ray_cast(depsgraph, vec_point, dir)
if ray[0]:
    Z = ray[1][2]
    fp.write(f"{lat_i},{lon_i},{Z}\n")

当たった地点の高さを記録したファイルを再度読み込んで、3次元散布図で可視化します。

画像

だいたいの場所からそれっぽいデータが取れた気がします!

もちろん、そこまで正確ではない気がするので、参考までに使うことにしましょう。精度高いデータが必要なときは、Google MapsのAPIなどを使うと良いでしょうか。

まとめ

来年はもっと3D都市モデルデータを真面目に使えるようになりたいですね。

Discussion