Skeletal animations in custom viewport

I’m writing some code that renders a spaceship to a png image. Make a new framebuffer, viewport, camera etc. and then use the code from ScreenShotAppState to save to file.
Everything seems to be pretty much working except skeletal animations. The parts of mesh which have bones attached to just simply dissappear.

An image for example:
Regular game:


Rendered to png:

See the turrets not being there? To be clear: I don’t need to run the actual animations, I just need to have all parts of the model rendered.

Class I use for rendering to png:

public class ShipToImageRenderer implements SceneProcessor{
    private ViewPort renderingViewport;
    private FrameBuffer fbuff;
    private RenderManager renderManager;
    private Camera renderCam;
    private DirectionalLight dl;

    //Exporting stuff
    private static final String outPath = "workShopRender.png";

    private ByteBuffer outBuff;
    private Renderer renderer;
    private boolean cheese = false;

    public ShipToImageRenderer(RenderManager renderManager) {
        this.renderManager = renderManager;
        renderCam = new Camera(1280, 720);
        renderCam.setLocation(new Vector3f(20, 20, 20));
        renderCam.lookAt(new Vector3f(0, 0, 0), Vector3f.UNIT_Y);
        Camera c = CPU.game.getCam();
        renderCam.setFrustum(c.getFrustumNear(), c.getFrustumFar(), c.getFrustumLeft(), c.getFrustumRight(), c.getFrustumTop(), c.getFrustumBottom());
        renderCam.setFrustumPerspective(45f, 16f/9f, 1f, 1000f);

        renderingViewport = renderManager.createPreView("imageRenderer", renderCam);
        renderingViewport.setClearFlags(true, true, true);
        renderingViewport.setBackgroundColor(ColorRGBA.LightGray);

        dl = new DirectionalLight(new Vector3f(-1, -1, -2));
        dl.setColor(ColorRGBA.White);

        DirectionalLightShadowRenderer dlsr = new DirectionalLightShadowRenderer(CPU.game.getAssetManager(), 1024, 2);
        dlsr.setLight(dl);
        renderingViewport.addProcessor(dlsr);
        renderingViewport.addProcessor(this);

        fbuff = new FrameBuffer(1280, 720, 1);
        fbuff.setDepthBuffer(Image.Format.Depth);
        fbuff.setColorBuffer(Image.Format.RGBA8);
        renderingViewport.setOutputFrameBuffer(fbuff);
    }

    public void renderShip(Ship shipToRender){
        Spatial ship = shipToRender.clone();
        ship.addLight(dl);
        ship.setLocalTranslation(shipToRender.size3f.x / 2, 0, 0);
        ship.setLocalRotation(new Quaternion().fromAngles(0, 0, 0));
        ship.updateGeometricState();
        renderingViewport.attachScene(ship);
        cheese = true;
    }

    @Override
    public void initialize(RenderManager renderManager, ViewPort viewPort) {
        this.renderManager = renderManager;
        renderer = renderManager.getRenderer();
        reshape(viewPort, viewPort.getCamera().getWidth(), viewPort.getCamera().getHeight());
    }

    @Override
    public void reshape(ViewPort viewPort, int w, int h) {
        outBuff = BufferUtils.createByteBuffer(w * h * 4);
        System.out.println("Width " + w + " Height: " + h);
    }

    @Override
    public boolean isInitialized() {
        return renderer != null;
    }

    @Override
    public void preFrame(float v) {
        if (!renderingViewport.getScenes().isEmpty())
            renderingViewport.getScenes().get(0).updateGeometricState();
    }

    @Override
    public void postQueue(RenderQueue renderQueue) {

    }

    @Override
    public void postFrame(FrameBuffer out) {
        if (cheese){
            cheese = false;

            Camera ccam = renderManager.getCurrentCamera();
            int viewX = (int) (ccam.getViewPortLeft() * ccam.getWidth());
            int viewY = (int) (ccam.getViewPortBottom() * ccam.getHeight());
            int viewWidth = (int) ((ccam.getViewPortRight() - ccam.getViewPortLeft()) * ccam.getWidth());
            int viewHeight = (int) ((ccam.getViewPortTop() - ccam.getViewPortBottom()) * ccam.getHeight());

            //Read the data into outbuff
            renderer.setViewPort(0, 0, 1280, 720);
            renderer.readFrameBuffer(out, outBuff);
            renderer.setViewPort(viewX, viewY, viewWidth, viewHeight);

            //Save
            File outFile = new File(outPath);
            outFile.delete();
            try (FileOutputStream fout = new FileOutputStream(outFile)){
                JmeSystem.writeImageFile(fout, "png", outBuff, 1280, 720);
            } catch (IOException e) {
                System.err.println("Problem rendering ship to image:");
                e.printStackTrace();
            }
            renderingViewport.clearScenes();
        }
    }

    @Override
    public void cleanup() {

    }

Help?

1 Like

You might try slipping in an updateLogicalState() in there too… I think that might be needed for the animations to sync up properly.

I changed that method to this:

public void renderShip(Ship shipToRender){
    Spatial ship = shipToRender.clone();
    while (ship.getNumControls() > 0){
        ship.removeControl(ship.getControl(0));
    }
    ship.addLight(dl);
    ship.setLocalTranslation(shipToRender.size3f.x / 2, 0, 0);
    ship.setLocalRotation(new Quaternion().fromAngles(0, 0, 0));
    ship.updateGeometricState();
    ship.updateLogicalState(0);
    renderingViewport.attachScene(ship);
    cheese = true;
}

The control removal has to be done because otherwise the controls mess up the set rotation/translation.

Now I get this result:


The animated parts do appear, but the fan blades (same happens with the turrets) are rotated for 90° for some reason. Any ideas?

Bump

Try something > 0

edit: Though you are removing controls so maybe not. I’d try changing it to 1 without removing controls, see what happens.

No effect at all. The result is same as with removing controls and passing 0.

I do this in one of my projects.

Just to check, are you doing both updateLogicalState and geometric state in preFrame (not just renderShip) ?

As far as I can see, the only difference between this and mine is that I do the 2 updates in simpleUpdate (Yeah I’m on 3.0, another big difference) and also I create a new “rootNode”, and attach those items with skeletons to that node. Minor difference but I thought it worth mentioning.

I only update geometric state in pre frame. I’ll try with updating logical state there as well.