如何select 3D场景中的2D节点?
How to select a 2D node in a 3D scene?
这是我的代码。您可以复制粘贴并按照我在下面写的内容自己查看问题。
public class MyApp extends Application {
@Override
public void start(Stage stage) throws Exception {
Scene scene = new Scene(new MyView(), 100, 150);
stage.setScene(scene);
stage.show();
}
private class MyView extends BorderPane {
MyView() {
GridPane board = new GridPane();
int size = 3;
for (int i = 0; i < size*size; i++) {
BorderPane pane = new BorderPane();
pane.setMinSize(30, 30);
pane.setBackground(new Background(new BackgroundFill(Color.RED, null, null)));
pane.setBorder(new Border(new BorderStroke(null, BorderStrokeStyle.SOLID,
null, null, null)));
pane.setOnMousePressed(e -> {
PickResult pick = e.getPickResult();
Pane selectedNode = (Pane) pick.getIntersectedNode();
selectedNode.setBackground(new Background(new BackgroundFill(Color.GREEN, null, null)));
});
board.add(pane, i / size, i % size);
}
Box box = new Box(20d, 20d, 20d);
BorderPane boardPane = new BorderPane(box, null, null, board, null);
Group root = new Group(boardPane);
SubScene scene = new SubScene(root, USE_PREF_SIZE, USE_PREF_SIZE, true, SceneAntialiasing.BALANCED);
scene.widthProperty().bind(widthProperty());
scene.heightProperty().bind(heightProperty());
setCenter(scene);
}
}
public static void main(String[] args) throws Exception {
launch(args);
}
}
我创建了一个带有正方形网格的子场景。当我按下一个正方形时,我希望它的背景改变颜色。这适用于 2 种情况:
- 如果我不将 Box 添加到
boardPane
- 如果我不使用深度缓冲区设置场景
或两者兼而有之。但是,如果我同时添加框并设置深度缓冲区,则方块不会收到事件。相反 boardPane
收到它。我想这与 3D 场景中的 2D 节点有关。
我尝试设置这些方法的组合:setPickOnBounds
、setDepthTest
、setMouseTransparent
,但没有任何效果。
有什么解决办法?
一旦有了 3D 场景,就没有真正的 2D 节点之类的东西了,场景图中的所有内容都有 x、y 和 z 坐标;即使是之前在深度缓冲区设置为 false 时被视为 2D 节点的东西。
当您在根边框窗格中放置一个框时,该根边框窗格采用该框的 3D 坐标。出于拾取目的,您定义的框在 3D space 中从 z 坐标 -10 到 10 表示,因此根边框窗格被定义为 -10 用于拾取目的。您放置在根边框窗格内的边框窗格没有为它们定义的 z 坐标,因此它们最终的 z 坐标为 0,从查看者的角度来看,它位于根边框窗格的后面。
因此,根边框窗格收到了点击,但因为它现在与其其余内容位于不同的 z 平面上,所以您定义的其他 2D 正方形内容不会收到点击。有人可能会争辩说根边框窗格根本没有呈现,因为它没有颜色,所以它应该被视为透明的并且点击只是通过子节点,但它似乎不是 3D 拾取算法的方式JavaFX 有效。
对于您的示例,要使所有东西都在同一个 Z 平面中并正确工作,请在您的 for 循环中添加以下行:pane.setTranslateZ(-10);
。
注意:我通过将以下行添加到您的源代码(它向我报告了鼠标点击的目标和每次点击的 x、y、z 选择结果坐标)来对此进行了调试:
root.setOnMouseClicked(System.out::println);
我的建议是避免使用专为 2D 目的设计的布局窗格(例如边框窗格)来尝试在 3D 中布置元素 space。 JavaFX 布局窗格实际上仅适用于 2D 布局。要处理 3D 中的定位 space 您应该自己管理坐标,只需使用组而不是派生自 Pane 的任何东西。至少不要尝试将 3D 元素添加到 2D 布局窗格中,因为结果可能会令人困惑(如您所见)。
您可以通过将它们放置在不同的子场景中来进一步分离 2D 和 3D 项目(这就是 intention of the sub scene notion in JavaFX is I think). An example of an application with multiple sub scenes is shown in the following answer: How to create custom 3d model in JavaFX 8?
这是我的代码。您可以复制粘贴并按照我在下面写的内容自己查看问题。
public class MyApp extends Application {
@Override
public void start(Stage stage) throws Exception {
Scene scene = new Scene(new MyView(), 100, 150);
stage.setScene(scene);
stage.show();
}
private class MyView extends BorderPane {
MyView() {
GridPane board = new GridPane();
int size = 3;
for (int i = 0; i < size*size; i++) {
BorderPane pane = new BorderPane();
pane.setMinSize(30, 30);
pane.setBackground(new Background(new BackgroundFill(Color.RED, null, null)));
pane.setBorder(new Border(new BorderStroke(null, BorderStrokeStyle.SOLID,
null, null, null)));
pane.setOnMousePressed(e -> {
PickResult pick = e.getPickResult();
Pane selectedNode = (Pane) pick.getIntersectedNode();
selectedNode.setBackground(new Background(new BackgroundFill(Color.GREEN, null, null)));
});
board.add(pane, i / size, i % size);
}
Box box = new Box(20d, 20d, 20d);
BorderPane boardPane = new BorderPane(box, null, null, board, null);
Group root = new Group(boardPane);
SubScene scene = new SubScene(root, USE_PREF_SIZE, USE_PREF_SIZE, true, SceneAntialiasing.BALANCED);
scene.widthProperty().bind(widthProperty());
scene.heightProperty().bind(heightProperty());
setCenter(scene);
}
}
public static void main(String[] args) throws Exception {
launch(args);
}
}
我创建了一个带有正方形网格的子场景。当我按下一个正方形时,我希望它的背景改变颜色。这适用于 2 种情况:
- 如果我不将 Box 添加到
boardPane
- 如果我不使用深度缓冲区设置场景
或两者兼而有之。但是,如果我同时添加框并设置深度缓冲区,则方块不会收到事件。相反 boardPane
收到它。我想这与 3D 场景中的 2D 节点有关。
我尝试设置这些方法的组合:setPickOnBounds
、setDepthTest
、setMouseTransparent
,但没有任何效果。
有什么解决办法?
一旦有了 3D 场景,就没有真正的 2D 节点之类的东西了,场景图中的所有内容都有 x、y 和 z 坐标;即使是之前在深度缓冲区设置为 false 时被视为 2D 节点的东西。
当您在根边框窗格中放置一个框时,该根边框窗格采用该框的 3D 坐标。出于拾取目的,您定义的框在 3D space 中从 z 坐标 -10 到 10 表示,因此根边框窗格被定义为 -10 用于拾取目的。您放置在根边框窗格内的边框窗格没有为它们定义的 z 坐标,因此它们最终的 z 坐标为 0,从查看者的角度来看,它位于根边框窗格的后面。
因此,根边框窗格收到了点击,但因为它现在与其其余内容位于不同的 z 平面上,所以您定义的其他 2D 正方形内容不会收到点击。有人可能会争辩说根边框窗格根本没有呈现,因为它没有颜色,所以它应该被视为透明的并且点击只是通过子节点,但它似乎不是 3D 拾取算法的方式JavaFX 有效。
对于您的示例,要使所有东西都在同一个 Z 平面中并正确工作,请在您的 for 循环中添加以下行:pane.setTranslateZ(-10);
。
注意:我通过将以下行添加到您的源代码(它向我报告了鼠标点击的目标和每次点击的 x、y、z 选择结果坐标)来对此进行了调试:
root.setOnMouseClicked(System.out::println);
我的建议是避免使用专为 2D 目的设计的布局窗格(例如边框窗格)来尝试在 3D 中布置元素 space。 JavaFX 布局窗格实际上仅适用于 2D 布局。要处理 3D 中的定位 space 您应该自己管理坐标,只需使用组而不是派生自 Pane 的任何东西。至少不要尝试将 3D 元素添加到 2D 布局窗格中,因为结果可能会令人困惑(如您所见)。
您可以通过将它们放置在不同的子场景中来进一步分离 2D 和 3D 项目(这就是 intention of the sub scene notion in JavaFX is I think). An example of an application with multiple sub scenes is shown in the following answer: How to create custom 3d model in JavaFX 8?