【问题标题】:How to embed a Canvas3D in a JavaFX application?如何在 JavaFX 应用程序中嵌入 Canvas3D?
【发布时间】:2018-01-24 13:13:31
【问题描述】:

我正在开发一个 JavaFX 桌面应用程序。我想在其中显示一些 java 3D 对象。

据我所知,这样做的方法是使用 JavaFX 的 SwingNode。 Java 3d 也必须集成到 Swing 组件中。所以这是一个两步的过程。

将 Java 3D 对象与 Java Swing 集成

由我打算在 FX 应用程序中重用的面板和一个显示它有效的 JFrame 组成的完整且最小的示例:

import java.awt.BorderLayout;

import javax.swing.JFrame;

public class JFrameWithCanvas3D extends JFrame {
   public JFrameWithCanvas3D() {
      super("Swing JFrame Wraps Canvas3D");
      setLayout(new BorderLayout());

      BallPanel panel = new BallPanel();
      add(panel, BorderLayout.CENTER);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      pack();
      setVisible(true);
   }

   public static void main(String[] args) {
      System.setProperty("sun.awt.noerasebackground", "true");
      javax.swing.SwingUtilities.invokeLater(new Runnable() {
         @SuppressWarnings("unused")
         @Override
         public void run() {
            new JFrameWithCanvas3D();
         }
      });
   }  
}

public class BallPanel extends JPanel {

   public BallPanel() {
      setLayout(new BorderLayout());
      setPreferredSize(new Dimension(500, 500));
      add(makeCanvas());

   }

   private static Canvas3D makeCanvas() {
      BranchGroup group = new BranchGroup();
      group.addChild(makeLight());
      group.addChild(new Sphere(5));

      Canvas3D canvas3D = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
      SimpleUniverse universe = new SimpleUniverse(canvas3D);
      Transform3D viewTransform = new Transform3D();
      viewTransform.setTranslation(new Vector3d(0, 0, 20)); //move "back" a little
      universe.getViewingPlatform().getViewPlatformTransform().setTransform(viewTransform);
      universe.addBranchGraph(group);
      return canvas3D;
   }

   private static DirectionalLight makeLight() {
      DirectionalLight light = new DirectionalLight(new Color3f(Color.WHITE), new Vector3f(-1.0f, -1.0f, -1.0f));
      light.setInfluencingBounds(new BoundingSphere(new Point3d(0, 0, 0), 100));
      return light;
   }

}

在 JavaFX 应用中集成 BallPanel

public class FXAppWithSwingPanel extends Application {
   @Override
   public void start(Stage stage) {
       final SwingNode swingNode = new SwingNode();

       JPanel panel = new JPanel();       
       panel.setLayout(new BorderLayout());
       panel.setPreferredSize(new Dimension(450, 450));
       panel.add(new BallPanel(), BorderLayout.CENTER);
       swingNode.setContent(panel);

       Pane pane = new Pane();
       pane.getChildren().add(swingNode);

       stage.setScene(new Scene(pane, 500, 500));
       stage.show();
   }

   public static void main(String[] args) {
       launch(args);
   }

}

我看到的只是球体应该在的灰色背景。我尝试了一些不同的变化,但没有运气。无法在网上找到有关 Java 3D 类和 JavaFX 之间这种特定集成的任何信息。

我知道 JavaFX 有 3D 图形,但我不喜欢它们(一点也不)。

相关的,未解决的,问题:

How Can I embed java3d's Canvas3d in javafx layout?

