ひらおかゆみのなげやりブログ

もう、なげやりです…

JavaFXで小惑星を描いてみよう

このエントリはJavaFX Advent Calendar 2016の19日目です。昨日は青江(@aoetk / id:aoe-tk)さんの「Java 9で強化されたデスクトップ環境関連のAPIをJavaFXで使ってみる」でした。明日は@khasunumaです。何をやるのか知りませんが。

そして今日は、私と昨日担当の青江さんの誕生日なのです。Happy Birthday!

私は中学生の頃から小惑星、特に海王星の外側を公転している小惑星(太陽系外縁天体)に興味がありまして、今年のAdvent Calendarでは、JavaFXの3D機能を使ってこれらを描いてみようと思います。

まずはじめに、前提条件を宣言しておきます。

  • JavaFXの3Dレンダリングにはフォンシェーディングという技法を採用していますが、フォンシェーディングでは天体を精緻に描画することができません。天体表面の物性や光の反射(アルベド)などを考慮する場合、これらをパラメータとする物理ベースレンダリングの方が向いています。
  • ただし、小惑星(特に太陽系外縁天体)の圧倒的多数は詳細不明であるため、フォンシェーディングによる近似でも十分だと思われます。どのように近似するかはこのエントリでみてゆきます。

Step 1 - とりあえずJavaFXで球形を描いてみる

まずはじめに、JavaFXで球形を描くところから始めます。小惑星には様々な形のものがありますが、神話に由来した名前を持つ大型のものは球形に近いからです。

3Dグラフィックスというと敷居が高いように思えますが、今回参考にしたサイトはStep by Stepで球形の描き方が説明されていたので、とてもわかりやすかったです。 

JavaFX 3Dを理解する - ソフトウェアエンジニアリング - Torutk

参考にしたサイトでは、最後に地球表面のテクスチャを貼り付けるところまであったのですが、小惑星で正確な表面地形が判明しているのは最近探査機が入ったケレスだけなので、今回はテクスチャは使いません。地球から110億km以上離れたセドナ(90377 Sedna)の表面なんて分かりませんから。

Step 2 - 回転楕円体・三軸不等の扱い

球形に見える天体の多くは、正確には回転楕円体といって、極方向が少しつぶれた形をしています。つまり、極半径より赤道半径の方が少しだけ長いのです(例外は金星で、極半径と赤道半径が等しい)。では、JavaFXでは回転楕円体をどのように実現すればよいのでしょうか?

球形を表すSquareSphereクラスには、半径を表すradiusプロパティと、各軸方向の倍率を示すscaleX/scaleY/scaleZプロパティがあります。このうち、scaleXプロパティを1よりも大きくすると、極半径よりも赤道半径が大きい回転楕円体ができます。radiusプロパティに極半径を、scaleXに赤道半径÷極半径の値を設定すると、ちょうど良い比率の回転楕円体が出来上がります。

小惑星には、さらに厄介な三軸不等と呼ばれるひずんだ形状が少なからずあります(実は地球と月もお互いの引力により厳密には三軸不等なのです)。どういうことかと言うと、回転楕円体は赤道面が真円なのですが、三軸不等の場合は赤道面も楕円になります。つまり、極半径、赤道長半径、赤道短半径の3つがすべて異なります。ケレス(1 Ceres)のようにパッと見では球に見えるものであれば球または回転楕円体として表しても問題ありませんが、後述のハウメア(136108 Haumea)のように極端だと無視するわけには生きません。

三軸不等は直感的ではない形状ですが、JavaFXで回転楕円体が描ければその応用です。回転楕円体ではscaleXプロパティを操作しましたが、三軸不等の場合はscaleXに加えてscaleYプロパティも操作します。具体的にはscaleYプロパティに赤道長半径÷赤道短半径の値を設定すればOKです。 

12/20訂正:SquareではなくSphereが正しいです。櫻庭さん、ありがとうございました。

Step 3 - 色の扱い

小惑星の大きさや形状ははっきりしないものが多いですが、色についてはかなり正確な情報がわかっています。小惑星はかすかな反射光を頼りに観測するのですが、その際に様々な色フィルターを駆使することから、色に関するデータは集まりやすいのです。

天体の色を表すには主にB-V色指数というものを使います。白を0として、マイナスになるほど青みが強く、プラスになるほど赤みが強い、というものです。B-V色指数は特に恒星で多く使われ、例えば太陽が+0.65、オリオン座のベテルギウスが+1.85、同じくリゲルが-0.03です。ここからもオリオン座のベテルギウスが赤く、リゲルが白いことがわかります。この延長で恒星の絶対等級を縦軸、B-V色指数を横軸に取ってプロットした図が、高校の地学の授業で習うHR図ヘルツシュプルング・ラッセル図)になります。

