Slide 1

Slide 1 text

CesiumのShaderを用いた 気象データ 3Dアニメーションについて 株式会社ノーザンシステムサービス 研究開発部 小林知愛 FOSS4G 2024 Japan

Slide 2

Slide 2 text

FOSS4G Advent Calendar • 今年もアドベントカレンダーの時期が近づいてきました! • 去年は弊社も参加させていただきました 2 [1] FOSS4G Advent Calendar 2023 https://qiita.com/advent-calendar/2023/foss4g FOSS4G Advent Calendar 2023

Slide 3

Slide 3 text

FOSS4G Advent Calender 2023 19日目 GraphCastの気象予測データをCesiumで可視 化してみた1 • AIが予測した気象データをCesiumで 可視化してみた記事 • 今回の発表はこちらの記事のアペンド 的内容 • 最初に記事の内容を簡単に紹介 [1] https://qiita.com/wayama_ryousuke/items/f1823be92153e9b2928b 3

Slide 4

Slide 4 text

背景 • 近年、異常気象による災害の被害が増加 早期に異常気象を発見するために 長期間を正確に気象予測する技術が重要 [1]気候変動監視レポート 2023 | 気象庁 https://www.data.jma.go.jp/cpdinfo/monitor/2023/pdf/ccmr2023_all.pdf [2] 2023 年(令和 5 年)の世界の主な異常気象・気象災害(速報) | 気象庁 https://www.jma.go.jp/jma/press/2312/22d/2023matome_besshi2-2.pdf 日本での気温の上昇、降水量の増加1 世界的に異常気象が発生2 4

Slide 5

Slide 5 text

背景 • Google DeepMind 気象予測AI モデル「GraphCast」1を公開 • 従来のシステムよりも高精度かつ高速に最大 10 日間先の気象を予測 • 予測が難しいとされる異常気象の予測にも強い [1] GraphCast: AI model for faster and more accurate global weather forecasting https://deepmind.google/discover/blog/graphcast-ai-model-for-faster-and-more-accurate- global-weather-forecasting/ 5

Slide 6

Slide 6 text

背景 • 予測された気象データを分かりやすく伝えるにはどのように可 視化するのがよいのだろうか? GraphCastの発表を見て…… GraphCastで予測された気象データの 可視化を3D 地球儀ライブラリCesium1で試してみた 6 [1] Cesium https://cesium.com/

Slide 7

Slide 7 text

GraphCast による気象予測 • ヨーロッパ中期予報センター(ECMWF)から公開されている GraphCast での推論ツール1で気象予測 2023/12/7 の気象データを入力して GraphCast で 予測された 2023/12/9 の気圧のデータ 2023/12/9 に実際に観測された気圧データ 7 [1] ecmwf-lab/ai-models https://github.com/ecmwf-lab/ai-models

Slide 8

Slide 8 text

気象データの可視化 • 風のように動きがあるものや時系列での変化を表現する場合に はアニメーションによる可視化が効果的 GraphCast で予測した気象データについて アニメーションで可視化 8

Slide 9

Slide 9 text

多次元風速アニメーション • WebGL により風速をパーティクルアニメーションとして描画す ることで可視化する手法がある1 GraphCast で予測された風速データを表示してみた例 9 [1] GPU Powered Wind Visualization With Cesium https://cesium.com/blog/2019/04/29/gpu-powered-wind/

Slide 10

Slide 10 text

多次元風速アニメーション • WebGL により風速をパーティクルアニメーションとして描画す ることで可視化する手法 • 多次元データの読み込みと表示にも対応 • 次元による風の動きの違いが見やすくなることが期待できる 次元ごとに高さを変えて立体的に表示できないか? 10

Slide 11

Slide 11 text

多次元風速アニメーション • 結果としてはうまくいかなかった • 地形との衝突判定のためにすべてのパーティクルに対して一律で高さ を設定している→次元ごとに高さを変えるように改修 • 高さから地形に隠れるかどうかの判定は行うものの、パーティクル間 の重なりについては計算されていないため立体的に見えない 高さの設定変更前 次元ごとに高さを変更(白<赤<黄の順で高い) 11 風速アニメーションの立体化は 今回は諦めた……

Slide 12

Slide 12 text

CS 立体図を用いた気圧可視化アニメーション • 気圧の可視化 • 一般的に等高線で表されることが多い • 等高線だと専門知識がないとぱっと見ではわ かりにくい • 「気圧の谷」っていうけど実際谷になってるの? • 地形判読に使用されるCS立体図で気圧を 可視化してアニメーション • 気圧の高低差が分かりやすく表現できるので は? 等高線の例1 12 [1] 日本周辺域 実況天気図の説明 | 気象庁 https://www.jma.go.jp/jma/kishou/know/kurashi/sokuhou_kaisetu.html

