Hi,
For some reason it seems to be quite slow to add TriMeshes to scene graph using attachChild. I have a simple square object (2 triangles). If I try to add about 100-200 square objects to a Node, it takes a couple of seconds. Should it be that slow?
With that said, can I somehow hide an existing Node in a scene graph to toggle if it is rendered or not rendered?
Thanks
When you look at the code, all that method would be doing is adding your object to an ArrayList.
The performance hit is most likely the 100-200 'new' objects you are creating to add to the list.
setCullHint( CullHint.Always );
and to show it again
setCullHint( CullHint.Dynamic );
Hi,
I have created two loops. First loop creates squares and second loop adds squares to scene graph. The first loop runs fast. The second loop which adds squares is slow. I noticed that JME writes a lot of messages to console when I run attachChilds (in second loop). Could writing a lot of messages make things slow? The messages seem to be informative messages, not errors.
paste your code
Hi,
After I see "Attaching tile instances" -message, it takes a long time until display is updated with all new tiles (squares).
What I am actually trying to do is that I have a terrain that consists of tiles and I am trying to paint an area which is selected using mouse. The selected area is shown by creating a square above for each selected terrain tile.
Here is the routine in question:
private void paintTiles(SparsePlane tileLocations) {
SparsePlaneIterator iter = new SparsePlaneIterator(tileLocations);
iter.begin();
Engine.field3D.clearTilePlates();
System.out.println("Creating Tile Instances");
Vector<TriMesh> v = new Vector<TriMesh>();
for (Location l; (l = iter.next()) != null;) {
TriMesh plane = Engine.instance.createPlane(new Location(l.x,l.y));
v.add(plane);
}
System.out.println("Attaching tile instances");
for (int i = 0; i < v.size(); i++) {
Field3D.instance.tilePlates.attachChild((TriMesh)v.get(i));
}
Engine.field3D.updateTilePlates();
}
Here is some related code:
public TriMesh createPlane(Location l) {
TriMesh m = new TriMesh("CP3D Plane");
Vector3f[] vertexes = {
new Vector3f(-0.5f, 0f, -0.5f),
new Vector3f(0.5f, 0f, -0.5f),
new Vector3f(-0.5f, 0, 0.5f),
new Vector3f(0.5f, 0, 0.5f)
};
Vector3f[] normals = {
new Vector3f(0, 1, 0),
new Vector3f(0, 1, 0),
new Vector3f(0, 1, 0),
new Vector3f(0, 1, 0)
};
ColorRGBA[] colors = {
new ColorRGBA(1f, 1f, 0f, 0.5f),
new ColorRGBA(1f, 1f, 0f, 0.5f),
new ColorRGBA(1f, 1f, 0f, 0.5f),
new ColorRGBA(1f, 1f, 0f, 0.5f)
};
Vector2f[] texCoords = {
new Vector2f(0, 0),
new Vector2f(1, 0),
new Vector2f(0, 1),
new Vector2f(1, 1)
};
int[] indexes = { 0, 2, 1, 1, 2, 3 };
m.reconstruct(BufferUtils.createFloatBuffer(vertexes),
BufferUtils.createFloatBuffer(normals),
BufferUtils.createFloatBuffer(colors),
TexCoords.makeNew(texCoords),
BufferUtils.createIntBuffer(indexes));
m.setLocalScale(blockSize);
m.setLocalTranslation(Field3D.gridPos(l.x, l.y));
m.setModelBound(new BoundingBox());
m.updateModelBound();
return m;
}
public Node tilePlates = new Node(); // this will be connected to rootNode
public void updateTilePlates() {
tilePlates.updateRenderState();
}
The first loop's time is marked by:
System.out.println("Creating Tile Instances");
try:
private void paintTiles(SparsePlane tileLocations) {
SparsePlaneIterator iter = new SparsePlaneIterator(tileLocations);
iter.begin();
Engine.field3D.clearTilePlates();
System.out.println("Creating Tile Instances");
Vector<TriMesh> v = new Vector<TriMesh>();
for (Location l; (l = iter.next()) != null;) {
TriMesh plane = Engine.instance.createPlane(new Location(l.x,l.y));
plane.updateGeometricState(0.0f, true); // <-
v.add(plane);
}
System.out.println("Attaching tile instances");
for (int i = 0; i < v.size(); i++) {
Field3D.instance.tilePlates.attachChild((TriMesh)v.get(i));
}
Engine.field3D.updateTilePlates();
}
Hi,
Unfortunately I did not notice any difference when I added: "plane.updateGeometricState(0.0f, true);"
I added also some debug messages and made a test run. What I can see is: STEP 1 and STEP 2 being printed. Then about 250 lines of text is printed on the console. It takes a couple seconds to all those lines being printed. Example of text lines that are printed:
12.5.2010 15:56:10 com.jme.scene.Node attachChild
INFO: Child "CP3D Plane" attached to this node "null"
After the text lines are printed I can see "STEP 3, done" and "STEP 4, done" and the same time, the squares are being updated/displayed on the screen.
How can I set logging level / disable logging?
System.out.println("STEP 1");
Vector<TriMesh> v = new Vector<TriMesh>();
for (Location l; (l = iter.next()) != null;) {
TriMesh plane = Engine.instance.createPlane(new Location(l.x,l.y));
plane.updateGeometricState(0.0f, true); // <-
v.add(plane);
}
System.out.println("STEP 2");
for (int i = 0; i < v.size(); i++) {
Field3D.instance.tilePlates.attachChild((TriMesh)v.get(i));
}
System.out.println("STEP 3, done");
Engine.field3D.updateTilePlates();
System.out.println("STEP 4, done");
{
// The root logger's handlers default to INFO change to ignore all bar SEVERE.
Handler[] handlers =
Logger.getLogger("").getHandlers();
for (int index = 0; index < handlers.length; index++)
{
handlers[index].setLevel(Level.SEVERE);
}
}
Hi,
I disabled the logging. It made things a little bit faster. Or at least to certain point.
Now comes the strange part. When I tested the application I noticed that it's memory consumption will increase fast as I create squares and does not decrease when squares are removed. Quite soon the application took over 2GB memory and the system begun swapping.
I continued testing and traced the problem to following call:
TriMesh plane = Engine.instance.createPlane(new Location(l.x,l.y));
Even if I don't store the resulting plane (TriMesh) anywhere or add it to schene graph, the memory usage will continue to grow with each call.
I am puzzled, how can createPlane leak memory?
* http://publib.boulder.ibm.com/infocenter/realtime/v2r0/index.jsp?topic=/com.ibm.softrt.doc/diag/appendixes/defaults.html
As far as i see, you add the plane to a Vector, so it cannot be garbage collected.
The Vector is defined in a function, it should be destroyed after function exits. I also made tests, where I don't add the plane to the Vector and it made no difference.
It might be that memory consumption did not exceed 2GB, but became close to it. It's hard to say, because my machine starts to kill processes around that point. Anyway, I have not changed gc-setting or JVM settings.
It seems to me that trying to use large amounts of short-lifespan objects is a bad idea. It leads to performance and memory problems. Perhaps I just try to implement differently what I want.
Big thanks to everybody who helped me to solve and investigate various problems!
On leaving the function all that would have happened is the Vector would be orphaned, awaiting gc -so would still be occupying memory.
Creating a large number of short life span objects does lead to performance decrement compared to reusing existing objects (pooling / caching), but that's an issue across all languages and a prime reason for various creational design patterns.
(If you want to know more about patterns, google 'GoF patterns')