Home > Back-end >  Displacement of an object around a sphere with JavaFX
Displacement of an object around a sphere with JavaFX

Time:01-28

I have an object, like a box in this example. I want this box to move in a sine to the left on the sphere when the Z-axis is rotated. But after the box has made a curve, i.e. the rotation of the Z-axis is back to 0. The sphere no longer rotates downwards as it did at the start, but upwards to the right.

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.image.Image;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.shape.Sphere;
import javafx.scene.transform.*;
import javafx.stage.Stage;
import org.joml.Matrix4f;
import org.joml.Quaternionf;

import java.util.ArrayList;

public class TestFX extends Application {

    public static final float WIDTH = 1400;
    public static final float HEIGHT = 1000;

    private final ArrayList<String> input = new ArrayList<>();

    private final Sphere sphere = new Sphere(500);

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        Flugzeug flieger = new Flugzeug(30, 30, 50);
        flieger.setMaterial(new PhongMaterial(Color.GREEN));
        flieger.setTranslateZ(330);
        flieger.getTransforms().add(new Rotate(20, Rotate.X_AXIS));

        sphere.translateZProperty().set(710);
        sphere.translateYProperty().set(420);
        PhongMaterial phongMaterial = new PhongMaterial();
        phongMaterial.setDiffuseMap(new Image(getClass().getResourceAsStream("Earth_diffuse_8k.png")));
        sphere.setMaterial(phongMaterial);

        PerspectiveCamera camera = new PerspectiveCamera(true);
        camera.setFarClip(40000);

        Group root = new Group(flieger, sphere);

        Scene scene = new Scene(root, WIDTH, HEIGHT, true);
        scene.setCamera(camera);

        primaryStage.setTitle("FliegenFX");
        primaryStage.setScene(scene);
        primaryStage.show();

        new AnimationTimer() {
            @Override
            public void handle(long now) {
                initGameLogic(flieger);
                dreheErde(flieger, sphere);
            }
        }.start();

        scene.setOnKeyPressed(event -> {
            String code = event.getCode().toString();
            if (!input.contains(code))
                input.add(code);
        });

        scene.setOnKeyReleased(event -> {
            String code = event.getCode().toString();
            input.remove(code);
        });
    }

    // TODO Erddrehung nach Drehung beibehalten

    private void dreheErde(Flugzeug flieger, Sphere erde) {
        double rotationFactor = 0.005;
        double drehung = flieger.getDrehung() * rotationFactor;
        double amplitude = 2;
        double frequency = 0.001;
        float angle = (float) (Math.sin(drehung * frequency) * amplitude);

        Quaternionf quat = new Quaternionf();
        Matrix4f matrix4f = new Matrix4f();
        Affine affine = new Affine();

        quat.rotateY(angle);
        quat.rotateZ(angle);
        quat.rotateX(-0.001f);

        quat.normalize();
        quat.get(matrix4f);
        float[] matrixArray = new float[16];
        matrix4f.get(matrixArray);
        double[] matrix = new double[16];
        for (int i = 0 ; i < matrixArray.length; i  )
        {
            matrix[i] = matrixArray[i];
        }

        affine.append(matrix, MatrixType.MT_3D_4x4, 0);

        erde.getTransforms().add(affine);
    }

    private void initGameLogic(Flugzeug flieger) {
        if (input.contains("LEFT")) {
            flieger.rotateByZ(-0.5);
        }
        if (input.contains("RIGHT")) {
            flieger.rotateByZ(0.5);
        }
    }

    private class Flugzeug extends Box{
        private double drehung = 0;
        private Rotate r;
        private Transform t = new Rotate();

        public Flugzeug(double width, double height, double depth){
            super(width, height, depth);
        }

        public void rotateByZ(double ang){
            drehung  = ang;
            r = new Rotate(ang, Rotate.Z_AXIS);
            t = t.createConcatenation(r);
            getTransforms().clear();
            getTransforms().addAll(t);
        }

        public double getDrehung() {
            return drehung;
        }
    }
}

I have tried many different ways with trigonometry but they have not been successful. This was for example to move the X-axis of the sphere also according to the sine or to subtract the movements of the Y and Z axis of the sphere as cosine.

I think it has to be transformed in a Rotation Matrix, but i‘ve never had matrix calculation.

CodePudding user response:

Rotating a Group inside another Group in 3d scene

rotating

In this approach Box instance doesn't seem to move 'cause it's moving with the camera . Camera and box are moving together because is it's Group parent who is rotating with keyboard event . The Sphere node is in another group and is not affected . Sphere itself is rotating in Y axis

App.java

public class App extends Application {

    @Override
    public void start(Stage stage) {

        Shape3D sphere = new Sphere(10);

        PhongMaterial mat = new PhongMaterial();
        mat.setDiffuseMap(new Image("https://www.h-schmidt.net/map/map.jpg"));
        sphere.setMaterial(mat);

        RotateTransition sphereRotation = new RotateTransition(Duration.seconds(40), sphere);
        sphereRotation.setAxis(Rotate.Y_AXIS);
        sphereRotation.setToAngle(360);
        sphereRotation.setInterpolator(Interpolator.LINEAR);
        sphereRotation.setCycleCount(Animation.INDEFINITE);
        sphereRotation.play();

        Shape3D box = new Box(2, 2, 2);
        box.setMaterial(new PhongMaterial(Color.ORANGE));
        box.setTranslateZ(-11);

        PerspectiveCamera camera = new PerspectiveCamera(true);
        camera.setTranslateZ(-30);

        var planeGroup = new Group(box, camera);

        Group sphereGroup = new Group(sphere);
        Group group3d = new Group(planeGroup, sphereGroup);
        Scene scene = new Scene(group3d, 640, 480, true, SceneAntialiasing.BALANCED);

        scene.setOnKeyPressed((t) -> {

            if (t.getCode() == KeyCode.UP) {

                Rotate r = new Rotate(-2);
                r.setAxis(Rotate.X_AXIS);
                planeGroup.getTransforms().add(r);

            }
            if (t.getCode() == KeyCode.LEFT) {

                Rotate r = new Rotate(2);
                r.setAxis(Rotate.Y_AXIS);
                planeGroup.getTransforms().add(r);

            }
            if (t.getCode() == KeyCode.RIGHT) {

                Rotate r = new Rotate(-2);
                r.setAxis(Rotate.Y_AXIS);
                planeGroup.getTransforms().add(r);

            }
            if (t.getCode() == KeyCode.DOWN) {

                Rotate r = new Rotate(2);
                r.setAxis(Rotate.X_AXIS);
                planeGroup.getTransforms().add(r);

            }

        });

        scene.setCamera(camera);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch();
    }

    }
  • Related