最大の問題は、B-V色指数をJavaFXで使用可能なRGB/sRGBまたはHSBにどうやって変換するかです。直接変換する方法がないのは明らかです。ColorクラスにB-V色指数は渡せませんから。

私の調べた範囲では、大まかな流れとして、以下の手順でB-V色指数からsRGBへと変換することができます。ただし、各手順で制限事項があります。

  1. B-V色指数→色温度
  2. 色温度→色度座標→XYZ表色系
  3. 色度座標→(XYZ表色系)→sRGB

Step 3.1 - B-V色指数から色温度への変換式

詳しくはこちら。

yumix.hatenablog.jp

この記事の考察より、以下を変換式として使用することにします。

log T = 3.939654 - 0.395361 * (B-V) + 0.2082113 * (B-V)2 - 0.0604097 * (B-V)3

(T : 表面温度、(B-V) : B-V色指数)

簡単な三次方程式と指数・対数関数の組み合わせであるため、JavaのMathクラスを使えば簡単に計算することができます(log Tの値からTは簡単に求められますよね?)。 

Step 3.2 - 色温度から色度座標への変換式

D65光源下と仮定すると、色度座標 (x, y) は、色温度 4,000~25,000 [K] の間で以下のように求められます。

x = 0.244063 + 0.09911e3 / T + 2.9678e6 / T2 - 4.6070e9 / T3 (4,000 ≦ T ≦ 7,000)
x = 0.237040 + 0.24748e3 / T + 1.9018e6 / T2 - 2.0064e9 / T3 (7,000 < T  2,5000)
y = -3.000 * (x * x) + 2.870 * x - 0.275

Step 3.3 - 色度座標からsRGBへの変換

まず、色度座標からXYZ表色系を求めます。

x = X / (X + Y + Z), y = Y / (X + Y + Z), z = Z / (X + Y + Z), x + y + z = 1

Y = 1 とすれば、X = x / y, Y = 1, Z = (1 - x - y) / y

XYZ表色系からsRGBへの変換式は以下の通りです。

r = 3.240970 * X - 1.537383 * Y - 0.498611 * Z

g = -0.969244 * X + 1.875968 * Y + 0.041555 * Z

b = 0.055630 * X - 0.203977 * Y + 1.056972 * Z

このままではr、g、bのいずれかが1を超えてしまう場合があります。特に小惑星の多くは全体的に赤みを帯びているため、rが容易に1を超えてしまいます。各色要素とも1を超えるものは1、0を下回るものは0にすることが多いようですが、実際にやってみるとなんとなく不自然な色になったため、r、g、bのいずれかが1を超えた場合にはその値で全要素を割って、最大値が1に収まるようにしました。

Step 4 - アルベドの扱い

小惑星は恒星と異なり、自ら光を発することができません。月と同じ、主に太陽光を反射することでかすかに光っています。小惑星に当たる光の量を1としたとき、反射する光の割合をアルベドといいます(アルベドの考慮が必要なので物理ベースレンダリングを使いたかったのですが)。

太陽系の天体のアルベドの例としては、地球が0.367、明るい星として知られる金星が0.67です。土星の衛星エンケラドゥスは1.375という異常値で、太陽系で最も白い衛星と言われます。小惑星準惑星アルベドは全般的に低いのですが、準惑星エリス(136199 Eris)は0.88と高値です。

仕上げとして、アルベドの表現はどうすればよいでしょうか?アルベド0.09のケレスは暗めに、一方でアルベド0.88のエリスは明るめに表現したいですよね?

考えた末に、点光源PointLightの色をグレースケールとした上で、その明るさとしてアルベドを設定するようにしました。実際にアルベドが関係するのは点光源の反射だけではないのですが、とりあえずということで。

Step 5 - UIの取り付けとFXMLへの変換

小惑星はメートル規模の隕石みたいなものから、直径2,400kmに達する冥王星(134340 Pluto)やエリスのような惑星クラスのものまで無数に存在します。そのすべてを表現するのは現実的ではありません。そこで、主に準惑星として分類されているものを中心に8つの小惑星を取り上げ、リストから選択できるようにしました。

小惑星直径 (km)B-V色指数アルベド
冥王星 Pluto 2370 0.82 0.56
エリス Eris 2326 0.71 0.88
ハウメア Haumea 1960×1518×996 0.626 0.6
マケマケ Makemake 1530.0×1402 0.7 0.77
オルクス Orcus 1502 0.68 0.09
セドナ Sedna 995 1.24 0.33
ケレス Ceres 974×974.6×974 0.713 0.090
クアオアー Quaoar 890 1.58 0.069