Slide 13

Slide 13 text

CS 立体図を用いた気圧可視化アニメーション • 「FOSS4G japan 2020 online1」で発表したGeotiff 画像を地図タイ ル化し、Cesium 上にWebGL で CS 立体図を描画させる手法2 • 実装に当たりtmizu23様3、frogcat様4の記事を参考 [1] FOSS4G japan 2020 online https://www.osgeo.jp/events/foss4g-2020/foss4g-2020-japan-online [2] Geotiff.js で始めるリアルタイム演算 in foss4g japan 2020 online (https://www.slideshare.net/makinux7/geotiffjs-in-foss4g-japan-2020-online) [3] GeoTIFFからUTFGridを作る方法 -自然環境保全のための周辺技術https://tmizu23.hatenablog.com/entry/20121107 [4] 標高PNGタイルと WebGL による地形表現 - Qiita https://qiita.com/frogcat/items/7e91d3070a7a8d3e2c94 GraphCastが推論した気圧のCS立体図 CS立体図+カラーマップ 13

Slide 14

Slide 14 text

CS 立体図を用いた気圧可視化アニメーション • さらに気圧を時系列でアニメーションさせてみる • レイヤーを重ねて表示し上から順番に非表示にしていく 14 アニメーションで気圧の変化をわかりやすく可視化できた

Slide 15

Slide 15 text

おまけ:気圧を 3D で可視化してみる • 地形タイルにして3Dで立体的に可視化してみた • Cesium terrain builder1を使用してGeotiff 画像から地形タイルを作成 • 起伏が小さいので高さ方向のスケールを 100 倍程度に拡大 2023 年 8 月の台風 7 号の気圧を地形タイル化 ここまでが去年の記事の内容 15 [1] geo-data/cesium-terrain-builder https://github.com/geo-data/cesium-terrain-builder

Slide 16

Slide 16 text

今回やったこと • おまけで気圧を地形タイルにして3Dで可視化 • 3Dでアニメーションはさせていなかった 気圧データを3Dアニメーションできないか? 16

Slide 17

Slide 17 text

3Dアニメーションの実装を模索 • Cesium公式のデモ1 • 点群の3Dモデルをカスタムシェーダーでアニメーション • 高速に滑らかに3Dモデルをアニメーションさせている 17 [1] Custom Shaders Models Cesium Sandcastle https://sandcastle.cesium.com/?src=Custom%20Shaders%20Models.html

Slide 18

Slide 18 text

3D点群アニメーション • 点群の3Dモデルの各点を時系列の気圧データに従って高さを変 化させてアニメーション • Cesiumのデモと同じようにカスタムシェーダーで実現 • インタラクティブに任意の日時を指定できるようにする • Cesiumの時系列スライダーで操作 18 時系列気圧データを点群でアニメーションさせる

Slide 19

Slide 19 text

3D点群アニメーション 実装項目 • 点群3Dモデル作成 • Cesium上に表示する点群の3Dモデルの作成 • カスタムシェーダー • カスタムシェーダーによって点群3Dモデルをアニメーション • 時系列データ読み込み • アニメーションに反映させる時系列気圧データの読み込み • 時系列スライダーで任意の日時のデータを読み込むようにする 19

Slide 20

Slide 20 text

3D点群アニメーション 点群3Dモデル作成 • 気圧のGeotiffデータを点群3Dモデルに反映させてアニメーション • 点群の頂点がGeotiffのピクセルと1対1で対応 • 対応するGeotiffのピクセルの値を点群の頂点の高さ等に反映させる 点群の各頂点からGeotiffの対応するピクセルを 参照できるようにする 20 点群モデル Geotiff 対応するGeotiffのピクセルの 値を点群に反映 対応するピクセルを参照

Slide 21

Slide 21 text

3D点群アニメーション 点群3Dモデル作成 • 点群3DモデルにGeotiffの対応するピクセルの情報を持たせる 必要がある • Cesiumに表示可能な3Dモデル形式「glTF」は任意の属性情報 を持たせることが可能 Geotiffの属性情報を持つ点群glTFモデルを作成 21

Slide 22

Slide 22 text

