Offscreen rendering corrupts after first render

70 Views Asked by At

I'm trying to render a series of static images from a 3D scene using Scijava's Java3D 1.6 and JOGL 2.4.0 on Java16. I've created some textured geometry, set up a SimpleUniverse with an off-screen Canvas3D and I then repeatedly render into an image buffer which I then dump out to file and swap out the geometry for the next render. This works great until I add a Background to the scene, at which point the first render looks fine but all subsequent renders look like the model's occlusion isn't being handled correctly and parts of the geometry that should be hidden behind other parts are instead on top.

  • This only happens when a Background is attached to the scene - multiple renders are fine with no background.
  • It is independent of the shapes being rendered - I can remove all the shapes and add completely different ones and the new shapes will still be rendered incorrectly.
  • I can also leave the scene entirely unchanged and simply call canvas.renderOffScreenBuffer / canvas.waitForOffScreenRendering twice and observe the corrupt result.
  • It does appear to be localised to the Universe/Canvas3D as I can instantiate additional copies of the entire object stack and they render fine on their first run too, so this is a viable workaround but I'd like to avoid re-creating the universe for every render.

Aside from the code for building the shapes, this is basically all of the rendering pipeline:

    public BufferedImage render(ImageComponent2D image, TransformGroup shapeTransform){
        BufferedImage bImage = new BufferedImage(TEMP_WIDTH, TEMP_HEIGHT, BufferedImage.TYPE_INT_ARGB);
        ImageComponent2D buffer = new ImageComponent2D(ImageComponent.FORMAT_RGBA, bImage);
        buffer.setCapability(ImageComponent2D.ALLOW_IMAGE_WRITE);
        buffer.setCapability(ImageComponent2D.ALLOW_IMAGE_READ);

        Canvas3D canvas = new Canvas3D(SimpleUniverse.getPreferredConfiguration(), true);
        canvas.setSize(HEIGHT * 4, WIDTH * 4);
        canvas.getScreen3D().setPhysicalScreenHeight(0.0254/90.0 * HEIGHT);
        canvas.getScreen3D().setPhysicalScreenWidth(0.0254/90.0 * WIDTH);
        canvas.getScreen3D().setSize(HEIGHT * 4, WIDTH * 4);
        canvas.setOffScreenBuffer(buffer);
        canvas.setBackground(new Color(0,0,0,0));

        SimpleUniverse universe = new SimpleUniverse(canvas);

        BranchGroup group = new BranchGroup();
        group.setCapability(BranchGroup.ALLOW_DETACH);

        BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);

        BranchGroup bgGroup = new BranchGroup();
        bgGroup.setCapability(BranchGroup.ALLOW_DETACH);
        Backgroundbackground = new Background();
        background.setImageScaleMode(Background.SCALE_FIT_MAX);
        background.setApplicationBounds(bounds);
        background.setCapability(Background.ALLOW_IMAGE_WRITE);
        background.setImage(image)
        bgGroup.addChild(background);
        
        PlatformGeometry pg = new PlatformGeometry();
        
        Color3f ambientColor = new Color3f(0.1f, 0.1f, 0.1f);
        AmbientLight ambientLightNode = new AmbientLight(ambientColor);
        ambientLightNode.setInfluencingBounds(bounds);
        pg.addChild(ambientLightNode);
        
        Color3f light1Color = new Color3f(1.0f, 1.0f, 0.9f);
        Vector3f light1Direction = new Vector3f(1.0f, 1.0f, 1.0f);
        Color3f light2Color = new Color3f(1.0f, 1.0f, 1.0f);
        Vector3f light2Direction = new Vector3f(-1.0f, -1.0f, -1.0f);
        
        DirectionalLight light1 = new DirectionalLight(light1Color, light1Direction);
        light1.setInfluencingBounds(bounds);
        pg.addChild(light1);
        
        DirectionalLight light2 = new DirectionalLight(light2Color,light2Direction);
        light2.setInfluencingBounds(bounds);
        pg.addChild(light2);
        
        universe.getViewingPlatform().setPlatformGeometry(pg);

        group.addChild(shapeTransform);
        universe.addBranchGraph(group);
        universe.addBranchGraph(bgGroup);

        canvas.renderOffScreenBuffer();
        canvas.waitForOffScreenRendering();
        return buffer.getImage();
    }

Can provide image samples of good/bad renders if required.

0

There are 0 best solutions below