[Astro] #186 今日の空 — 太陽・月・星を計算して、全天 3D と Quest の VR で見る日課アプリ
はじめに
前回は、トップページの 3D の世界に、風・雪・夜を足しました。
[Astro] #185 トップページの世界に風・雪・夜を足す 01 — 髪・霧・雪を 1 つの風でつなぎ、調整パネルで決める
トップページの 3D の世界に、風、雪、時間帯(夜)、スポットライトを足しました。
lain-lab.com今回は、毎日開く「日課アプリ」として、今日の空(Sky Today)を作りました。場所と日付を入れると、その日の太陽と月がいつ出て、どこにあるかが分かります。そして、星空も見られます。ブラウザだけで動き、通信はしません。
最初は、数字を出すだけのものでした。見せたところ、「ほしもなにもない、ただのデータやん」と言われました。そのとおりだったので、星の図を足しました。さらに、「リアルタイムで、VR で見られるのでは?」と言われて、Quest の VR で見られるところまで作りました。そこから、1 年の図、全画面、天の川と、足していきました。この記事は、できたところまでの、実装のまとめです。
作ったもの
- 今日の数字: 日の出・日の入り、薄明(市民・航海・天文)、南中、月の出・月の入り、月齢、輝面、昼の長さ
- 1 日の高度のグラフ: 太陽と月の高度。クリックやドラッグで時刻を選ぶと、その時刻の高度と方位が出ます
- 1 年の日の出・日の入りの図: この場所・この時間帯での、1 年分。クリックで、日付を選べます
- 場所: 緯度・経度・標高を入れます。「現在地」のボタンもあります。入れた値は、このブラウザの中にだけ保存します
- 空の図(平面): 真上を中心にした半球の図に、太陽・月・惑星・星・星座の線と名前を出します
- 全天(3D・VR): 同じ空を、three.js で球に貼って、見回せます。画面いっぱいの全画面と、キーボード操作があります。星の色、天の川、星雲・星団、流れ星、日付アニメ付きです。Quest では、VR と MR でも見られます
- リアルタイム: 開いている間、15 秒ごとに、いまの空に更新します
- F1 のヘルプ: ふだんの画面には、余計なものを置かず、操作の説明は、F1 に入れました
計算は、astronomy-engine(MIT ライセンス)を使いました。自作はしていません。検算できる相手が、いなくなるからです。星のデータは、d3-celestial(BSD-3、元は Hipparcos 星表)から作りました(5,044 個、等級 6 まで)。
GitHub - cosinekitty/astronomy: Astronomy Engine: multi-language calculation of Sun, Moon, and planet positions. Predicts lunar phases, eclipses, transits, oppositions, conjunctions, equinoxes, solstices, rise/set times, and other events. Provides vector and angular coordinate transforms among equatorial, ecliptic, horizontal, and galactic orientations.
Astronomy Engine: multi-language calculation of Sun, Moon, and planet positions. Predicts lunar phases, eclipses, transits, oppositions, conjunctions, equinoxes, solstices, rise/set times, and othe...
github.com
日の出の「定義」
日の出の時刻は、「太陽の上の端が、地平線に触れたとき」です。太陽の中心の高度で言うと、−0.833° です。太陽の見かけの半径(約 0.27°)と、大気による屈折(約 0.57°)を足した値です。
薄明は、太陽の中心の高度で決まります。
- 市民薄明: −6°
- 航海薄明: −12°
- 天文薄明: −18°
ここで、1 つ、つまずきました。
屈折を含めたら、定義とずれました
画面に出す太陽の高度を、屈折を含めた値にしていました。すると、検算で、日の出の瞬間の高度が −0.22°、市民薄明の始まりが −5.39° と出ました。定義は、−0.833° と −6° です。
原因は、屈折の補正が、地平線の下では、一定の値で効くことでした。出入りの時刻は、屈折を含めて探します。ところが、その時刻の高度まで屈折を含めて出すと、定義と合わなくなります。
そこで、画面に出す高度は、屈折を含まない値に変えました。出入りの時刻のほうだけに、屈折を含めます。日の出のときに、高度が約 −0.8° と出るのは、そのためです。これは、検算のテストに足しました。テストをしていなければ、気づきませんでした。
検算の結果
天体の計算は、合っているかどうかが、見た目では分かりません。そこで、別の計算と比べました。
- 太陽の出・入り・南中を、NOAA の近似式と、6 地点 × 6 日付 = 108 件で比較しました。最大の差は 0.62 分でした
- 北緯 69.65°(トロムソ)で、6/21 が白夜、12/21 が極夜と判定されました
- 北極星の高度が、1 日中、緯度の前後 1° 以内でした
- シリウスの最高高度は 37.57°(期待は 37.60°)、南中の方位は 179.9° でした
- 東京の 2026-10-21 は、日の出 05:52、日の入り 16:58、月齢 10.5 でした
astronomy-engine を信頼しているので、月の出入りは、独立には検算していません。
星の投影
星のデータは、J2000(2000 年の春分点)の赤経・赤緯です。見たい日の、見たい場所の空に直すには、2 つの回転が要ります。
- 歳差: J2000 から、その日の座標へ
- 恒星時: その場所・その時刻で、空がどれだけ回っているか
これで、地平線の座標(高度と方位)が出ます。3D 用には、同じ計算を、行列 1 つにまとめました。東・上・南の座標にして、星のすべてを、フレームごとに、行列 1 つで回します。星の位置を、毎フレーム計算し直しているわけではありません。
2D の図と 3D の座標が合っているかは、4 地点 × 2 日付 × 6 星の 48 点で比べて、一致しました(最大差 0.00000°)。
空の図は、中心が真上、上が北、左が東です。地図とは、東西が逆に見えます。空を見上げて持っているからです。
1 年の日の出・日の入りの図
1 年の図は、横が日付、縦が時刻(0〜24 時)で、昼の部分を、帯で塗ります。日ごとに、日の出と日の入りの分を計算して、結ぶだけです。
- 夏時間がある時間帯でも、日ごとのずれを使うので、段差がちゃんと出ます
- 白夜・極夜の日は、帯を切ります。白夜が続くところは、1 つの四角にまとめます
最初は、日ごとに細い四角を並べました。すると、縦のすじが出ました。四角の継ぎ目が見えたのです。多角形 1 つで塗る作りに変えて、消えました。
もう 1 つは、丸めです。日の入りが、「18:60」と出ました。分を四捨五入していたのが原因です。日のカードは、秒を切り捨てて出していたので、図も切り捨てにそろえて、直しました。
全天(3D)を、画面いっぱいで
VR のボタンは、押すとダイブします。ところが、パソコンでは、小さな窓でしか見られませんでした。
せっかく星空が見られるのに、もったいないので、全画面を足しました。
- 「全画面(F)」のボタン、または F キーで、全画面にします。Esc で戻ります
- 左上に時刻、下に操作のヒントを出します
- マウスだけでは疲れるので、キーボードも足しました。矢印で見回し、
+−で拡大・縮小、,.で時刻(Shift で 1 時間)、Nで「いま」に戻ります。入力欄を触っているときは、効かないようにしました
見た目を作り込む
星の色と大きさ
星の色は、最初は 4 段階でした。星のデータには、**色指数(B−V)**が入っています。これを、表面温度に直して、黒体の色にしました。白を少し混ぜて、きつすぎない色にします。
大きさは、等級で、連続的に変えました。約 3 等より明るい星には、光のにじみを付けます。暗い星は、うすくします。描画は、星 5,044 個の点群を、1 つのシェーダーで描くままです。
最初の版は、白を 3 割混ぜていたので、「あまり変わらない」と言われました。1 割に下げましたが、星は小さな点なので、変化は、控えめです。
地平線の空の色
空の背景は、太陽の高度で決めた、青から暗い紺の、1 色でした。これを、天頂から地平線のグラデーションにしました。太陽が地平線の近くにあるとき(日の出・日の入りの前後)は、太陽の方角の地平線を、橙から赤紫に染めます。球の殻を 1 つ置いただけで、軽いです。MR のときは、背景を出しません。
星をクリックして、名前を出す
星をクリックすると、名前(名前のある星だけ)、等級、色、いまの高度と方角が出ます。いちばん近い星を選びますが、明るい星を、少し有利にします。ドラッグで見回しているときに反応しないよう、動きが 5px 未満・0.5 秒未満のときだけ、クリックとして扱います。
クリックできることに、作った自分が、しばらく気づきませんでした。画面下のヒントと F1 に、1 行ずつ足しました。
天の川
天の川を足すと、画面の印象が、ガラッと変わりました。「白い霧みたいなのが追加されるだけで、イメージが変わる。背景は大事」と言われました。
天の川は、銀河座標の小さな画像に、起動時に 1 回だけ焼きます(1024 × 512)。帯の濃さは、銀河面からの距離で決めます。銀河中心(いて座)の方向は、太く明るくして、ノイズで濃淡と暗黒帯を作ります。描画は、空の球に、その画像を、銀河座標へ戻す行列で引くだけです。毎フレームのノイズ計算は、ありません。
実際の天の川とは違う、模式図です。確かめたのは、位置です。8 月の 22 時に南を向くと、さそり座からいて座に中心が来て、わし座・はくちょう座の方向に暗い筋が出ました。10 月は、ペルセウス座・ぎょしゃ座を通ります。
最初の版は、2 つ失敗しました。
- 画像の中心の置き方を、描画の側とずらしました。銀河の反対側(ぎょしゃ座)が、中心の明るさで光りました
- 透明度つきの画像に、低い値を入れたら、色が荒れて、縞が出ました。強さを色に掛けて、透明度は使わない形にしました。明るさも、なだらかに頭打ちする形に直しました
色は、自然な青白にしました。サイトマップの背景にある紫の煙は、宇宙空間の色のサンプルで、天の川には使いません。
星雲・星団・銀河
アンドロメダ銀河、オリオン大星雲、すばる、M13、マゼラン雲など、約 41 個を、ぼんやりした光の玉で置きました。種類で色を変えます(銀河は暖色、散光星雲は桃、惑星状星雲は青緑、散開星団は青白、球状星団は黄白)。大きさは、見かけの大きさです。クリックで、名前、記号、種類、等級、大きさ、高度、方角が出ます。
形は描いていません。位置は、座標どおりです。等級・大きさは、手元の記憶ベースの代表値で、検算していません。目で、位置を確かめました。
流れ星
流れ星は、飾りです。S キーで入・切にして、ふだんは切にしました。夜(太陽高度が −6° より下)だけ、流れます。
流星群の時期(ピークの前後 3.5 日)は、その放射点から、遠ざかる向きに流れます。しぶんぎ座、こと座、ペルセウス座、オリオン座、しし座、ふたご座の 6 つです。時期でないときは、ランダムです。放射点の座標とピーク日は、記憶ベースの代表値で、検算していません。
確かめるのが、難しい機能でした。描画の遅い環境では、流れ星の寿命(0.5〜1 秒)が、スクリーンショットより短いのです。ページの時計を、0.04 倍に遅らせて、やっと 2 本写しました。
実機でも、「出た、動いてる」と、確認できました。
日付アニメ
[ と ] で、日付を 1 日ずつ動かします(Shift で 10 日)。Y キーで、1 年のアニメです。時刻は、そのままで、日付だけが動くので、同じ時刻の空が、季節で動く様子が見えます。下の日の出・日の入りの図の、縦の線も、一緒に動きます。
VR で見る
「VR で見られるのでは?」と言われたとき、私は、実機で確認してから後で、と考えていました。ただ、日課アプリで、見たものが VR で見えない、というのは、確かにもったいないことでした。それで、先に作りました。
- three.js で、星を 1 つの点群にして、空の球に貼ります
- 空の回転は、1 フレームに行列 1 つ
- 太陽・月・惑星は、20 秒ごとに計算し直します
- Quest では、WebXR の
immersive-vr(とimmersive-ar= MR)を使います。ボタンは、対応した端末で開いたときだけ出ます - 開始時は、北を向いた状態です
- スティックの左右で、空を回して、北を合わせます
- スティックの上下で、時間を動かします(最大、1 秒で 2 時間)
- A ボタンで、「いま」に戻ります
実機で、VR は問題なく動きました。スティックで時間を動かすと、夜から昼に変わります(空が青くなり、太陽と月が出ます)。見ていて、いちばん楽しい動きでした。星の色、天の川、星雲、流れ星を足したあとも、VR で問題ありませんでした。
MR は、部屋の景色の中に星空が出ましたが、部屋の壁や天井で、空がさえぎられて、不自然でした。屋外で、ゴーグルをかぶって使うモードのようです。機能は、残しました。
詰まったこと
- 「動く」と言って、動いていませんでした。ページが開かなかったのを、「JS が起動していない」「
httpで開いている」と、2 回、決めつけました。どちらも、証拠がありませんでした。実際は、ブラウザを再起動したら直りました。原因は、特定していません。エラーがERR_...のときは、アプリの JS が動く前の話です。まず、開発サーバーのログに、アクセスの行が出ているかを見るべきでした - UMD 版の読み込みは、サイトによって失敗します。サイト側に
define.amdなどがあると、UMD 版のastronomyが起動しません。ES モジュール版に変えて、起動に失敗したら、理由を画面に出すようにしました - 画面の色が、思ったより明るくなりました。3D の背景色を、リニアの色として渡していて、sRGB として扱われていませんでした。
setRGBに、SRGBColorSpaceを渡して直しました - テストが、空振りしていました。ボタンを文字(「今日」)で探して、ページ見出しの「今日の空」に当たっていました。role で探すように変えました
- Quest の録画を、読み違えました。冒頭の 1 コマだけを見て、「MR の場面がない」と判断しました。実際は、冒頭から MR でした。録画は、時間を追って、何コマも見るべきでした
- 見た目を、聞かずに変えました。画面の縦を縮めようと、カードを 9 枚の 1 行にしたところ、「醜くなった」と言われました。3 段のまま、ブロックを小さくするほうが、正解でした。大きな見た目の変更は、先に聞きます
- シェーダーの
#includeを、同じ行に書いて、コンパイルエラーになりました。改行が要ります。headless のブラウザで、見つけました - 「機能を足さない」と、言いすぎました。頼まれていない機能を足さない、と決めかけたら、「創作の幅が小さくなる」と言われました。足してもいい。ふだんの画面を、すっきりさせておいて、足したものは、F1 のヘルプか、専用のボタンの後ろに置く、という決め方にしました
未確認のこと・制限
- 実際の夜空との見比べは、まだです。星の位置が合っているかどうかは、夜に外で見て、確かめるのが確実です。月と、明るい惑星(いまは木星と土星)の、方角と高度を見比べると、分かりやすいと思います
- 屋外の MRは、試していません。明るい屋外では、パススルーの映像に、星が負けるかもしれません(推測です)
- 星雲・星団の等級と大きさ、流星群の放射点とピーク日は、記憶ベースの代表値です
- 天の川は、模式図です。写真ではありません
- 「現在地」のボタンは、実機で、緯度・経度が入るのを確認しました
- Chrome と Quest のブラウザで確認しました。Safari と Firefox は、確認していません
- 時間帯は、「このPC」「日本時間」「UTC」「現地の太陽時」の 4 択です。国や夏時間の決まりは入れていません
- 日付アニメは、画面の再計算が毎回走るので、遅いパソコンでは、速度が落ちます
- VR の中では、日付を動かせません(スティックは、時間のみ)
おわりに
次は、2 つ考えています。
-
トップページの昼夜に、日の出・日の入りと月齢を流す。いまは、PC の時刻だけで決めています
-
VR のモードに、プラネタリウムを組み込む。メニューからボタンで呼び出して、表示します。今日の空と、描画の部分を分けて、トップページの 3D の世界の中で動かす形になりそうです