1
votes

Is there any way to have two scenes that are having two different cameras, but looking at the same objects at the same time with out duplicating instances of every object? I am developing a 3D game that has main scene with camera that is following the player and I would want to have another scene in the corner that is showing the bird's eye view of the same environment, like a mini map. Any ideas how to develop this?

1
This is a valid question but I doubt that this is technically possible. - mipa
You can’t have the same nodes be part of two different scenes. I’d recommend a MVC approach: you basically have two views of the same model. - James_D

1 Answers

3
votes

For starters, you can't have two scenes at the same stage. You could have two scenes and two stages, but obviously that would mean having duplicated objects, that need to be synchronized between scenes and stages.

However, there is possible way to get, in the same stage and same scene, a small mini-map (2D) node on top of the overall 3D node, each of them having their own camera.

This is based on this answer, and the existing CameraView class in the FXyz library.

As you can see, CameraView is basically an ImageView node that goes on the main scene to the right bottom corner (or anywhere else), while the 3D part goes to a SubScene in the center of the scene.

Both the subScene and the imageView can have mouse/keyboard event handling, and both have a camera, so in a way you have two different 3D views with their own control of the same 3D object.

To get a "live" ImageView that reflects the content of the subScene, looking like a real subScene, but without duplicating objects, the CameraView mainly uses:

  • Node::snapshot: taking snapshots of the subScene with will get an updated Image for the ImageView.

  • SnapshotParameters::setCamera (see javadoc. This not so well-known feature allows taking the snapshot with a given perspective based on a given camera.

  • AnimationTimer to do this process all over again on every frame/pulse.

The following is a simple use case of the CameraView, that can be added to your project including the org.fxyz3d:fxyz3d:0.5.2 dependency.

    @Override
    public void start(Stage stage) {

        // 1. SubScene

        // 3D node
        SpringMesh spring = new SpringMesh(10, 2, 2, 8 * 2 * Math.PI, 200, 100, 0, 0);
        spring.setCullFace(CullFace.NONE);
        spring.setTextureModeVertices3D(1530, p -> p.f);

        // root
        Group worldRoot = new Group(spring);

        // Camera
        PerspectiveCamera camera = new PerspectiveCamera(true);
        CameraTransformer cameraTransform = new CameraTransformer();
        cameraTransform.setTranslate(0, 0, 0);
        cameraTransform.getChildren().add(camera);
        camera.setNearClip(0.1);
        camera.setFarClip(10000.0);
        camera.setTranslateZ(-100);
        camera.setFieldOfView(20);
        cameraTransform.ry.setAngle(-30.0);
        cameraTransform.rx.setAngle(-15.0);
        worldRoot.getChildren().add(cameraTransform);

        // SubScene
        SubScene subScene = new SubScene(worldRoot, 800,600, true, SceneAntialiasing.BALANCED);
        subScene.setFill(Color.DARKSLATEGRAY);
        subScene.setCamera(camera);

        // mouse, key events on subScene:
    
        // subScene.setOnKeyPressed(event -> {...});
        // subScene.setOnMousePressed(event -> {...});
        // subScene.setOnMouseDragged(event -> {...});

        // 2. CameraView
        CameraView cameraView = new CameraView(subScene);
        cameraView.setFirstPersonNavigationEabled(true);
        cameraView.setFitWidth(350);
        cameraView.setFitHeight(225);
        cameraView.getRx().setAngle(-45);
        cameraView.getT().setZ(-100);
        cameraView.getT().setY(-500);
        cameraView.getCamera().setTranslateZ(-100);

        // Right-bottom corner
        StackPane.setAlignment(cameraView, Pos.BOTTOM_RIGHT);
        StackPane.setMargin(cameraView, new Insets(5));

        // 3. Scene
        StackPane root = new StackPane(subScene, cameraView);
        root.setStyle("-fx-background-color: DEEPSKYBLUE;");
        subScene.widthProperty().bind(root.widthProperty());
        subScene.heightProperty().bind(root.heightProperty());

        Scene scene = new Scene(root, 810,610, true, SceneAntialiasing.BALANCED);
        stage.setTitle("MiniMapTest");
        stage.setScene(scene);
        stage.show();

        // start timer
        cameraView.startViewing();
    }

Running the application, you will get:

Mini-map 1

and you can move the camera on the mini-map view to get a different view of the 3D object:

Mini-map 2

Now it's up to you to play around with both 3D subScene and 2D cameraView to get the effect you want. By setting cameraView.setFirstPersonNavigationEabled(false) the mini-map won't allow user interaction, and you could control its camera (i.e, keeping a given zoom level of the subScene...).