0

I want to be able to rotate a perspective camera using the WASD keys. Pressing the W and S keys should rotate the camera along the X axis, and pressing the A and D keys should rotate it along the Y. In an attempt to do this I created a class called RotateCamera that extends the PerspectiveCamera class and includes methods I made to rotate the camera. This way mostly works, but I find if I first move the camera forward using the up arrow key, and then spam the W key so that the camera rotates 360 degrees, when the sphere comes back in view it is very far away, and moving the camera using the arrow keys seems to move it in random directions. I was wondering why this is/how to fix it? A copy of my classes is below.

package ui;

import javafx.scene.PerspectiveCamera;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Transform;

/**
 * A PerspectiveCamera that includes methods which allow it to be rotated
 */
public class RotateCamera extends PerspectiveCamera {
    Transform currTransform;

    /**
     * Constructor
     * Creates a new camera with default Rotate transform
     */
    public RotateCamera() {
        currTransform = new Rotate();
    }

    /**
     * Rotates the camera along the x-axis according to the given angle
     * @param angle the amount of degrees the camera is rotated
     */
    public void rotateInX(int angle) {
       Rotate newRotation = new Rotate(angle, Rotate.X_AXIS);
       rotateCam(newRotation);
    }

    /**
     * Rotates the camera along the y-axis according to the given angle
     * @param angle the amount of degrees the camera is rotated
     */
    public void rotateInY(int angle) {
        Rotate newRotation = new Rotate(angle, Rotate.Y_AXIS);
        rotateCam(newRotation);
    }

    /**
     * Applies both the currTransform and given rotation to the camera
     */
    private void rotateCam(Rotate rotation) {
        currTransform = currTransform.createConcatenation(rotation);
        getTransforms().clear();
        getTransforms().addAll(currTransform);
    }
}

>

package ui;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Sphere;
import javafx.stage.Stage;
import javafx.scene.Group;
import model.Molecule;

import java.util.Observable;
import java.util.Observer;

/**
 * Represents the window in which the molecule drawing editor appears.
 * Run the main method to start the program!
 */
public class MarsBonds extends Application {

    private static final int CAM_NEAR_CLIP = 0;
    private static final int CAM_FAR_CLIP = 1000;
    private static final int CAM_ORG_DISTANCE = -10;
    private static final int WIDTH = 1000;
    private static final int HEIGHT = 800;
    private static final Color SCENE_COLOR = Color.BLACK;
    private static final int CAM_SPEED = 30;

    private static Stage primaryStage;
    private static RotateCamera camera;
    private static Scene scene;

    @Override
    public void start(Stage primaryStage) throws Exception {
        setScene();
        setCamera();
        setPrimaryState(primaryStage);
    }

    /**
     * Creates scene with molecule in center of screen and black background
     */
    public static void setScene() {
        Sphere molecule = new Sphere(30);
        molecule.translateXProperty().set(WIDTH/2);
        molecule.translateYProperty().set(HEIGHT/2);
        Group root = new Group();
        root.getChildren().add(molecule);
        scene = new Scene(root, WIDTH, HEIGHT);
        scene.setFill(SCENE_COLOR);
    }

    /**
     * Initializes camera and adds to scene
     */
    private static void setCamera() {
        camera = new RotateCamera();
        camera.setNearClip(CAM_NEAR_CLIP);
        camera.setFarClip(CAM_FAR_CLIP);
        camera.translateZProperty().set(CAM_ORG_DISTANCE);
        scene.setCamera(camera);
    }

    /**
     * Sets up the primary stage by setting its scene, title, and adding key control
     * @param stage the primary stage
     */
    private static void setPrimaryState(Stage stage) {
        primaryStage = stage;
        addEventHandlers();
        primaryStage.setTitle("Mar's Bonds");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * Adds KeyEvent handler to primary stage
     * The KeyEvent handler uses input from the WASD keys to rotate
     * the camera and the arrow keys to move the camera
     */
    private static void addEventHandlers() {
        primaryStage.addEventHandler(KeyEvent.KEY_PRESSED, e -> {
            switch(e.getCode()) {
                case W:
                    camera.rotateInX(-1);
                    break;
                case S:
                    camera.rotateInX(1);
                    break;
                case A:
                    camera.rotateInY(1);
                    break;
                case D:
                    camera.rotateInY(-1);
                    break;
                case UP:
                    camera.setTranslateZ(camera.getTranslateZ() + CAM_SPEED);
                    break;
                case DOWN:
                    camera.setTranslateZ(camera.getTranslateZ() - CAM_SPEED);
                    break;
                case LEFT:
                    camera.setTranslateX(camera.getTranslateX() - CAM_SPEED/3);
                    break;
                case RIGHT:
                    camera.setTranslateX(camera.getTranslateX() + CAM_SPEED/3);
                    break;
            }
        });
    }

    public static void main( String[] args ) {
        launch(args);
    }
}
  • See: [How to create a Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve). – SedJ601 Jun 03 '19 at 21:30
  • The behavior of the camera seems correct. After a full 360 in the WASD direction, the `Sphere` (replacing the `Molecule` class) came back to the exact position it was at. – user1803551 Jun 04 '19 at 13:46
  • @user1803551 Right, sorry I forgot I didn't attach the code for the Molecule class (it's just a class that extends Sphere so it doesn't really matter). Actually I've figured out that the camera only appears to move during rotation if you first move it with the arrow keys. I think this has to do with the fact that I'm rotating the camera around the points Rotate.X_AXIS and Rotate.Y_AXIS, but I don't know how to fix it. – user2669897 Jun 04 '19 at 19:11
  • I still don't understand what the exact issue is. What is happening that you think shouldn't (or vice versa)? One thing you might want to be aware of is that translation and rotation have a defined order, so you might think that one happens before/after another, but it doesn't. – user1803551 Jun 04 '19 at 19:40
  • This is the screen when the application first runs:[original screen](https://drive.google.com/file/d/1HvwlCMMeA-JHI_6sbvVO601jha7rqh0m/view?usp=sharing) This is the screen after moving the camera forward pressing the forward arrow key:[after zoom in](https://drive.google.com/file/d/1b2ojDd8-IFHzMUTUeJhZ2CGVLYLSCZ3F/view?usp=sharing) This is the screen after rotating the camera 360 degrees:[after rotation](https://drive.google.com/file/d/1XlB61vTLdL80Or6j_CIUjkALbAvWXZif/view?usp=sharing). Why does the sphere look far away after rotating the camera? Shouldn't the camera be in the same location? – user2669897 Jun 04 '19 at 20:49
  • @user1803551 (forgot to tag you in the above post) – user2669897 Jun 05 '19 at 15:59
  • The screen when the application first runs and the one after a 360 degrees rotation are the same for me. I press A, S, D or W until I accumulate a +-360 rotation, and I get the starting point. I do not use any arrow keys. If you get a different result, you are not using the code you posted. – user1803551 Jun 08 '19 at 20:34
  • @user1803551 First use the arrow keys to move the camera forward, then rotate 360 degrees. If you do not move the camera first, rotating the camera works perfectly. The bug only shows up if you first move the camera forward by pressing the up arrow (like what I did in the screenshots) – user2669897 Jun 14 '19 at 19:02
  • I'll try to get to this this week. – user1803551 Jun 25 '19 at 03:50

0 Answers0