java - 最简单的通过鼠标旋转相机不起作用

标签 java javafx javafx-3d

好吧,这让我发疯。文档很薄弱,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) 处。
image
这是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();
    }
}

最佳答案

而不是将相机添加到 Group 的 children ,

getChildren().add(camera);
您应该设置场景的相机。
scene.setCamera(g.camera);
您将立即看到屏幕中央的轴。同样,鼠标处理程序应应用于场景。然后,您可以在场景处理程序中更新组的变换。
例如,下面的变体根据鼠标滚动事件改变了相机的旋转。请注意鼠标垂直滚动如何影响绕 X 轴的旋转,而鼠标水平滚动如何影响绕 Y 轴的旋转。同样的手势也将整个群体转化为整体。一系列键盘命令使人们能够围绕 Z 轴旋转相机、沿 Z 轴移动并重置场景。
您可以围绕圆上的点平移和旋转,如图 here ;相比之下,这个相关example动画对象围绕枢轴的旋转。
imageImag
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();
    }
}

关于java - 最简单的通过鼠标旋转相机不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69249037/

相关文章:

java - 通过 JavaFX 8 中的代码访问和更改 css 伪类的值

java - JavaFX 多线程导致 java.lang.IllegalStateException : Not on FX application thread

java - 使用鼠标和键盘在 3D 空间中移动 [JavaFX3D]

java - 如何将网格从 Blender 3.++ 导入到 javafx?

3d - 将 3D 对象鼠标拖动移动限制到 JavaFX 中的平面

java - Jbilling + Ruby

java - 通过 JAX-RS 的 RESTful,@QueryParam 和@Consume 的常见用法是什么?

java - 如何正确使用回调?

java - 使用最少的批处理发送不同大小的文档

java - 仅允许 JavaFX 节点的视觉溢出