JavaFX三维子场景中的二维场景。

问题描述 投票:1回答:1

我正在为一个游戏开发GUI,我想在JavaFX中混合一个3D SubScene和一个2D Pane。我有一个名为root3D的组,其中包含了我所有已经正确设置的3D对象,然后我使用通过JavaFX场景生成器设置的FXML文件创建一个Pane。但是没有任何显示,我只能看到我的3D对象。

       PerspectiveCamera camera = new PerspectiveCamera(true);
       camera.setTranslateZ(-30);
       Group root3D = new Group(model1,model2,model3); //various 3d models I imported
       SubScene subScene = new SubScene(root3D, 1280, 700, true,SceneAntialiasing.BALANCED);
       subScene.setCamera(camera);
       FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/file.fxml"));
       AnchorPane pane = loader.load();
       pane.getChildren().add(subScene);
       Scene scene = new Scene(pane);
       primaryStage.setScene(scene);
       primaryStage.setResizable(false);
       primaryStage.show();

FXML文件。

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.TextField?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.text.Font?>

<AnchorPane prefHeight="700.0" prefWidth="1200.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <StackPane prefHeight="150.0" prefWidth="200.0">
         <children>
            <ImageView fitHeight="214.0" fitWidth="169.0" pickOnBounds="true" preserveRatio="true">
               <image>
                  <Image url="@../Sprite/Cards/Small/podium-characters-Poseidon.png" />
               </image>
            </ImageView>
            <TextField prefHeight="62.0" prefWidth="274.0" text="APOLLO">
               <font>
                  <Font name="Trebuchet MS Bold Italic" size="22.0" />
               </font>
            </TextField>
         </children>
      </StackPane>
   </children>
</AnchorPane>

No sign of the FXML Layout

EDIT:我发现调整子场景的大小,我可以看到FXML元素。显然,它们被子场景 "覆盖 "了。有谁知道如何将FXML元素放置在子场景之上,而不是像现在这样相反?The Subscene covers the FXML Layout I created

java javafx scenebuilder java-2d java-3d
1个回答
3
投票

虽然你已经找到了解决方法,但我还是贴出了一个答案,希望能让事情更清楚一些,关于... 何以 呼叫 toBack() 在你 SubScene 作品。

Z-Order

每个 Parent的所有布局都可以有一个或多个子代。如果两个(或更多)子代占据同一空间,在 Parent 那么一个将呈现在另一个上面。哪个子代被画在另一个子代之上是由两件事决定的。

  1. 子代的顺序 Parent's 子女名单.
  2. (从JavaFX 9开始)每个子代的值是 viewOrder 属性,相对于同类型的其他子代而言。Parent.

JavaFX中的Z-Order Q&A将详细介绍。

代码中的问题

您的FXML文件描述了一个 AnchorPane 其具有 StackPane 作为其独生子女。这意味着,下面的内容。

AnchorPane pane = loader.load();

给你一个 AnchorPane 带着 StackPane 的子代列表中,在第零个索引处。然后你立即添加你的 SubScene 使用。

pane.getChildren().add(subScene);

The add 你使用的方法 附加 元素到列表的最后。所以这意味着 AnchorPane的子代列表的顺序是。

  1. StackPane
  2. SubScene

因为 SubScene 之后 StackPane 前者是呈现在后者之上的。

您的解决方案

您选择的解决方案是调用 toBack() 在你 SubScene 掺入 AnchorPane. 这里是 文件 的方法。

移动这个 Node 到它的兄弟节点的后面,按z-顺序排列。这是通过移动这个 Node 到其父内容的第一个位置 ObservableList. 如果此功能在以下情况下没有效果 Node 不属于一个组。

换句话说,当你调用该方法后,你的 AnchorPane的子代列表的顺序变成。

  1. SubScene
  2. StackPane

这就是为什么 SubScene 现在呈现在下面的 StackPane因为你改变了孩子们的顺序。

请注意 toBack() 方法的一部分。Node 阶级,不 SubScene. 后者继承了前者。我提出这个问题是为了指出,你所遇到的问题并不是特定的。SubScene 甚至将2D和3D场景图混合在一起。您的 StackPane 和你 SubScene 属于二维 Scene (即没有深度缓冲),这意味着它们的z-order只受上面讨论的内容的制约。*. 事实是: SubScene 是3D的(即深度缓冲启用)与当前的问题无关;这一事实只影响到以下方面 后人SubScene.

* 在3D场景中,节点的Z坐标变得相关。

其他解决方案

下面是一些其他的方法,可以用来解决你的问题。

  • 添加 SubScene 至始至终 AnchorPane的子代列表。

    pane.getChildren().add(0, subScene);
    
  • 如果你使用的是JavaFX 9+,请设置 viewOrder 的财产 SubScene 的东西。AnchorPane的属性(默认情况下,该属性的值是 0):

    subScene.setViewOrder(-1);
    
  • 定义你的 SubScene 前的FXML文件中的 StackPane (注意这种方法需要使用 控件):

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import javafx.scene.control.TextField?>
    <?import javafx.scene.Group?>
    <?import javafx.scene.image.Image?>
    <?import javafx.scene.image.ImageView?>
    <?import javafx.scene.layout.AnchorPane?>
    <?import javafx.scene.layout.StackPane?>
    <?import javafx.scene.SceneAntialiasing?>
    <?import javafx.scene.SubScene?>
    <?import javafx.scene.text.Font?>
    
    <AnchorPane prefHeight="700.0" prefWidth="1200.0" xmlns="http://javafx.com/javafx/11.0.1"
                xmlns:fx="http://javafx.com/fxml/1">
      <children>
    
        <!-- Define the SubScene before the StackPane -->
        <SubScene fx:id="subScene" width="1280" height="700" depthBuffer="true">
          <antiAliasing>
            <SceneAntialiasing fx:constant="BALANCED"/>
          </antiAliasing>
    
          <!-- 
            Unfortunately, as far as I can tell, you can't set your PerspectiveCamera in FXML because you
            want 'fixedEyeAtCameraZero' to be true. That property can only be set during construction but
            the constructor with that parameter does not annotate said parameter with @NamedArg, thus the
            FXMLLoader can't see it. And the no-arg constructor sets the value to false, not true. This
            means you have to inject the SubScene into your controller and add the PerspectiveCamera in
            code.
           -->
    
          <root>
            <!-- Inject the root into the controller in order to add your models to it in code -->
            <Group fx:id="root3D"/>
          </root>
        </SubScene>
    
        <StackPane prefHeight="150.0" prefWidth="200.0">
          <children>
            <ImageView fitHeight="214.0" fitWidth="169.0" pickOnBounds="true" preserveRatio="true">
              <image>
                <Image url="@../Sprite/Cards/Small/podium-characters-Poseidon.png"/>
              </image>
            </ImageView>
            <TextField prefHeight="62.0" prefWidth="274.0" text="APOLLO">
              <font>
                <Font name="Trebuchet MS Bold Italic" size="22.0"/>
              </font>
            </TextField>
          </children>
        </StackPane>
    
      </children>
    </AnchorPane>
    

2
投票

正如@Slaw间接指出的那样 我需要的是设置Subscene.toBack() 在我的场景中设置一个正确的Z-order. 非常感谢您 在阅读Subscenes的时候,我没有发现任何关于它的内容,所以我希望这可以帮助将来有问题的2D和3D混合的人!final result

© www.soinside.com 2019 - 2024. All rights reserved.