javajavafxcameramouseeventmouselistener

3D Camera movement in JavaFX using mouse


I've managed to move the camera using mouse drag. However, the problem is that once I've moved the camera and released the mouse press, the camera returns back to the origin.

I want the camera to remain in the changed position instead so that when I use the mouse again to move the camera, it moves from that position to wherever instead of from the origin.

package application;
    
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Camera;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Sphere;


public class Main extends Application {
    
    private static final int WIDTH = 900;
    private static final int HEIGHT = 600;  

    //Tracks drag starting point for x and y
    private double anchorX, anchorY;
    
    @Override
    public void start(Stage primaryStage) {
        Sphere sphere = new Sphere(50);
        
        Group group = new Group();
        group.getChildren().add(sphere);
     
        Camera camera = new PerspectiveCamera();
        Scene scene = new Scene(group, WIDTH, HEIGHT);
        scene.setFill(Color.SILVER);
        scene.setCamera(camera);
     
        sphere.setTranslateX(WIDTH / 2);
        sphere.setTranslateY(HEIGHT / 2);
        
        initMouseControl(scene, camera, primaryStage, sphere);
     
        primaryStage.setTitle("Solar System Simulator");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    private void initMouseControl(Scene scene, Camera camera, Stage stage, Sphere sphere) {

           scene.setOnMousePressed(event -> {
                //Save start points
                anchorX = event.getSceneX();
                anchorY = event.getSceneY();
           });
         
           scene.setOnMouseDragged(event -> {
                camera.setTranslateY(anchorY - event.getSceneY());
                camera.setTranslateX(anchorX - event.getSceneX());
           });
           
           stage.addEventHandler(ScrollEvent.SCROLL, event -> {
               sphere.setTranslateZ(sphere.getTranslateZ() + event.getDeltaY());
           });
    }
    
    public static void main(String[] args) {
        launch(args);
    }
}

I've tried googling to find a solution but couldn't find much on camera movement with javafx


Solution

  • First of all, your scene does not have depth buffer enabled . These constructors enable 3d features in a scene instance Scene(Parent root,double width,double height,boolean depthBuffer) and Scene(Parent root,double width,double height,boolean depthBuffer,SceneAntialiasing antiAliasing) both with depthBufer boolean set to true. Second ,if you want to translate a node ; translate it getting its current coordinates and then add new coords . that will avoid reset coords . I divided the dragged result by 10 because it brought too high values

        public class Main extends Application {
    
        private static final int WIDTH = 900;
        private static final int HEIGHT = 600;
    
        //Tracks drag starting point for x and y
        private double anchorX, anchorY;
    
        @Override
        public void start(Stage primaryStage) {
            Sphere sphere = new Sphere(50);
    
            Group group = new Group();
            group.getChildren().add(sphere);
    
            Camera camera = new PerspectiveCamera();
            // for 3d  Scene constructor must have zbuffer= true and SceneAntialiasing
            Scene scene = new Scene(group, WIDTH, HEIGHT, true, SceneAntialiasing.BALANCED);
            scene.setFill(Color.SILVER);
            scene.setCamera(camera);
    
            sphere.setTranslateX(WIDTH / 2);
            sphere.setTranslateY(HEIGHT / 2);
    
            initMouseControl(scene, camera, primaryStage, sphere);
    
            primaryStage.setTitle("Solar System Simulator");
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        private void initMouseControl(Scene scene, Camera camera, Stage stage, Sphere sphere) {
    
            scene.setOnMousePressed(event -> {
                //Save start points
                anchorX = event.getSceneX();
                anchorY = event.getSceneY();
            });
            // translating camera from its current coords pluss event 
            scene.setOnMouseDragged(event -> {
                camera.setTranslateY(camera.getTranslateY() + ((anchorY - event.getSceneY()) / 10));
                camera.setTranslateX(camera.getTranslateX() + ((anchorX - event.getSceneX()) / 10));
            });
    
            stage.addEventHandler(ScrollEvent.SCROLL, event -> {
                sphere.setTranslateZ(sphere.getTranslateZ() + event.getDeltaY());
            });
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }