#はじめに
今年もFOSS4G年末隠し芸大会の時期がやってまいりました。
最近はディープラーニング周りしかやっていなかったので、久々にCesiumで趣味的な実験をやってみようかと思いました。
結構前のFOSS4GでCesiumでリアルタイム物理演算デモをやったのですが、やっつけコード&岩手山周辺しか対応していなかったため、全国版に対応して、かつ劇重コードだったのでちょっと軽くしてみようと昔のコードを思い出しつつ、整理して公開してみました。
しかし、昔の自分のコードは動作確認用のやっつけ用でコメントしていなかったので、何書いているか思い出すのに苦労しました・・・。
#諸君。私は噴火が好きだ。
諸君。私は噴火が大好きだ。
と某代行殿のもおっしゃっておりましたが、噴火を見ていると心が震えます。
噴火ができると、ちょっと嫌なことがあっても「まあ噴火できるしな」ってなるし仕事でむかつく人に会っても「そんな口きいていいのか?私は噴火とよろしくやってる身だぞ」ってなれる。戦闘力を求められる現代社会において噴火できることは有効なはず。
噴火させたいと思うことは誰しもがあるはずです。
しかしながら神ならぬ身では噴火などそう簡単には起こせない。
そう考えたことは?
喜べ少年。君の望みはようやく叶う。
そう、Cesiumならね。
#Cesiumで物理演算ってどうすんの?
とはいってもCesiumでは標準では物理演算は用意されていません。
Google summer of codeのアイディアでoimo.jsとか使った物理演算とか実装出来るとクール! とか書いてあったので、現時点では物理演算機能は実装されていない模様。
#oimo.jsってそもそもなんだ?お芋?
元々はOimoPhysicsというactionscript3で実装された物理演算ライブラリをjavascriptに移植した軽量物理演算ライブラリのようです。
とりあえず、物理演算だけを実装するには向いてそうなので採択してみることに。
#ではこれをどうやってCesiumに組み込むか?
まず座標系が異なると変換が必要なので確認してみます。
Cesiumではcartesian(カーテシアンと読みます。デカルト座標系=直交座標系)という地球楕円体の中心を原点とした座標系を採用しているため、oimo.js等、物理演算系は大抵直交座標なので、cartesianで渡してやればいけそうです。
#地面はどうする?
また、oimo.jsの地面が必要となります。
ここはお約束の地理院標高タイルを使ってみることに。
標高タイルは256*256の行列なので、左上の原点を下に緯度経度標高を算出してからカーテシアン座標に変換する必要があります。
oimo.jsでは平面ポリゴンが存在しないため、球体オブジェクトを敷き詰めて地面の代わりとしました。
#ただでさえ重いCesiumが物理演算とか耐えれるんか
oimo.jsとかの物理演算等のCPUバウンド処理はworkerで別スレッドで実行すれば多少は軽くなるのではないかということで、worker使ってみることに。Cesiumでもオブジェクト作成時などにworkerで処理しているぽいです。
ほんとはWebGPUとかつかってみたかったけど、あれはそもそもSafariのベータ版でしか使えないし、どうも見ていると描画の方が重そうです。
シェーダー言語であるGLSLを使えば簡単な演算であれば出来るし、こういう大量の粒子が動く系の表現にはフラグメントシェーダーが有効らしいが、習得に時間がかかりそうなので今回はパスしました。
#oimo.js with worker
oimo.jsはworker版が用意されていたのでそちらで実装してみました。
Step毎にworker版oimoで計算された位置及び回転情報をメインスレッドで受け取り、three.jsのオブジェクトに適用し、カメラ位置をCesiumと同期することで、あたかもCesiumで物理演算しているように表示することが出来ました。
GTX980Mとかであれば2万オブジェクトくらいまでは問題なく表示できているので、最新のGPUだともうちょっといくかもしれません。
#いつでも、どこでも、どんなときでも
Let's 噴火!
ソースコードはこちら。やっつけなんで使用する際は適当にきれいにしてください。