【问题标题】:Most simple rotate camera via mouse not working通过鼠标最简单的旋转相机不起作用
【发布时间】:2021-11-13 20:14:57
【问题描述】:

好吧,这快把我逼疯了。文档很薄弱,Oracle 的示例应用程序很奇怪,有一个巨大的令人费解的帮助类,甚至这里的问题都没有答案!

我在很大程度上遵循并简化了this tutorial,但我没有旋转对象,而是尝试旋转相机,所以当你拖动鼠标时,它应该围绕相机旋转。

但是,尽管我已经通过控制台日志和调试确认正在调用事件处理程序,并且一切似乎都有正确的值,但我的轮换永远不会发生!我错过了什么?

此外,我根本无法移动相机,即使(注释掉)translateX 之类的也不起作用,所以我很困惑,但无法让轴看起来喜欢除了左上角的任何地方!

import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.scene.Camera;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.transform.Rotate;

public class RotateCameraExample extends Group {

    private double anchorX, anchorY;
    private double anchorAngleX = 0;
    private double anchorAngleY = 0;
    private DoubleProperty angleX = new SimpleDoubleProperty(0);
    private DoubleProperty angleY = new SimpleDoubleProperty(0);

    Camera camera;
    Group axes;

    public RotateCameraExample() {
        axes = buildAxes();
        getChildren().add(axes);

        camera = new PerspectiveCamera(true);
        camera.setFarClip(6000);
        camera.setNearClip(0.01);
        //camera.translateYProperty().set(300); // this doesn't do anything!  why?

        getChildren().add(camera);
        initMouseControl();
    }

    private void initMouseControl() {
        Rotate xRotate = new Rotate(0, Rotate.X_AXIS);
        Rotate yRotate = new Rotate(0, Rotate.Y_AXIS);
        camera.getTransforms().addAll(xRotate, yRotate);

        xRotate.angleProperty().bind(angleX);
        yRotate.angleProperty().bind(angleY);

        setOnMousePressed(event -> {
            anchorX = event.getSceneX();
            anchorY = event.getSceneY();
            anchorAngleX = angleX.get();
            anchorAngleY = angleY.get();
        });

        setOnMouseDragged(event -> {
            angleX.set(anchorAngleX - (anchorY - event.getSceneY()));
            angleY.set(anchorAngleY + anchorX - event.getSceneX());
        });
    }

    private Group buildAxes() {
        final Box xAxis = new Box(1200, 10, 10);
        final Box yAxis = new Box(10, 1200, 10);
        final Box zAxis = new Box(10, 10, 1200);

        xAxis.setMaterial(new PhongMaterial(Color.RED));
        yAxis.setMaterial(new PhongMaterial(Color.GREEN));
        zAxis.setMaterial(new PhongMaterial(Color.BLUE));

        Group axisGroup = new Group();
        axisGroup.getChildren().addAll(xAxis, yAxis, zAxis);
        return axisGroup;
    }
}

这里可以看到轴在左上角可见,我希望它在围绕它移动相机时保持在 (0, 0, 0)。

这是Application 的启动代码,这显然不是问题:

public class TestApp extends Application {
    @Override
    public void start(Stage stage) throws IOException {
        RotateCameraExample g = new RotateCameraExample();
        Scene scene = new Scene(g, 800, 800, Color.BLACK);
        stage.setScene(scene);
        stage.show();
    }
    public static void main(String[] args) {
        launch();
    }
}

