WebGLスクール第3回の宿題テーマは「地球の周りに何かを回す」でした。
SpaceXが上場してお祭りになっていたので今回はStarlinkの可視化です。
人工衛星の描画
人工衛星の軌道情報を公開しているWebサイトがあり、そこからTLEファイルというものをダウンロードしてsatellite.jsというライブラリに入れると三次元極座標での位置と速度情報が手に入ります。
なので基本的にはコーンを四元数で回転させたあとに位置を移動させているだけです。課題だったのは軌跡の情報とパフォーマンスの改善です。
人工衛星の軌道計算回数の削減
毎フレーム衛星の数分の厳密な位置の計算をすると非常に重いので、数フレームに1回だけ厳密な位置と速度を計算しています。
その間のフレームでは前回計算した速度を維持していると仮定して位置を更新します。(経過時間分だけ位置に足し込むだけなのでこの計算は非常に軽い。)
人工衛星の軌跡の更新
軌跡自体はThree.jsのLine2で書いています。軌跡は毎フレーム計算しないと見た目が不自然になりますが、毎フレームGeometryの形状も変わるため、そのまま更新するとメモリ確保が問題になります。
レンダリングのたびにLine2をメモリに確保しているとそれだけで重い処理になるので、一度用意したGeometryの内部の変数を書き換えて余計なメモリ確保などが走らないようにしています。
ここに関してはまだ改善できる余地が全然ありそうで、パッと思いつく限りでも以下のような工夫はまだまだできたと思います。
- カメラに映る可能性がある点だけを事前にフィルターする。
- LineSegmentGeometryを使いDraw Callの回数を抑える。
背景の星々
単純なパーティクルを並べているだけではあるんですが、ICS MEDIA - カールノイズでパーティクルを動かすを参考にカールノイズでわずかに動かしています。
BufferGeometry + PointsMaterialで描画する実装です。
内部的な実装は詳しくないですがBufferGeometryで複数の点の情報を一回のDraw Callで送れるのでCPU -> GPUの転送コストを抑えることができます。
地球の回転
初期状態では等速で回転運動していますが、wheelイベントで回転速度が加速・減速するようになっています。
これは速度を一定に保つように加速度を制御する雑なPID制御を入れています。
制御工学何も詳しくないので各パラメータは何通りか試して良さそうなやつを入れています。
今回の用途ではD項(微分項)は不要かもしれません。
ビネット
四隅を暗くするようなVignettePassを自前で定義しています。
ほとんどAIに書かせましたが中心からの距離がしきい値を超えた領域をsmoothstepで暗くするようなフラグメントシェーダーを用意しています。