3D点群アニメーション 点群3Dモデル作成 • PythonでGeotiffから点群glTFモデルを生成 • PythonライブラリのGDALでGeotiffを読み込み • モデルの頂点用にGeotiffの座標値を3次元空間の座標値に変換 (WGS84座標→ECEF座標) • pymap3d1:3次元地理座標変換ライブラリ import pymap3d as pm def xyz_to_ecef(lon, lat, alt): # WGS84座標をECEF座標に変換 x, y, z = pm.geodetic2ecef(lat, lon, alt) return x, y, z 22 [1] geospace-code/pymap3d https://github.com/geospace-code/pymap3d

Slide 23

Slide 23 text

3D点群アニメーション 点群3Dモデル作成 • PythonでGeotiffから点群glTF モデルを生成 • glTFモデルを生成 • pygltflib1:PythonでglTFの読み書 きを行うライブラリ • 対応するピクセルのインデックス とWGS84の座標値を属性情報とし て持たせる gltf = pygltflib.GLTF2( ... accessors=[ pygltflib.Accessor( bufferView=0, componentType=pygltflib.FLOAT, count=len(points), type=pygltflib.VEC3, max=points.max(axis=0).tolist(), min=points.min(axis=0).tolist(), ), pygltflib.Accessor( bufferView=1, componentType=pygltflib.FLOAT, count=len(lonlat_list), type=pygltflib.VEC2, max=lonlat_list.max(axis=0).tolist(), min=lonlat_list.min(axis=0).tolist(), ), pygltflib.Accessor( bufferView=2, componentType=pygltflib.UNSIGNED_INT, count=len(idx_list), type=pygltflib.VEC2, max=idx_list.max(axis=0).tolist(), min=idx_list.min(axis=0).tolist(), ), ], ... 3Dモデルの 頂点の座標値 (ECEF座標) WGS84の座標値 ピクセルの インデックス 23 [1] pygltflib https://gitlab.com/dodgyville/pygltflib

Slide 24

Slide 24 text

3D点群アニメーション 点群3Dモデル作成 • PythonでGeotiffから点群glTFモデルを生成 • 全球を覆うような点群3Dモデルが作成できた • 属性情報として生成元のGeotiffの対応するピクセルのインデックスを 保持している 24

Slide 25

Slide 25 text

3D点群アニメーション カスタムシェーダー • カスタムシェーダーで気圧の値が点の高度に反映されるように 実装 • vertexShaderで点群の頂点の位置を操作 void vertexMain(VertexInput vsInput, inout czm_modelVertexOutput vsOutput) { vec2 lonlat = vsInput.attributes.longlat; vec2 geotiff_idx = vsInput.attributes.idx; vec2 uv_pos = vec2(float(geotiff_idx.x) / 1439.0, float(geotiff_idx.y) / 719.0); float zval = get_tex_value(uv_pos); float newz = 1000.0 + ((zval - zmin) * heightBuf); vec3 newXyz = geodeticToECEF(lonlat.x, lonlat.y, newz); vsOutput.positionMC.x = newXyz.x; vsOutput.positionMC.y = newXyz.y; vsOutput.positionMC.z = newXyz.z; vsOutput.pointSize = 3.0; } モデルの属性情報から座標値と Geotiffのインデックスを取得 Geotiffデータからインデックスが参照する気圧の値を取得 気圧の値から高さを計算し、 頂点の新しい座標値を生成 頂点に新しい座標値を設定 25

Slide 26

Slide 26 text

3D点群アニメーション カスタムシェーダー • CS立体図やカラーマップ等が点群の色に反映されるように実装 • CS立体図や等高線等の計算にはfrogcat様1の記事を参考 • fragmentShader vec3 get_cs_map(vec2 uv_pos) { mat3 h; h[0][0] = get_tex_value(uv_pos + (vec2(-1,-1) * unit)); ... return cs_map * dem_color * contour; } void fragmentMain(FragmentInput fsInput, inout czm_modelMaterial material) { vec2 geotiff_idx = fsInput.attributes.idx; vec2 uv_pos = vec2(float(geotiff_idx.x) / 1439.0, float(geotiff_idx.y) / 719.0); material.diffuse = get_cs_map(uv_pos); } モデルの属性情報からGeotiffのインデックスを取得 Geotiffデータから気圧値を取得、CS立体図等を計算して点群の色に反映 [1] 標高PNGタイルと WebGL による地形表現 - Qiita https://qiita.com/frogcat/items/7e91d3070a7a8d3e2c94 26

Slide 27

Slide 27 text

3D点群アニメーション 時系列データ読み込み • Geotiffから気圧データを時系列で読み込む • Geotiffの形式 • 画像サイズ:1440x721(1ピクセル0.25度の全球データ) • バンド数:40(10日間6時間ごとの時点) • 浮動小数点型の気圧データを格納 • Geotiff.js1を使用してブラウザ上から直接Geotiffを読み込む • GraphCastの気象予測データを格納したGeotiffは40バンドの時系列 データを持つ • 40バンドのGeotiffをいっぺんに読み込むとメモリエラーになる 27 [1] geotiff.js https://geotiffjs.github.io/

Slide 28

Slide 28 text

3D点群アニメーション 時系列データ読み込み • 1バンドのGeotiffを40枚読み込むとメモリエラーにはならない • 40バンドのGeotiffを1バンドのGeotiff x 40枚に分離して1枚ずつ順番 に読み込み • 最初に全部の時系列の気圧データを読み込む形式で実装 • 時系列スライダーが動いた場合、読み込まれた時系列気圧データから 現在の日時のデータを参照 28

Slide 29

Slide 29 text

3D点群アニメーション • 時系列気圧データの点群アニメーションができた! デモをご覧ください 29

Slide 30

Slide 30 text

3D点群アニメーション • 時系列気圧データの点群アニメーションができた! 30

Slide 31

Slide 31 text

3D点群アニメーション • 問題点:点群なので近くによってみるとスカスカで見辛い • 点群モデルの各頂点を動かしていたが、メッシュモデルに適用 することは可能か? 31 アップだと色や起伏がわかりにくい

Slide 32

Slide 32 text

メッシュアニメーション メッシュ3Dモデル作成 • Geotiffからメッシュモデルを作成 • 点群モデルを作成するPythonスクリプトを改修 • Pythonライブラリopen3d1で点群をメッシュ化してglTFモデルを作成 # メッシュ作成 # 点の法線推定 ptCloud = o3d.geometry.PointCloud() ptCloud.points = o3d.utility.Vector3dVector(points_ecef_mesh) ptCloud.estimate_normals() ptCloud.orient_normals_consistent_tangent_plane(100) # メッシュ再構成 distances = ptCloud.compute_nearest_neighbor_distance() avg_dist = np.mean(distances) radius = 2*avg_dist radii = [radius, radius * 2] recMeshBPA = o3d.geometry.TriangleMesh.create_from_point_cloud_ball_pivoting( ptCloud, o3d.utility.DoubleVector(radii)) triangles = np.array(recMeshBPA.triangles, dtype=np.uint32) 三角ポリゴンの情報をglTFの設定に追加する 32 [1] Open3D https://www.open3d.org/

Slide 33

Slide 33 text

メッシュアニメーション メッシュ3Dモデル作成 • Geotiffからメッシュモデルを作成 • 全球を覆うようなメッシュ3Dモデルが作成できた 33 メッシュの生成がうまくいってない ところもあるが概ね良さそう

Slide 34

Slide 34 text

メッシュモデルアニメーション • 点群モデルをメッシュモデルに差し替えてアニメーション • カスタムシェーダーは変更なし デモをご覧ください 34

Slide 35

Slide 35 text

メッシュモデルアニメーション • 点群モデルをメッシュモデルに差し替えてアニメーション 35

Slide 36

Slide 36 text

メッシュモデルアニメーション • 気圧データの3Dメッシュアニメーションによる可視化ができた • 気圧の起伏の変化が分かりやすい • 点群では近くによるとスカスカだったが、メッシュでは改善され見やすくなった • 画像レイヤーでのアニメーションよりも挙動が重くない • リアルタイムでのパラメータの反映も可能 36

Slide 37

Slide 37 text

まとめ • 気圧を時系列3Dアニメーションさせてみた • 専門知識がない人でも気圧の起伏と変化をわかりやすく表現 • 気象以外でもグリッド形式のデータであれば同様にアニメー ション可視化が期待できる 気象に限らず専門家以外にもわかりやすく可視化できる 37

Slide 38

Slide 38 text

まとめ • 今までは全球クラスの時系列データは2Dで表示することが多く、 3D表示だと動作が重くなってしまう印象 • GPUが無い環境(スマホなど)でもアニメーション可視化でき る 38 Cesiumのカスタムシェーダーを使うことで 従来よりも軽い動作で3D可視化できる

Slide 39

Slide 39 text

まとめ • 今回作成した時系列データの3Dアニメーションのソースコード はGithubで公開中! • https://github.com/makinux/GridVizA 39

Slide 40

Slide 40 text

最後に • 各種OSSのGISツールを使うことで、今回の気象データの可視 化も比較的簡単に実装することができました 40 OSSツールの開発者の皆様ありがとうございました!

Slide 41

Slide 41 text

41 ご清聴ありがとうございました!