【问题讨论】:

    标签: java javafx javafx-3d


    【解决方案1】:

    而不是添加相机到Group的孩子,

    getChildren().add(camera);
    

    你应该设置场景的相机。

    scene.setCamera(g.camera);
    

    您将立即看到屏幕中心的坐标轴。同样,鼠标处理程序应应用于场景。然后,您可以在场景的处理程序中更新组的变换。

    例如,下面的变体改变了相机的旋转以响应鼠标滚动事件。请注意垂直鼠标滚动如何影响围绕 X 轴的旋转,而水平鼠标滚动如何影响围绕 Y 轴的旋转。同样的手势也将整个群体翻译成一个整体。各种键盘命令使您能够围绕 Z 轴旋转相机,沿 Z 轴旋转相机,并重置场景。

    你可以平移和旋转圆上的点,如图here;相比之下,这个相关的example 为对象围绕轴的旋转设置动画。

    import javafx.application.Application;
    import javafx.scene.Camera;
    import javafx.scene.Group;
    import javafx.scene.PerspectiveCamera;
    import javafx.scene.Scene;
    import javafx.scene.input.KeyCode;
    import javafx.scene.input.KeyEvent;
    import javafx.scene.input.ScrollEvent;
    import javafx.scene.paint.Color;
    import javafx.scene.paint.PhongMaterial;
    import javafx.scene.shape.Box;
    import javafx.scene.transform.Rotate;
    import javafx.stage.Stage;
    
    /**
     * @see https://stackoverflow.com/a/69260181/230513
     */
    public class RotateCameraExample extends Application {
    
        private static class RotateCamera extends Group {
    
            private final Camera camera;
            private final Rotate xRotate = new Rotate(0, Rotate.X_AXIS);
            private final Rotate yRotate = new Rotate(0, Rotate.Y_AXIS);
            private final Rotate zRotate = new Rotate(0, Rotate.Z_AXIS);
    
            public RotateCamera() {
                buildAxes();
                camera = new PerspectiveCamera(true);
                camera.setFarClip(6000);
                camera.setNearClip(0.01);
                camera.setTranslateZ(-2000);
                camera.getTransforms().addAll(xRotate, yRotate, zRotate);
            }
    
            private void buildAxes() {
                final Box xAxis = new Box(1200, 10, 10);
                final Box yAxis = new Box(10, 1200, 10);
                final Box zAxis = new Box(10, 10, 1200);
    
                xAxis.setMaterial(new PhongMaterial(Color.RED));
                yAxis.setMaterial(new PhongMaterial(Color.GREEN));
                zAxis.setMaterial(new PhongMaterial(Color.BLUE));
    
                Group axisGroup = new Group();
                axisGroup.getChildren().addAll(xAxis, yAxis, zAxis);
                this.getChildren().add(axisGroup);
            }
        }
    
        @Override
        public void start(Stage stage) {
            RotateCamera g = new RotateCamera();
            Scene scene = new Scene(g, 800, 800, Color.BLACK);
            scene.setCamera(g.camera);
            stage.setScene(scene);
            stage.show();
            scene.setOnScroll((final ScrollEvent e) -> {
                g.xRotate.setAngle(g.xRotate.getAngle() + e.getDeltaY() / 10);
                g.yRotate.setAngle(g.yRotate.getAngle() - e.getDeltaX() / 10);
                g.setTranslateX(g.getTranslateX() + e.getDeltaX());
                g.setTranslateY(g.getTranslateY() + e.getDeltaY());
            });
            scene.setOnKeyPressed((KeyEvent e) -> {
                KeyCode code = e.getCode();
                switch (code) {
                    case LEFT:
                        g.zRotate.setAngle(g.zRotate.getAngle() + 10);
                        break;
                    case RIGHT:
                        g.zRotate.setAngle(g.zRotate.getAngle() - 10);
                        break;
                    case UP:
                        g.setTranslateZ(g.getTranslateZ() - 100);
                        break;
                    case DOWN:
                        g.setTranslateZ(g.getTranslateZ() + 100);
                        break;
                    case HOME:
                        g.xRotate.setAngle(0);
                        g.yRotate.setAngle(0);
                        g.zRotate.setAngle(0);
                        g.setTranslateX(0);
                        g.setTranslateY(0);
                        g.setTranslateZ(0);
                        break;
                    default:
                        break;
                }
            });
        }
    
        public static void main(String[] args) {
            launch();
        }
    }
    

    【讨论】:

    • ??‍♂️ 哦,荣耀归于好,谢谢!所以我根本不需要添加相机?如果我想要更多摄像头怎么办,我是否只需使用setCamera() 切换到一个新摄像头,然后它会以某种方式自动添加为节点?
    • 很高兴它有帮助;我在上面添加了一些键盘处理程序;调试处理程序时,重置场景会派上用场; setCamera() 仅对SceneSubScene SnapshotParameters 可用;我从来不需要超过一台相机。
    • 对于多台相机,我建议您尝试一下并找出有效的方法(可能正如您所猜测的那样有效)。如果您认为它可能对其他人有帮助,您可以随时将其作为一个新问题提出,如果您已经知道答案,请自行回答您自己的问题。
    猜你喜欢
    • 1970-01-01
    • 2020-06-18
    • 2023-03-04
    • 2012-01-15
    • 2018-06-29
    • 1970-01-01
    • 2017-05-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多