在JavaFX中将3D对象鼠标拖动移动限制到一个平面 [英] Restricting a 3D object mouse drag movement to a plane in JavaFX

查看:191
本文介绍了在JavaFX中将3D对象鼠标拖动移动限制到一个平面的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用JavaFX通过鼠标拖动来移动3D立方体。立方体应停留在x和z轴所跨的平面上。我的解决方案效果很好,但是,如果我用鼠标将立方体移动得太快,或者当它遇到具有特定深度(y轴)的对象时,则假定鼠标正在y轴和立方体上移动开始向前或向后跳跃。有没有一种方法可以将鼠标限制在xz平面上?一个更复杂的解决方案是将y长度投影回xz平面,但是我不知道该怎么做。
我看了 JavaFX移动3D对象,但无法适应我的情况。



到目前为止,我的代码是:

 私有易失性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()); //应该保持较小的值,但有时会跳到较高的值,从而造成问题。
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拖动的两种可能方法:




  • 纯拖动和像您提出的建议

  • 非投影方向,例如问题



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



这里的窍门是,不要听形状上拖动事件之间的交互,而要听



通过定义目标,您可以轻松限制形状的移动,因为仅当将其拖动到该目标上时才会更新其位置。



因此,如果您想限制飞机上的运动,可以使用 Rectangle 作为目标。 / 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(新Rotate(60,Rotate.X_AXIS),新Translate(-200,-200,300));

最终组根= new Group();

最终Box层=新Box(500,500,1);
floor.setTranslateX(200);
floor.setTranslateY(200);
floor.setTranslateZ(50);
floor.setMaterial(new PhongMaterial(Color.YELLOW));
root.getChildren()。add(floor);

最终Box框= new Box(50,50,50);
box.setMaterial(new PhongMaterial(Color.RED));
root.getChildren()。add(box);

最终的Rectangle矩形= new Rectangle(400,400,Color.TRANSPARENT);
angle.setMouseTransparent(true);
矩形.setDepthTest(DepthTest.DISABLE);
root.getChildren()。add(rectangle);

// D& D开始
box.setOnDragDetected((MouseEvent event)-> {
box.setMouseTransparent(true);
矩形.setMouseTransparent(false );
box.setCursor(Cursor.MOVE);
box.startFullDrag();
});

// D& D结尾
box.setOnMouseReleased((MouseEvent event)-> {
box.setMouseTransparent(false);
矩形.setMouseTransparent(true );
box.setCursor(Cursor.DEFAULT);
});

//在D& D中,仅限于矩形
矩形。setOnMouseDragOver((MouseDragEvent事件)-> {
Point3D coords = event.getPickResult()。getIntersectedPoint ();
coords =矩形.localToParent(coords);
box.setTranslateX(coords.getX());
box.setTranslateY(coords.getY());
box.setTranslateZ(coords.getZ());
});

最终场景场景=新场景(root,800,600,true);
scene.setCamera(cam);

stage.setScene(scene);
stage.setTitle( JavaFX 3D拖放);
stage.show();
}

如果运行它,您会看到可以选择该框并拖动它遍布整个地板。



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





请注意鼠标在方框和矩形中均透明。矩形仅在拖动期间不是鼠标透明的。


I'm using JavaFX to move 3D cubes around by mouse drag. The cube should stay on the plane spanned by x and z axis. My solution works fairly well, however if I move the cube too fast with my mouse or when it encounters an object with a certain depth (y-Axis), it is assumed, that the mouse is moving on the y-Axis and the cube starts jumping forward or backwards. Is there a way to restrict the mouse to the xz-plane? A more complicated solution would be projecting the y length back to the xz-plane, but I got no clue how. I looked at JavaFX Moving 3D Objects, but couldn't adapt it to my case.

My code so far:

    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);
            }
        });
   }

解决方案

As you have mentioned, there two possible approachs for 3D dragging:

  • Pure drag & drop, like you propose
  • unprojecting directions, like in this question.

For drag and drop events, we can detect a drag event on the 3D shape, when the event starts and finishes.

The trick here is, instead of listening to the in between dragging events on the shape, listen to drag over events on a possible target.

By defining a target, you can restrict easily the shape movements, since you will only update its position when you are dragging it only over this target.

So if you want to restrict movements on a plane, you can use a Rectangle as the target.

This snippet shows how this approach works:

@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();
}

If you run it, you will see that you can pick the box and drag it all over the floor.

In this picture, I've added some color and stroke to the rectangle to see the limits of dragging.

Note also the changes in mouse transparent both in box and rectangle. The rectangle is not mouse transparent only during the dragging.

这篇关于在JavaFX中将3D对象鼠标拖动移动限制到一个平面的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