【问题讨论】:

  • 我不知道 Java-3D。 Canvas3D 是轻量级组件(即由 Swing 呈现的组件,而不是由本机窗口工具包呈现的组件)?如果没有,您将无法在SwingNode 中呈现它。另请注意,您应该通过SwingUtilities.invokeLater(...) 在AWT 事件调度线程上为SwingNode 创建内容:请参阅SwingNode docs
  • 啊,原来如此。显然 Canvas3D 是一个重量级的 GUI 元素。有什么解决方法吗?
  • 我不这么认为。 SwingNode 旨在与“纯摇摆”组件(即轻量级组件)向后兼容,但 JavaFX 通常是从头开始设计的。如果您使用 JavaFX,您可能必须使用 JavaFX 3D。如果您想走 JavaFX 路线,José Pereda(有时会在这里发帖)可能是寻找好的 JavaFX 3d 文章的人。
  • 我会推迟一段时间,因为我一般不是 3D 专家;如果以后没有人有更好的建议,我将在答案中总结这些 cmets。
  • 你试过com.sun.j3d.exp.swing.JCanvas3D吗? jogamp.org/deployment/java3d/1.6.0-final/javadoc/com/sun/j3d/… OpenJFX/JavaFX 通常不能与第三方 3D API 很好地互操作,我在这里解释了原因:jogamp.org/bugzilla/show_bug.cgi?id=607

标签: java swing javafx javafx-8 java-3d


【解决方案1】:

我终于设法使用 JCanvas3D 使它工作。建议归功于@gouessej。非常感谢。

这是新的makeCanvas 方法:

   private void makeCanvas() {
      GraphicsConfigTemplate3D gCT = new GraphicsConfigTemplate3D();
      JCanvas3D jCanvas3D = new JCanvas3D(gCT);
      Dimension canvasDim = new Dimension(400, 400);
      jCanvas3D.setPreferredSize(canvasDim);
      jCanvas3D.setSize(canvasDim);
      add(jCanvas3D, BorderLayout.CENTER);          
      Canvas3D canvas3D =  jCanvas3D.getOffscreenCanvas3D(); 

      View view = new View();
      view.setPhysicalBody(new PhysicalBody());
      view.setPhysicalEnvironment(new PhysicalEnvironment());
      view.addCanvas3D(canvas3D);

      ViewPlatform vp = new ViewPlatform();
      view.attachViewPlatform(vp);


      Transform3D viewTransform = new Transform3D();
      viewTransform.setTranslation(new Vector3d(0, 0, 20)); //move "back" a little

      TransformGroup viewTG = new TransformGroup();
      viewTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
      viewTG.setTransform(viewTransform);

      viewTG.addChild(vp);


      viewTG.addChild(makeLight());
      viewTG.addChild(new Sphere(5));

      BranchGroup group = new BranchGroup();
      group.addChild(viewTG);
      group.addChild(makeLight());
      group.addChild(new Sphere(5));

      VirtualUniverse vu = new VirtualUniverse();
      Locale locale = new Locale(vu);  
      locale.addBranchGraph(group);
   }

此外,正如 James_D 在 cmets 中指出的那样,Canvas3D 不是要走的路,因为它无法在 JavaFX SwingNode 中正确呈现,因为它是重量级组件。

SwingNode javadoc 确认:

JComponent 实例中包含的组件的层次结构 不应包含任何重量级组件,否则 SwingNode 可能 画不出来。

【讨论】:

    【解决方案2】:

    如果这两个句子“我正在开发一个 JavaFX 桌面应用程序。我想在其中显示一些 Java 3D 对象。”真的是你在这里问的本质,那么你完全走错了路。 JavaFX 原生支持 3D 形状,因此除非您有非常特殊的要求,否则不需要任何 Canvas3D 和嵌入任何 Swing。

    我刚刚看到您说您知道 JavaFX 3D 图形,但您不喜欢它。不喜欢的东西能不能具体一点?

    【讨论】:

    • 当然: 1. 默认情况下看起来很丑,没有很多调整 2. javafx 3d api 缺少可以在 j3d 中找到的高级函数(这可能是错误的,这是我的印象,当我试图做旋转和诸如此类的事情) 3. 我不喜欢 api,太复杂 4. 对我的应用程序非常特殊的东西与两侧表面有关,其中重复的表面集将无法正确显示。这一定是 javafx 缺陷。在这个有限的篇幅里我无法正确解释。这是交易破坏者。
    猜你喜欢
    • 2014-03-04
    • 2015-03-13
    • 2011-01-24
    • 2013-05-29
    • 1970-01-01
    • 2012-12-24
    • 2018-11-30
    • 2011-03-30
    • 2011-01-19
    相关资源
    最近更新 更多