3d 在JavaFX中将三维对象鼠标拖动移动限制到平面
我正在使用JavaFX通过鼠标拖动来移动3D立方体。立方体应保持在x轴和z轴跨越的平面上。我的解决方案工作得相当好,但是如果我用鼠标移动立方体太快,或者当它遇到具有一定深度(y轴)的对象时,假设鼠标在y轴上移动,立方体开始向前或向后跳跃。有没有办法将鼠标限制在xz平面上?更复杂的解决方案是将y长度投影回xz平面,但我不知道如何。 我看了看,但不能适应我的情况 到目前为止,我的代码是:3d 在JavaFX中将三维对象鼠标拖动移动限制到平面,3d,javafx,axis,drag,javafx-3d,3d,Javafx,Axis,Drag,Javafx 3d,我正在使用JavaFX通过鼠标拖动来移动3D立方体。立方体应保持在x轴和z轴跨越的平面上。我的解决方案工作得相当好,但是如果我用鼠标移动立方体太快,或者当它遇到具有一定深度(y轴)的对象时,假设鼠标在y轴上移动,立方体开始向前或向后跳跃。有没有办法将鼠标限制在xz平面上?更复杂的解决方案是将y长度投影回xz平面,但我不知道如何。 我看了看,但不能适应我的情况 到目前为止,我的代码是: private volatile double relMousePosX; private vo
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);
}
});
}
如您所述,三维拖动有两种可能的方法:
- 纯拖放,就像你建议的那样
- 非投影方向,如图所示
矩形
作为目标
此代码段显示了此方法的工作原理:
@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(),这样框就会被你点击的地方抓住,而且它的中心不会在第一次拖动时跳到鼠标指针上。当然,代码片段还有改进的余地,但是你会想到如何在你方便的时候定义平面,允许三维物体在这些空间内移动。多亏了下面JoséPereda的解决方案,我才得以实现它。请参阅:以及存储库的其余部分以了解上下文。