【问题标题】:Restricting a 3D object mouse drag movement to a plane in JavaFX将 3D 对象鼠标拖动移动限制到 JavaFX 中的平面
【发布时间】:2015-03-13 13:55:12
【问题描述】:

我正在使用 JavaFX 通过鼠标拖动来移动 3D 立方体。立方体应保持在 x 和 z 轴跨越的平面上。我的解决方案效果很好,但是如果我用鼠标移动立方体太快或遇到具有一定深度(y 轴)的对象时,假设鼠标在 y 轴和立方体上移动开始向前或向后跳跃。有没有办法将鼠标限制在 xz 平面上?一个更复杂的解决方案是将 y 长度投影回 xz 平面,但我不知道如何。 我查看了JavaFX Moving 3D Objects,但无法适应我的情况。

到目前为止我的代码:

    private volatile double relMousePosX;
    private volatile double relMousePosZ;

    public void enableDragMove(PaneBox paneBox) {
        Group paneBoxGroup = paneBox.get();

        paneBoxGroup.setOnMousePressed((MouseEvent me) -> {
            if(isSelected(paneBox) && MouseButton.PRIMARY.equals(me.getButton())) {
                relMousePosX = me.getX();
                relMousePosZ = me.getZ();
            }
        });

        paneBoxGroup.setOnMouseDragged((MouseEvent me) -> {
            if(paneBoxGroup.focusedProperty().get() && MouseButton.PRIMARY.equals(me.getButton())) {
                setDragInProgress(paneBox, true);
                System.out.println(me.getY()); // should stay small value, but jumps to higher values at times, creating the problem.
                paneBoxGroup.setCursor(Cursor.MOVE);
                paneBox.setTranslateX(paneBox.getTranslateX() + (me.getX() - relMousePosX));
                paneBox.setTranslateZ(paneBox.getTranslateZ() + (me.getZ() - relMousePosZ));
            }
        });

        paneBoxGroup.setOnMouseReleased((MouseEvent me) -> {
            if(paneBoxGroup.focusedProperty().get() && MouseButton.PRIMARY.equals(me.getButton())) {
                setDragInProgress(paneBox, false);
                paneBoxGroup.setCursor(Cursor.DEFAULT);
            }
        });
   }

【问题讨论】:

标签: 3d javafx axis drag javafx-3d


【解决方案1】:

正如您所提到的,3D 拖动有两种可能的方法:

  • 按照您的建议进行纯拖放
  • 未投影的方向,例如 question

对于拖放事件,我们可以在事件开始和结束时检测 3D 形状上的拖动事件。

这里的技巧是,不是在形状上的拖动事件之间监听,而是在可能的目标上监听拖动事件。

通过定义一个目标,您可以轻松地限制形状移动,因为您只会在将其拖动到该目标上时更新其位置。

所以如果你想限制飞机上的移动,你可以使用Rectangle作为目标。

这个 sn-p 显示了这种方法的工作原理:

@Override 
public void start(Stage stage) {
    final PerspectiveCamera cam = new PerspectiveCamera();
    cam.setFieldOfView(20);
    cam.setFarClip(10000);
    cam.setNearClip(0.01);
    cam.getTransforms().addAll(new Rotate(60,Rotate.X_AXIS),new Translate(-200,-200,300));

    final Group root = new Group();

    final Box floor = new Box(500, 500, 1);
    floor.setTranslateX(200);
    floor.setTranslateY(200);
    floor.setTranslateZ(50);
    floor.setMaterial(new PhongMaterial(Color.YELLOW));
    root.getChildren().add(floor);

    final Box box = new Box(50, 50, 50);
    box.setMaterial(new PhongMaterial(Color.RED));
    root.getChildren().add(box);

    final Rectangle rectangle = new Rectangle(400, 400, Color.TRANSPARENT);
    rectangle.setMouseTransparent(true);
    rectangle.setDepthTest(DepthTest.DISABLE);
    root.getChildren().add(rectangle);

    // D&D starts
    box.setOnDragDetected((MouseEvent event)-> {
        box.setMouseTransparent(true);
        rectangle.setMouseTransparent(false);
        box.setCursor(Cursor.MOVE);
        box.startFullDrag();
    });

    // D&D ends
    box.setOnMouseReleased((MouseEvent event)-> {
        box.setMouseTransparent(false);
        rectangle.setMouseTransparent(true);
        box.setCursor(Cursor.DEFAULT);
    });

    // While D&D, only confined to the rectangle
    rectangle.setOnMouseDragOver((MouseDragEvent event)-> {
        Point3D coords = event.getPickResult().getIntersectedPoint();
        coords = rectangle.localToParent(coords);
        box.setTranslateX(coords.getX());
        box.setTranslateY(coords.getY());
        box.setTranslateZ(coords.getZ());
    });

    final Scene scene = new Scene(root, 800, 600, true);
    scene.setCamera(cam);

    stage.setScene(scene);
    stage.setTitle("JavaFX 3D Drag&Drop");
    stage.show();
}

如果你运行它,你会看到你可以选择盒子并将它拖到地板上。

在这张图片中,我为矩形添加了一些颜色和笔触,以查看拖动的限制。

还要注意鼠标透明在框和矩形中的变化。矩形仅在拖动过程中不是鼠标透明的。

【讨论】:

  • 这种方法近乎完美!唯一的缺点是,您需要使场景鼠标中的所有节点都是透明的(就像迭代子场景世界的所有子节点)并且地板的大小是有限的(但可以绑定到相机坐标以跟随)。还要从 coords.getX() 等中减去 event.getX() ,这样 Box 就会被您点击的位置捕获,并且它的中心不会在第一次拖动时跳转到鼠标指针。
  • 嗯,当然,sn-p 有改进的余地,但是您会知道如何在方便的时候定义平面,以允许限制在这些空间内的 3D 对象的移动。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多