swe_primus/learn/java/javafx/Hello3d/Hello3d.java @ 097e9149
| 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 | |||
| 097e9149 | TAKAHASHI,Toru | //private final Image earthImage = new Image(getClass().getResourceAsStream("physical-free-world-map-b1.jpg"));
|
||
private final Image earthImage = new Image(getClass().getResourceAsStream("bluemarble_cyrindricalEqualArea_2048.png"));
|
||||
| 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();
|
||||
}
|
||||
/**
|
||||
* カメラ位置を更新する。
|
||||
| 097e9149 | TAKAHASHI,Toru | * カメラは原点を中心に (地球半径 + 高度)を半径とし、赤道面(y=0)から
|
||
* 指定した仰角の円軌道を移動する。
|
||||
| 4900ce66 | torutk | */
|
||
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;
|
||||
| 097e9149 | TAKAHASHI,Toru | cameraTranslate.setZ(-orbitalRadius);
|
||
cameraRotateX.setAngle(elevationProperty.get());
|
||||
| 4900ce66 | torutk | 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 | cameraRotateX,
|
||
cameraRotateY,
|
||||
| 097e9149 | TAKAHASHI,Toru | cameraRotateZ,
|
||
cameraTranslate
|
||||
| 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);
|
||||
| 097e9149 | TAKAHASHI,Toru | final Label elevationLabel = createSliderLabel("仰角[deg]");
|
||
| 4900ce66 | torutk | grid.add(elevationLabel, 0, 1);
|
||
grid.setValignment(elevationLabel, VPos.TOP);
|
||||
| 097e9149 | TAKAHASHI,Toru | grid.add(createSlider(-90d, 90d, 0d, 30d, 6d, elevationProperty), 1, 1);
|
||
| 4900ce66 | torutk | 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);
|
||||
}
|
||||
| 097e9149 | TAKAHASHI,Toru | }
|