Hello,
I’m trying to figure out the right way to attach/detach child geometries from an InstancedNode. Essentially the goal is to have different geometries appear or disappear from the InstancedNode based on distance to the camera. I don’t want to use LOD because these geometries need to either appear or disappear, not change mesh complexity.
At the moment, the geometries appear briefly then disappear completely. I probably have the wrong mental model for how to use InstancedNode, so any nudges gratefully received.
SSCE:
import com.jme3.app.SimpleApplication;
import com.jme3.light.AmbientLight;
import com.jme3.light.PointLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.instancing.InstancedNode;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
// Based on distance from camera, swap in/out more/less detailed geometry to/from an InstancedNode.
public class TestInstancedNodeAttachDetach extends SimpleApplication {
public static void main(String[] args) {
TestInstancedNodeAttachDetach app = new TestInstancedNodeAttachDetach();
app.setShowSettings(false); // disable the initial settings dialog window
app.start();
}
private InstancedNode instancedNode;
private Vector3f[] locations = new Vector3f[10];
private Geometry[] spheres = new Geometry[10];
private Geometry[] boxes = new Geometry[10];
@Override
public void simpleInitApp() {
addPointLight();
addAmbientLight();
Material material = createInstancedLightingMaterial();
instancedNode = new InstancedNode("theParentInstancedNode");
rootNode.attachChild(instancedNode);
// create 10 spheres & boxes, positioned along Z-axis successively further from the camera
for (int i = 0; i < 10; i++) {
Vector3f location = new Vector3f(0, -3, -(i*5));
locations[i] = location;
Geometry sphere = new Geometry("sphere", new Sphere(16, 16, 1f));
sphere.setMaterial(material);
sphere.setLocalTranslation(location);
instancedNode.attachChild(sphere); // initially just add the spheres to the InstancedNode
spheres[i] = sphere;
Geometry box = new Geometry("box", new Box(0.7f, 0.7f, 0.7f));
box.setMaterial(material);
box.setLocalTranslation(location);
boxes[i] = box;
}
instancedNode.instance();
flyCam.setMoveSpeed(30);
}
@Override
public void simpleUpdate(float tpf) {
// Each frame, determine the distance to each sphere/box from the camera.
// If the object is > 25 units away, switch in the Box. If it's nearer, switch in the Sphere.
// Normally we wouldn't do this every frame, only when player has moved a sufficient distance, etc.
instancedNode.detachAllChildren();
for (int i = 0; i < 10; i++) {
Vector3f location = locations[i];
float distance = location.distance(cam.getLocation());
if( distance > 25.0f ) {
instancedNode.attachChild(boxes[i]);
} else {
instancedNode.attachChild(spheres[i]);
}
}
instancedNode.instance();
}
private Material createInstancedLightingMaterial() {
Material material = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
material.setBoolean("UseMaterialColors", true);
material.setBoolean("UseInstancing", true);
material.setColor("Ambient", ColorRGBA.Red);
material.setColor("Diffuse", ColorRGBA.Red);
material.setColor("Specular", ColorRGBA.Red);
material.setFloat("Shininess", 1.0f);
return material;
}
private void addAmbientLight() {
AmbientLight ambientLight = new AmbientLight(new ColorRGBA(0.2f, 0.2f, 0.2f, 1.0f));
rootNode.addLight(ambientLight);
}
private void addPointLight() {
PointLight pointLight = new PointLight();
pointLight.setColor(ColorRGBA.White);
pointLight.setRadius(100f);
pointLight.setPosition(new Vector3f(10f, 10f, 0));
rootNode.addLight(pointLight);
}
}
From adding a breakpoint and debugging the InstancedNode, I can see that it has the children that I expect, but it doesn’t seem to clear or rebuild it’s instancesMap - maybe this is related?
If anyone could help shine a light on my misunderstandings that would be excellent.
Thanks,
Duncan.