InstancedNode noob questions

I am about to switch from an AssetLinkNode to InstancedNode and I have a few questions first:

  1. Do I have to check for opengl3.0 compatability in order to use the InstancedNode?
  2. Will my code blow up if the video card is only opengl2.0 compatible?
  3. Do I just create and instance of InstanedNode and create new Geometries with the same mesh instance on each and I will be able to set any material to each Geometry and pick up the speed increase?
  4. Can an instance of InstancedNode contain several copied of say, two or more difrent meshes and still give me the speed increase I am looking for?
    1. Yes, you can do it like this:
if (renderer.getCaps().contains(Caps.MeshInstancing)) {
    // Use instancing
} else {
    // Fallback
}

We avoided adding instancing for a long time because its a feature that requires hardware support beyond OpenGL 2.
Note that you can still use InstancedNode, but you just have to avoid calling the .instance() method if its not supported.

  1. Yes the mesh instances have to be the same for instancing to work. Material instances also have to be the same for objects to be instanced together. This doesn’t mean instancing will break or anything, just that you won’t see any performance improvement if all objects are completely different.

  2. No, you cannot use mesh copies, the instances have to be the same.

1 Like

Thank you very much for the information. This has answered all of my questions.

Hi

I tried instancing but performance decreased instead of increasing!
I do not know where I am wrong.
Here is two screenshots :
1-Instancing Disabled

2- Instancing Enabled

and here is my code :

package mygame;
import com.jme3.app.BasicProfilerState;
import com.jme3.app.SimpleApplication;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Caps;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.SceneGraphVisitor;
import com.jme3.scene.Spatial;
import com.jme3.scene.instancing.InstancedNode;
import com.jme3.shader.VarType;


public class Main extends SimpleApplication {

    public static void main(String[] args) {

        Main app = new Main();
        app.start();
    }

    @Override
    public void simpleInitApp() {
        stateManager.attach(new BasicProfilerState(true));

        flyCam.setEnabled(true);
        flyCam.setMoveSpeed(10);
        boolean INSTANCING = false;

        Node instancedNodeJungle = new InstancedNode("Jungle");
        rootNode.attachChild(instancedNodeJungle);
        Spatial jungle = assetManager.loadModel("Scenes/JungleLinkedObjects.j3o");

        instancedNodeJungle.attachChild(jungle);

        DirectionalLight sun = new DirectionalLight();
        sun.setDirection((new Vector3f(-0.5f, -0.5f, -0.5f)).normalizeLocal());
        sun.setColor((ColorRGBA.White));
        rootNode.addLight(sun);
        if (renderer.getCaps().contains(Caps.MeshInstancing)) {
            // Use instancing
            if (INSTANCING) {
                enableMaterialInstancing(jungle);
                ((InstancedNode) instancedNodeJungle).instance();
            }

        } else {
            // Fallback
        }

    }

    @Override
    public void simpleUpdate(float tpf) {

    }

    @Override
    public void simpleRender(RenderManager rm) {
        //TODO: add render code
    }

    private void enableMaterialInstancing(Spatial jungle) {
        // Material MAT = new Material(assetManager, "Common/MatDefs/Lighy/Lighting.j3md");
        SceneGraphVisitor v = new SceneGraphVisitor() {

            @Override
            public void visit(Spatial spatial) {

                if (spatial instanceof Geometry) {
                    Material mat = ((Geometry) spatial).getMaterial();
                    mat.getMaterialDef().addMaterialParam(VarType.Boolean, "UseInstancing", true);
                    mat.setBoolean("UseInstancing", true);
                }
            }
        };

        jungle.depthFirstTraversal(v);

    }

}
1 Like

Funny how you turned off stats in the second picture so that we can’t see if the object count improved at all…

I did not turn it off .
((InstancedNode) instancedNodeJungle).instance(); makes them turned off.

So, that’s the only difference between the first and last picture?

That’s a pretty huge bug, then.

Yes only difference.
but let me show this :

this is TestInstanceNode in jme3test.scene.instancing;
Here instancing is on and stats works OK.

Here is my scene hierarchy :

JungleLinkedObjects :

BambooTrees :

bambooGrove : this is one of those 3 tree models in my scene

I converted them from blender to .j3o . and when calling this method :
((InstancedNode) instancedNodeJungle).instance();
I got this error :

SEVERE: Uncaught exception thrown in Thread[jME3 Main,5,main]
java.lang.IllegalStateException: You must set the 'UseInstancing' parameter to true on the material prior to adding it to InstancedNode
    at com.jme3.scene.instancing.InstancedNode.addToInstancedGeometry(InstancedNode.java:199)
    at com.jme3.scene.instancing.InstancedNode.instance(InstancedNode.java:261)
    at com.jme3.scene.instancing.InstancedNode.instance(InstancedNode.java:268)
    at com.jme3.scene.instancing.InstancedNode.instance(InstancedNode.java:268)
    at com.jme3.scene.instancing.InstancedNode.instance(InstancedNode.java:268)
    at com.jme3.scene.instancing.InstancedNode.instance(InstancedNode.java:268)
    at com.jme3.scene.instancing.InstancedNode.instance(InstancedNode.java:268)
    at com.jme3.scene.instancing.InstancedNode.instance(InstancedNode.java:268)
    at com.jme3.scene.instancing.InstancedNode.instance(InstancedNode.java:268)
    at com.jme3.scene.instancing.InstancedNode.instance(InstancedNode.java:268)
    at com.jme3.scene.instancing.InstancedNode.instance(InstancedNode.java:268)
    at com.jme3.scene.instancing.InstancedNode.instance(InstancedNode.java:268)
    at com.jme3.scene.instancing.InstancedNode.instance(InstancedNode.java:274)
    at mygame.Main.simpleInitApp(Main.java:48)
    at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:227)
    at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:130)
    at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:211)
    at java.lang.Thread.run(Thread.java:745)

so I created this method to add “UseInstancing” parameter to all materials in scene :

private void enableMaterialInstancing(Spatial jungle) {
      
        SceneGraphVisitor v = new SceneGraphVisitor() {

            @Override
            public void visit(Spatial spatial) {

                if (spatial instanceof Geometry) {
                    Material mat = ((Geometry) spatial).getMaterial();
                    mat.getMaterialDef().addMaterialParam(VarType.Boolean, "UseInstancing", true);
                    mat.setBoolean("UseInstancing", true);
                }
            }
        };

        jungle.depthFirstTraversal(v);

    }

Thanks for any help.

2 Likes