Scene graph is not properly updated for rendering Error

Hi guys.

Recently I have been experiencing the following error:

SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.lang.IllegalStateException: Scene graph is not properly updated for rendering.
State was changed after rootNode.updateGeometricState() call.
Make sure you do not modify the scene from another thread!
Problem spatial name: Root Node
at com.jme3.scene.Spatial.checkCulling(Spatial.java:260)
at com.jme3.renderer.RenderManager.renderSubScene(RenderManager.java:647)
at com.jme3.renderer.RenderManager.renderScene(RenderManager.java:640)
at com.jme3.renderer.RenderManager.renderViewPort(RenderManager.java:974)
at com.jme3.renderer.RenderManager.render(RenderManager.java:1029)
at com.jme3.app.SimpleApplication.update(SimpleApplication.java:252)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:185)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:228)
at java.lang.Thread.run(Thread.java:744)

It does not happen all the time, and when it does happen, is only when I try to use my ā€œfly through featureā€. Hereā€™s the code for the fly through:

public void flyThrough(String fromLocation, final String toLocation, final boolean pathHighlight, boolean flyThrough) {

    PathFinder pf = new PathFinder(box.getXExtent(), box.getZExtent(), buildings);
    Vector3f fromVector;
    final Vector3f toVector = buildings.getBuildingJumpCoords(toLocation)[0];

    if (!(fromLocation.equals("Current"))) {
        jumpToLocation(fromLocation);
    }

    fromVector = player.getPhysicsLocation();

    pf.setPath(fromVector, toVector);

    ArrayList<Vector3f> vList = pf.getPath();
    //cam.lookAt(vList.get(1), Vector3f.UNIT_Y);

    if (pathHighlight) {
        setPathH(vList);
    }

    if (flyThrough) {
        path = new MotionPath();
        for (int i = 0; i < vList.size(); i++) {
            path.addWayPoint(vList.get(i));
        }

        //cam.setLocation(fromVector);
        cam.lookAt(path.getWayPoint(1), Vector3f.UNIT_Y);
        player.setPhysicsLocation(fromVector);

        camNode = new CameraNode("Motion cam", cam);

        camNode.setControlDir(ControlDirection.SpatialToCamera);
        camNode.setEnabled(false);
        path.setCurveTension(0.5f);

        cameraMotionControl = new MotionEvent(camNode, path);

        rootNode.attachChild(camNode);

        camNode.setEnabled(true);
        cameraMotionControl.setSpeed(10f);
        cameraMotionControl.setInitialDuration(path.getNbWayPoints() / 2);
        cameraMotionControl.setDirectionType(MotionEvent.Direction.Path);
        cameraMotionControl.play();


        path.addListener(new MotionPathListener() {
            public void onWayPointReach(MotionEvent control, int wayPointIndex) {
                if (path.getNbWayPoints() == wayPointIndex + 1) {
                    if (pathHighlight) {
                        removePathH();
                    }

                    cameraMotionControl.stop();
                    camNode.setEnabled(false);
                    player.setPhysicsLocation(toVector);
                    cam.lookAt(buildings.getBuildingJumpCoords(toLocation)[1], Vector3f.UNIT_Y);

                } else {
                    player.setPhysicsLocation(path.getWayPoint(wayPointIndex));
                }
            }
        });

    }

}[/java] 

This method is called via an outside Java Dialog class (user clicks button which send information to this method). The code for the button in the other class:

[java]flyBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
setVisible(false);
Robot robot = new Robot();
robot.mouseMove(cursorX, cursorY);
app.flyThrough(flyComboBoxF.getSelectedItem().toString(),
flyComboBoxT.getSelectedItem().toString(), pathH.isSelected(),
true);
} catch (AWTException ex) {
}
}
});[/java]

You are changing the scene from the AWT thread by doing what you do (as the error message says).

https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:multithreading

Any ideas for a quick solution? - normally I would take the time to explore, but I am currently at my project demo fair, and the problem has only just started occurring!

You do the same you would do with invokeLater() when you would call Swing from another thread basically. You enqueue a Callable to the application via application.enqueue().

The GUI is a dialog, that is instantiated at run time (once) and then the visibility is changed. Would I use invokeLater when instantiating the GUI for the first time? Iā€™ve never really used multi-threading so Iā€™m not 100% sure on how to use it.

How would I use callable to pass parameters to an actual method?

Thanks for all your help! Iā€™m in a dire situation right now :stuck_out_tongue:

Please just click that link, would you? You can basically copy-paste the code example at the very top, would have taken less time than this conversation already did.

I clicked the link, and have read through all the documentation. I just donā€™t understand how to apply that enqueue code to sending parameters to a method in the appā€¦

Got it working, with:

[java] app.enqueue(new Callable() {
public Object call() throws Exception {
app.flyThrough(flyComboBoxF.getSelectedItem().toString(),
flyComboBoxT.getSelectedItem().toString(), pathH.isSelected(),
true);

                        return null;
                              
                    }
                });[/java]

I also have this issue, and was really reluctant to start a thread because by searching Iā€™ve seen you answer it a thousand times normen.

I think I am misunderstanding something. I have created a second viewport, and attached a scene (invNode = new Node(), I attachScene this)

ā€œIf you make changes only in Control.update(), AppState.update(), or SimpleApplication.simpleUpdate(), this will happen automatically.ā€

In my ā€˜public void simpleUpdate(float ptf)ā€™ simple update loop, I update my inventory, which also happens to do:

invNode.attachChild(tempModel);

This one line causes the error the OP has, when I comment it out it is gone. I double checked it was occuring in the simpleUpdate loop as you suggested with
System.out.println( Thread.currentThread() ); getting Thread[LWJGL Renderer Thread,5,main] in both my simpleUpdate loop, and in the method this problem occurs right before the crash

I thought this would be ok to update my scene for my second viewport/camera in the update loop?

(I also added
invNode.updateLogicalState(1);
invNode.updateGeometricState();
these as that was suggested elsewere in the forum)

I know I can fix it with the link provided, just curious as to why it doesnā€™t work as is

If you have a complete seperate scenegraph in a different viewport, you need to do stuff like that yourself, yes, as jme does not even know about it. it only takes care for stuff in the rootnode of the application for you.

1 Like

Ah ok, thanks empire