如何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 种情况:

  1. 如果我不将 Box 添加到 boardPane
  2. 如果我不使用深度缓冲区设置场景

或两者兼而有之。但是,如果我同时添加框并设置深度缓冲区,则方块不会收到事件。相反 boardPane 收到它。我想这与 3D 场景中的 2D 节点有关。

我尝试设置这些方法的组合:setPickOnBoundssetDepthTestsetMouseTransparent,但没有任何效果。

有什么解决办法?

一旦有了 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?