I am trying to develop a tool with JavaFX that has multiple viewports and I think the best way to do that is through the use of SubScenes. One requirement I have is the ability to know where on a given plane in the scene corresponds to the pixel clicked by the mouse. I thought that I could use the Node.localToScreen() and Node.screenToLocal() functions to do this, however when adding a SubScene I get different values, despite nothing else changing.
Below is an example, where running the code with withSubScene = false
, the console shows:
Point2D [x = 996.0, y = 514.8333400189878]
Point2D [x = 117.98005476276654, y = 514.8333400189878]
And running with withSubScene = true
, the console shows:
Point2D [x = 997.0, y = 529.3333400189878]
Point2D [x = 64.91937872905163, y = 529.3333400189878]
Why would these values be different, when the camera is in the same location and looking at the same object?
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class ScreenToLocalTest extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
// Change this variable to swap to adding a SubScene
boolean withSubScene = false;
// Set the stage to be the same size each time
primaryStage.setWidth(1000);
primaryStage.setHeight(500);
Group root = new Group();
Scene rootScene = new Scene(root);
// Create out camera
Camera camera = new PerspectiveCamera(true);
camera.setTranslateZ(-1000);
camera.setNearClip(1);
camera.setFarClip(10000);
Group groupToAddRectangle;
if(withSubScene) {
Group sceneRoot = new Group();
SubScene subScene = new SubScene(sceneRoot, primaryStage.getWidth(), primaryStage.getHeight());
root.getChildren().add(subScene);
subScene.setCamera(camera);
groupToAddRectangle = sceneRoot;
} else {
rootScene.setCamera(camera);
groupToAddRectangle = root;
}
Rectangle rectangle = new Rectangle(1000, 300, Color.ALICEBLUE);
groupToAddRectangle.getChildren().add(rectangle);
rectangle.setTranslateZ(1);
root.setOnMouseMoved(event-> {
System.out.println(rectangle.screenToLocal(event.getScreenX(), event.getScreenY()));
});
primaryStage.setScene(rootScene);
primaryStage.show();
System.out.println(rectangle.localToScreen(0, 0));
rectangle.translateXProperty().set(-1000);
System.out.println(rectangle.localToScreen(0, 0));
}
public static void main(String[] args) {
launch(args);
}
}