JavaFX 中的 JOGL canvas

JOGL canvas in JavaFX

我在 JavaFX 场景中获取 JOGL canvas/panel 时遇到问题。我的假设是,如果 JOGL GLCanvas 遵守 awt.Canvas 的合同,将其放置在 JFX 场景中应该没有问题。

我整理了以下代码(所有片段都在 JFX Application::start 中)。

首次创建 JOGL "hello world"(脉动背景只是为了查看事物是否渲染和移动):

GLCanvas glCanvas = new GLCanvas();
glCanvas.setSize(size-10, size-10);
glCanvas.addGLEventListener(new GLEventListener() {
    private final long t0 = System.currentTimeMillis();
    @Override
    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {}
    @Override
    public void init(GLAutoDrawable drawable) {
        new Thread(() -> {while (true) glCanvas.display();}).start();
    }
    @Override
    public void dispose(GLAutoDrawable drawable) {}
    @Override
    public void display(GLAutoDrawable drawable) {
        GL4 gl = drawable.getGL().getGL4();
        float t = (float)(Math.sin((System.currentTimeMillis()-t0)/1000f)+1)/2f;
        gl.glClearColor(t, 1-t, 0, 1);
        gl.glClear(GL4.GL_COLOR_BUFFER_BIT);
    }
});

GLJPanel glPanel = new GLJPanel();
glPanel.add(glCanvas);
glPanel.setBackground(Color.BLUE);

另一种你好世界(不动,这显然有效):

Canvas awtCanvas = new Canvas() {
    @Override
    public void paint(Graphics g) {g.fillRect(0, 0, getWidth(), getHeight());}
};
awtCanvas.setSize(size-10, size-10);

JPanel swingPanel = new JPanel();
swingPanel.add(awtCanvas);
swingPanel.setBackground(Color.BLUE);

并将测试代码放在一起:

if (jfx) {
    SwingNode swingNode = new SwingNode();
    swingNode.setContent(swingPanel);
    primaryStage.setScene(new Scene(new Group(swingNode), size, size+30));
    primaryStage.show();
} else {
    JFrame frame = new JFrame();
    frame.setSize(size, size+30);
    frame.add(swingPanel);
    frame.setVisible(true);
}

参考方案JFrame(Panel(Canvas())),JFrame(JPanel(GLCanvas())) JFrame(GLJPanel(GLCanvas())) 按预期工作(有点,GLPanel 似乎忽略背景颜色设置)。

当我尝试非 JOGL 包装器时 Stage(Scene(Group(JPanel(Canvas()))),按预期工作(JFX 工作)。

现在对于 JOGL,包装器 Stage(Scene(Group(JPanel(GLJPanel(GLCanvas())))) 在 canvas 处产生黑色内容应该是.Wrapper Stage(Scene(Group(JPanel(GLCanvas())))(跳过使用 GLJPanel)不会为 [=52= 生成黑色方块] 内容,我只得到 JPanel 的蓝色方块。

我在互联网上发现的唯一提及是从 2012/2013 开始的,它似乎不起作用(但当时 SwingNode 似乎也不存在),以及 2016 年在 JOGL 论坛上 link s to dead link in bugzzila.

出于绝望尝试使用 GLJPanel 而不是 GLCanvas,它起作用了。有点。

SwingNode 调整大小存在问题 - 它有一个错误,不允许轻松调整大小(OracleJDK has the bug for quite some time, OpenJDK 似乎已解决)

针对调整大小问题的建议解决方案是在场景中放置 width/height 属性 侦听器,并在每次大小更改时重新插入 canvas:

Dimension dim = new Dimension((int)scene.getWidth(), (int)scene.getHeight());
ChangeListener<Number> stageSizeListener = (obs, prev, next) -> {
    dim.setSize(scene.getWidth(), scene.getHeight());
    component.setSize(dim);
    swingNode.setContent(swingPanel);
};
scene.heightProperty().addListener(stageSizeListener);
scene.widthProperty().addListener(stageSizeListener);

这适用于问题中的代码,但每次重新插入都会触发 dispose(GL)init(GL) 循环,这可能是对于某些应用程序来说还可以,但我的情况不行。

决定做一些小改动,使 GLJPanel 的大小达到某个最大允许分辨率(比如 4K,无论如何我首先渲染到屏幕外缓冲区),以所需的分辨率渲染,将结果 blitting 到左上角面板,并将 JFX 场景中的面板裁剪到完全相同的分辨率。

tomsontom所述,性能不是很好,GLJPanelGLCanvas[=32慢得多=] 本身(在 4K 时从 800FPS 到 40FPS),当在 SwingNode 时它变得更糟(在 4K 时为 17FPS)。将尽可能推迟 JFX 的使用,并希望他们在即将与 JDK 分离时修复 SwingNode,甚至获得 DirectRenderingNode[=32] =].