JavaFX 3Dで赤道座標系の地球表示(1)

#JavaFX 3Dで赤道座標系の地球表示(1)

この記事は、[JavaFX Advent Calendar 2017](https://qiita.com/advent-calendar/2017/javafx)の11日目です。10日目はHASUNUMA Kenjiさんの[JavaFX-Maven-Plugin の現状について](http://www.coppermine.jp/docs/notepad/2017/12/javafx-maven-plugin.html)です。

## はじめに

今年の夏頃から、JavaFXの3D機能を使って、地球と人工衛星の軌道を3次元表示してみようとプログラムを作り始めました。完成していれば本日のAdvent Calendarは地球の周りに多数の軌道が表示される画面を提示するところから始まるのですが、残念ながら完成しておりません。本日は、衛星軌道を表示するために、衛星軌道で主に使われる赤道座標系（地球中心を原点とし、地球の自転軸をZ軸、赤道面をXY平面とする右手系直交座標系）で地球を定義し、表示するまでを紹介します。

## 3次元グラフィックスのHello world

3Dプログラミングで地球を表示する、すなわち、球体（Sphere）にテクスチャマップで世界地図を貼って地球として表示させるというサンプルプログラムは、3Dグラフィックス界のHello worldプログラムとしてよく使われています。JavaFXで作った3D地球表示の例を次に示します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/100353/a2402951-f0cb-6f6b-29dd-b19ea6894149.png)

JavaFXの3D機能で地球を表示するにはどのようにプログラミングすればよいか、については、以前に[JavaFX 3Dを理解する](http://www.torutk.com/projects/swe/wiki/JavaFX_3D%E3%82%92%E7%90%86%E8%A7%A3%E3%81%99%E3%82%8B)という記事を書きました。

このとき、JavaFX 3Dの座標系は、Z軸が画面の奥行方向、X軸が画面の右方向、Y軸が画面の下方向という取り方となっています。JavaFX 3Dの表示は、この座標系にカメラ（パースペクティブカメラ）を置き、そのカメラから見た世界となります。デフォルトのパースペクティブカメラは原点に位置し、カメラの方向はZ軸の正に向いています。この座標系とカメラの位置と方向を次の図に示します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/100353/989d359a-72a9-77bc-cc41-30117ce3341a.png)

## 赤道座標系

人工衛星の軌道は、地球の中心を原点とし、地球の自転軸をZ軸（北極方向を正）とし、X軸は春分点方向、X軸とY軸は赤道面上にある座標系で表現します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/100353/78b23e50-ccc3-4581-b04d-a5a901bf3950.png)

これは、先ほどのHello world的地球表示とは同じ右手系の直交座標系ですが、向きが異なります。

## 赤道座標系で定義したモデルをそのままの向きで表示したい

地球の北極方向が画面の上方向となるようにモデル（地球）を表示する方法を模索しました。

### 座標軸をAffine変換で変えるとテクスチャが・・・

3Dグラフィックスはカメラの位置と向きを制御して表示を自由に変更しますが、3Dに慣れていないとカメラの制御ではなく、モデルと座標軸をアフィン変換でいじって表示しようとしがちです。この夏に、Affine変換で座標軸の向きを変えたときのテクスチャマップの様子（左右が反転したり、上下が反転したりと）を次に書きました。
[JavaFX 3DのテクスチャマッピングとAffine変換](http://d.hatena.ne.jp/torutk/20170716)

JavaFX 3Dでは、Affine変換で座標軸の向きを変えるような指定をすると、テクスチャマップも影響を受けてしまいます。

### カメラの位置と向き

カメラの位置と向きを変えることによって、画面表示においてZ軸を上下方向となるようにしたいと思います。これについては次に書きました。
[JavaFX 3Dの座標系とカメラの向きについて](http://d.hatena.ne.jp/torutk/20170813/p1)

上記ブログを一言でまとめると、カメラの向きを、X軸に沿って90度回転させることで、Z軸が画面の上下方向に表示されるようになります。

## 赤道座標系で地球を表示する

![image.png](https://qiita-image-store.s3.amazonaws.com/0/100353/95fb304e-fd0b-abf8-26ae-d2d458b60482.png)

この画面は、カメラの位置と向きを制御して、Z軸が画面上下方向となるようにして地球を表示するJavaFXプログラムです。

地球の中心を原点として、X軸、Y軸、Z軸をそれぞれ赤、緑、青の円柱と正方向の端点に球を付けて示しています。
また、XY平面、YZ平面、ZX平面をワイヤフレーム表示しています。（ちょっとわかりにくいですが）

右側の制御パネルには、カメラの位置と向きを制御するコントロールを配置しています。

このプログラムは次のリポジトリで現在鋭意開発中です。
https://github.com/torutk/javafx-satorbit

カメラの方向を制御するコード部分を抜粋して次に示します。

```java:SatelliteOrbits3dView.java（抜粋）
    private final Rotate azimuthRotate = new Rotate(0, Rotate.Y_AXIS); // カメラの経度方向（赤道周囲）回転
    private final Rotate elevationRotate = new Rotate(0, Rotate.X_AXIS); // カメラの緯度方向（子午線周囲）回転
    private final Translate distanceTranslate = new Translate(0, 0, CAMERA_DISTANCE); // カメラの距離
 
    // カメラの位置・姿勢を定める座標変換列
    private final Transform[] cameraTransforms = new Transform[] {
        new Rotate(-90, Rotate.X_AXIS), // カメラをZ軸正方向が画面上になるよう回転
        azimuthRotate,
        elevationRotate,
        distanceTranslate
    };

    void rotationCamera() {
        subScene.setCamera(createCamera(cameraTransforms));
    }
    // カメラを作成する。
    private PerspectiveCamera createCamera(Transform... args) {
        PerspectiveCamera camera = new PerspectiveCamera(true);
        camera.setFieldOfView(45.0);
        camera.setFarClip(400);
        camera.getTransforms().addAll(args);
        return camera;
    }
```

ここでは、常に原点を向くカメラを用意しています。カメラの位置・方向は、Transform[]で定義します。カメラの制御をする（位置や方向を変える）都度、カメラを作成してシーンにセットします。

詳しい説明は、次回に行いたいと思います。