プロジェクト

全般

プロフィール

ダウンロード (6.57 KB) 統計
| ブランチ: | タグ: | リビジョン:
0ce05d74 torutk
import javafx.animation.AnimationTimer;
29192059 torutk
import javafx.application.Application;
4900ce66 torutk
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.geometry.Insets;
import javafx.geometry.VPos;
685d257b torutk
import javafx.scene.AmbientLight;
29192059 torutk
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
38b62b0a torutk
import javafx.scene.PointLight;
29192059 torutk
import javafx.scene.Scene;
4900ce66 torutk
import javafx.scene.SubScene;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
5775a464 torutk
import javafx.scene.image.Image;
4900ce66 torutk
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.GridPane;
29192059 torutk
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Sphere;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;

public class Hello3d extends Application {

4900ce66 torutk
private static final double EARTH_RADIUS = 6378.137 / 2; // WGS84長半径[km]
5775a464 torutk
4900ce66 torutk
private final Image earthImage = new Image(getClass().getResourceAsStream("physical-free-world-map-b1.jpg"));
0ce05d74 torutk
private double azimuth;
4900ce66 torutk
private long previousHandledTime;
0ce05d74 torutk
4900ce66 torutk
private final DoubleProperty azimuthRateProperty = new SimpleDoubleProperty(10d);
private final DoubleProperty elevationProperty = new SimpleDoubleProperty(0d);
private final DoubleProperty orbitalAltitudeProperty = new SimpleDoubleProperty(4_000d);
0ce05d74 torutk
private final Rotate cameraRotateX = new Rotate(0d, Rotate.X_AXIS);
private final Rotate cameraRotateY = new Rotate(0d, Rotate.Y_AXIS);
private final Rotate cameraRotateZ = new Rotate(0d, Rotate.Z_AXIS);
4900ce66 torutk
private final Translate cameraTranslate = new Translate(0d, 0d, 0d);
0ce05d74 torutk
29192059 torutk
@Override
public void start(final Stage stage) {
4900ce66 torutk
final SubScene earthScene = createEarthScene();
final GridPane panel = createUIPanel();

// レイアウト
final AnchorPane root = new AnchorPane();
root.setTopAnchor(earthScene, 0d);
root.setLeftAnchor(earthScene, 0d);
root.setTopAnchor(panel, 0d);
root.setRightAnchor(panel, 0d);
root.getChildren().addAll(earthScene, panel);

final Scene scene = new Scene(root, 1100, 600, Color.BLACK);

stage.setScene(scene);
stage.setTitle("Hello JavaFX 3D World");
stage.show();

AnimationTimer timer = new AnimationTimer() {
@Override
public void handle(long now) {
update(now);
}
};
timer.start();
}

/**
* カメラ位置を更新する。
* カメラは Y=0 の平面(X-Z平面)で原点を中心に (地球半径 + 高度)を半径とした
* 円軌道を移動する。
* また、カメラの角度は常に球体を向くように円軌道の移動に合わせて設定する。
*/
private void update(long now) {
if (previousHandledTime == 0) {
previousHandledTime = now;
return;
}
azimuth += azimuthRateProperty.get() * (now - previousHandledTime) / 1_000_000_000;
previousHandledTime = now;
double orbitalRadius = orbitalAltitudeProperty.get() + EARTH_RADIUS;

cameraTranslate.setX(Math.sin(Math.toRadians(azimuth)) * orbitalRadius);
cameraTranslate.setZ(-1 * Math.cos(Math.toRadians(azimuth)) * orbitalRadius);
cameraTranslate.setY(-1 * Math.sin(Math.toRadians(elevationProperty.getValue())) * orbitalRadius);
cameraRotateY.setAngle(-1 * azimuth);
}

/**
* 地球系のモデルを作成
*/
private SubScene createEarthScene() {
final Group earthGroup = new Group();
29192059 torutk
// 球体の定義
4900ce66 torutk
final Sphere earth = new Sphere(EARTH_RADIUS);
earthGroup.getChildren().add(earth);
29192059 torutk
a87c4319 torutk
// 材質の定義
final PhongMaterial material = new PhongMaterial();
5775a464 torutk
material.setDiffuseMap(earthImage);
a87c4319 torutk
earth.setMaterial(material);

29192059 torutk
// カメラの定義
final PerspectiveCamera camera = new PerspectiveCamera(true);
0ce05d74 torutk
camera.setFieldOfView(45d);
4900ce66 torutk
camera.setFarClip(100_000d);
29192059 torutk
camera.getTransforms().addAll(
0ce05d74 torutk
cameraTranslate,
cameraRotateX,
cameraRotateY,
cameraRotateZ
29192059 torutk
);

38b62b0a torutk
// 点光源の定義
final PointLight pointLight = new PointLight(Color.WHITE);
4900ce66 torutk
pointLight.setTranslateX(-2_000d);
0ce05d74 torutk
pointLight.setTranslateY(0d);
4900ce66 torutk
pointLight.setTranslateZ(100_000d);
earthGroup.getChildren().add(pointLight);
38b62b0a torutk
685d257b torutk
// 環境光の定義
final AmbientLight ambientLight = new AmbientLight(Color.rgb(80, 80, 80, 0.5));
4900ce66 torutk
earthGroup.getChildren().add(ambientLight);
685d257b torutk
4900ce66 torutk
// サブシーンの定義
final SubScene earthScene = new SubScene(earthGroup, 800d, 600d);
earthScene.setFill(Color.BLACK);
earthScene.setCamera(camera);
return earthScene;
}
0ce05d74 torutk
4900ce66 torutk
/**
* 制御UIパネルを作成する。
*/
private GridPane createUIPanel() {
final GridPane grid = new GridPane();
grid.setHgap(8d);
grid.setVgap(16d);
grid.setPadding(new Insets(32d, 10d, 10d, 16d));
grid.setPrefSize(300d, 600d);
grid.setStyle("-fx-background-color: midnightblue;");

final Label azimuthRateLabel = createSliderLabel("回転速度[deg/s]");
grid.add(azimuthRateLabel, 0, 0);
grid.setValignment(azimuthRateLabel, VPos.TOP);
grid.add(createSlider(-30d, 30d, 1d, 10d, 2d, azimuthRateProperty), 1, 0);
final Label elevationLabel = createSliderLabel("緯度[deg]");
grid.add(elevationLabel, 0, 1);
grid.setValignment(elevationLabel, VPos.TOP);
grid.add(createSlider(-45d, 45d, 0d, 15d, 3d, elevationProperty), 1, 1);
final Label altitudeLabel = createSliderLabel("高度[km]");
grid.add(altitudeLabel, 0, 2);
grid.setValignment(altitudeLabel, VPos.TOP);
grid.add(createSlider(0d, 30_000d, 200d, 5_000d, 1_000d, orbitalAltitudeProperty), 1, 2);
return grid;
0ce05d74 torutk
}

/**
4900ce66 torutk
* ラベルを作成する。
0ce05d74 torutk
*/
4900ce66 torutk
private Label createSliderLabel(String title) {
final Label label = new Label(title);
label.setStyle("-fx-text-fill: aliceblue;");
return label;
}
0ce05d74 torutk
4900ce66 torutk
/**
* スライダーを生成する。
*/
private Slider createSlider(double min, double max, double initial, double major, double minor, DoubleProperty prop) {
final Slider slider = new Slider(min, max, initial);
slider.setShowTickMarks(true);
slider.setShowTickLabels(true);
slider.setMajorTickUnit(major);
slider.setBlockIncrement(minor);
slider.valueProperty().bindBidirectional(prop);
return slider;
29192059 torutk
}

public static void main(final String... args) {
launch(args);
}
3cf7d266 torutk
}