リストなどのUIを付けるに当たって、サンプル同様にJavaのコードのみで記述していたものを、FXMLに変換しました。その際、カメラがUIを含むScene全体にかかると画面がうまく表示できなかったため、小惑星を描く部分をSubSceneとし、そこに対してのみカメラが適用されるようにしてみました(SubSceneをFXMLで扱っている例はごくわずかでした)。

Step 6 - できあがり

コードはGitHub https://github.com/yumix/asteroid-viewer に載せてあります。

Step 6.1 - 冥王星

f:id:yumix_h:20161206215143p:plain

冥王星(134340 Pluto)は最大の準惑星であり、かつては太陽系第九惑星に分類されていた天体です。B-V色指数+0.82からは薄く褐色を帯びた色が表現できました。 

Step 6.2 - エリス

f:id:yumix_h:20161206215156p:plain

エリス(136199 Eris)は冥王星とだいたい同じ大きさの準惑星です。仮符号2003 UB313で思い出される方もいらっしゃるでしょうが、冥王星が惑星から準惑星に細分類される直接のきっかけとなった大型の小惑星です。B-V色指数+0.71は冥王星より若干赤みが少ない色を表します。また、アルベド0.88は今回挙げた8つのうちで最も高い値です。これらがちゃんと表現できているでしょうか?

Step 6.3 - ハウメア

f:id:yumix_h:20161206225811p:plain

ハウメア(136108 Haumea)は直径1,500km級としては珍しいラグビーボール形状をしているユニークな天体です(当然ですが三軸不等です)。この極端な扁平は、4時間に満たない非常に早い時点によるものだと考えられています。

Step 6.4 - マケマケ

f:id:yumix_h:20161206221039p:plain

マケマケ(136472 Makemake)は準惑星の一つです。アルベド0.77はエリスに次ぎ、かなり明るい天体であることがうかがえます。準惑星の中では現時点で最近(2005年)に発見されたものです。

Step 6.5 - オルクス

f:id:yumix_h:20161206215247p:plain

オルクス(90482 Orcus)は2004年に発見された太陽系外縁天体ですが、実は1951年にも観測されていたことが判明しています(最初に発見された太陽系外縁天体である1992QB1に遡ること41年前です)。B-V色指数は0.68と低めで、冥王星やエリスと比較して赤みが薄いのが特徴です。Wikipediaの想像図では青い小惑星として描かれていますが、B-V色指数からはこの程度の色が妥当だと思います。 

Step 6.6 - セドナ

f:id:yumix_h:20161206215302p:plain

セドナ(90377 Sedna)は他の多くの太陽系外縁天体よりも遙か外側を公転する天体で、固有名がついた小惑星の中では太陽および地球から最も遠い位置にあります。その公転周期は12,000年(「君の名は。」に登場するティアマト彗星のなんと10倍です!)です。太陽系の奥深くに存在する小惑星ですが、アルベドは0.33と小さくはありません。 

Step 6.7 - ケレス

f:id:yumix_h:20161206215323p:plain

ケレス(1 Ceres)は最初に発見された小惑星で、メインベルト(火星ー木星間の小惑星帯)に存在する唯一の準惑星です。ケレスはメインベルト全体の質量の大半を占めますが、他のメインベルト天体と組成が全く違うことが判明しており、外部からメインベルトへ迷い込んで定着した天体だと考えられています。アルベド0.09と暗い小惑星ですが、小惑星全体で見ると平均的な値です。B-V色指数+0.71からも推測できるように赤みを帯びてはいますが、全体的に暗いため色がはっきりしないところも表現できました。 

Step 6.8 - クアオアー

f:id:yumix_h:20161206215338p:plain

クアオアー(50000 Quaoar)は2002年に発見された太陽系外縁天体ですが、実は1954年に観測されていたことが判明しています(最初に発見された太陽系外縁天体である1992 QB1に遡ること38年前です)。小惑星番号はちょうど50000番です。8つの天体の中で最も小さくて暗い、また赤みが強いのがおわかりいただけるでしょうか。

Step 7 - 今後

小惑星(太陽系外縁天体)に関する詳しいことが判明したら、いずれはJavaFXで描いた小惑星を回転させられるようにしたいです。小惑星で表面の写真が存在するのはケレスだけで、ほとんどは地軸の傾きさえも分からないのですが、ハウメアのように極端な三軸不等の天体を回してみると、地球儀とはまた違った面白さがあると思います。