如何在3D场景中选择2D节点? [英] How to select a 2D node in a 3D scene?

查看:250
本文介绍了如何在3D场景中选择2D节点?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的代码您可以复制粘贴,并按照我自己写的内容自己查看问题。

Here is my code. You can copy-paste and follow what I write bellow to see the problem yourself.

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

我创建了一个带有格子的网格。当我按一个正方形我想要它的背景改变颜色。这有两种情况:

I create a subscene with a grid of squares. When i press on a square I want its background to change color. This works in 2 situations:


  1. 如果我不将Box添加到 boardPane

  2. 如果我没有使用深度缓冲区设置场景

或两者。但是如果我都添加了方框并设置了一个深度缓冲区,那么方块就不会收到事件。而是将 boardPane 接收它。我想这是与3D场景中的2D节点有关的。

or both. But if i both add the box and set a depth buffer, the squares don't receive the event. instead the boardPane receives it. i guess it's something to do with 2D nodes in a 3D scene.

我尝试设置这些方法的组合: setPickOnBounds setDepthTest setMouseTransparent 但没有任何工作。

I tried setting combinations of these methods :setPickOnBounds, setDepthTest, setMouseTransparent but nothing worked.

什么是解决方案?

推荐答案

一旦你有一个3D场景,没有真正的2D节点,场景图具有x,y和z坐标;甚至当深度缓冲区设置为false时,以前被视为2D节点的东西。

Once you have a 3D scene, there aren't really such things as 2D nodes, everything in the scene graph has an x, y and z co-ordinate; even things that were previously treated as 2D nodes when the depth buffer was set to false.

当您将一个框放在根边界窗格中时,该根边界窗格将假定3D坐标框。为了选择目的,您定义的框在从3D坐标-10到10的3D空间中表示,因此根边界窗格被定义为-10用于选择目的。您在根边界窗格中放置的边框窗格没有为它们定义z坐标,因此它们以0坐标的坐标结束,从观察者的角度来看,这是从根边界窗格的后面。

When you place a box in your root border pane, that root border pane assumes the 3D co-ordinates of the box. For picking purposes, the box you have defined is represented in 3D space from z co-ordinates -10 to 10, so the root border pane is defined as -10 for picking purposes. The border panes that you place inside the root border pane have no z co-ordinate defined for them, so they end up at a z co-ordinate of 0, which, from the viewers perspective is behind the root border pane.

所以,根边框窗格正在接收点击,但是由于它现在位于与其余内容不同的z平面上,所以您定义的其他二维正方形内容不接收点击。人们可以认为,根边界窗格根本没有渲染,因为它没有颜色,所以它应该被视为透明的,点击只是通过子节点,但似乎这不是3D采摘算法JavaFX可以工作。

So, the root border pane is receiving clicks, but because it is now on a different z plane than the rest of its contents, the other 2D square contents you have defined do not receive clicks. One could argue that the root border pane is not rendered at all as it has no color, so it should be treated as transparent and the clicks just go through to the child nodes, but it seems that is just not how the 3D picking algorithm for JavaFX works.

为了让你的例子,让所有的东西都在同一个Z平面上,并且pick选择正常,在你的for循环中添加以下行: pane.setTranslateZ(-10);

For your example, to get everything in the same Z plane and picking working correctly, add the following line inside your for loop: pane.setTranslateZ(-10);.

注意:我通过将以下代码添加到您的源代码中(这向我报告了鼠标点击的目标以及x,y,z pick result co - 每个点击) -

Note: I debugged this by adding the following line to your source code (which reported to me the target of the mouse clicks and the x,y,z pick result co-ordinate for each click):

root.setOnMouseClicked(System.out::println);

我的建议是避免使用专为2D目的设计的布局窗格(例如边框)来尝试在3D空间中布置元素。 JavaFX布局窗格实际上仅用于2D布局。要处理3D空间中的定位,您应该通过使用组而不是派生自任务来管理自己的坐标。至少不要尝试将3D元素添加到2D布局窗格中,因为结果可能会令人困惑(如您所发现的那样)。

My advice is to avoid using layout panes that are designed for 2D purposes (e.g. border panes) to attempt laying out elements in 3D space. The JavaFX layout panes are really only meant for 2D layout. To handle positioning in 3D space you should manage co-ordinates yourself, by just using Groups rather than anything that derives from Pane. At the very least don't try adding 3D elements into 2D layout panes as the results can be confusing (as you have discovered).

您可以进一步分离2D和3D将它们放在不同的子场景中(这就是子场景的意图 JavaFX的概念是我认为)。以下答案中显示了具有多个子场景的应用程序的示例:如何在JavaFX 8中创建自定义3D模型?

You can further separate 2D and 3D items by placing them in different sub scenes (that is really what the 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?

这篇关于如何在3D场景中选择2D节点?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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