Is BatchNode or SimpleBatchNode supposed to reduce # of objects sent to the GPU?

  1. Hi, maybe it’s a stupid question, but FAIK: isn’t BatchNode and/or SimpleBatchNode supposed to substancially reduce the amount of objects sent to the GPU? I have a case here where the FPS is incredibly low and when I look at the stats, I see that the objects count is >11000 (!!!) and I don’t even have that many objects in all so I don’t know why BatchNode produces so many objects, it’s insane!?..

  2. Once I update a couple of its spatials rotations, should I call .batch() again or not? I’ve read it’s unnessary, but if I don’t call it, I don’t see the objects change.

  3. What’s the difference between BatchNode and SimpleBatchNode except for the fact I have to strip all nodes and only feed it geometries?

Thx :smiley:

If you have 11000 objects in your scene then you have 11000 Geometry instances in your scene before batching. BatchNode isn’t going to add those objects.

BatchNode will batch geometries with the same material. If they don’t have the same material then they don’t get batched. If they aren’t getting batched then they don’t have the same material.

1 Like

Note also that the stat view report the number of objects rendered not the number of objects in the scene.
Some objects can be rendered several times depending on if you use some post processing filters or shadows for example.

  1. As pspeed stated batchNode batches together geometries that have the same material
  2. You don’t need to rebatch when you transform a sub-geometrie (that the point of the batchNode actually). If you witnessed this kind of issue then, could you post a test case?
  3. SImpleBatchNode is useful if you have to transform your BatchNode : for example you want to rotate the node on every frame. In that case, the classic batch node will rotate the batch geom by updating the underlying meshes buffers, SimpleBatchNode will rotate it like any other geometry, so it’s pretty faster. Also BatchNode can handle a sub graph of nodes, SimpleBatchNode only contains geometries

Well guys, I knew already the “same material” batching concept, but I was wondering if it’s supposed to render that many objects. I’ll give you an example. I isolated an instance of an object that repeats a lot in my project and I rendered the exact same camera location/rotation on all the out-of-the-box ways I could think of to batch them and compare the amount of objects and fps. I must say there is no physics or rigid bodies at all on these… just a quad geometry, so… not a very complex shape! Here are the results:

I created a node and give it a name, created a quad, created a geo from the quad, set a material on the geo and then attach the geo to the node and batched all the nodes together or if you prefer… this function repeated like 1000 times:

[java]
Float s = 0.8f; // Size
Node tree = new Node(“Tree”);
Quad faceShape = new Quad(s, s);
Geometry face = new Geometry(“Tree face”, faceShape);
face.move(-s/2, 0, 0);
tree.attachChild(face);
face.setMaterial(treeMaterial);
tree.setLocalTranslation(new Vector3f(x,y,z);
return tree;
[/java]

Unoptimized fed with node > geo: 15761 / 11fps
GeometryBatched fed with node > geo: 1454 / 57fps
SimpleBatchNode fed directly with geo: 4325 / 30fps
BatchNode fed directly with geo: 4325 / 30fps
BatchNode fed with node > geo: 5278 / 25fps // <-------- You can clearly see here that the node encapsulation raises the number of objects… but why?

It’s not like the encapsulation node had anything to do with the rendered geometry… I mean it’s just a node with a name. Is it because the face geometry is displaced before being attached to the node? Well, I tried commenting that line and guess what… 5296 objects (18 more objects!!!) lol like what the F…?

As you can see, I’m thinking it might be worth it to simply GeometryBatch every now and then and run at 57 fps, unless somebody can help me figure out what’s wrong with my BatchNode implementation! I want to highlight again the fact that I’m not going to update them every frame, just once every now and then like every 5 seconds or something.

Your support/help/ideas are greatly appreciated guys. Thank you so much for taking this time with me :stuck_out_tongue:

EDIT: GeometryBatched fed directly with geo: 1464 / 63fps (+10 objects… +6fps… just by removing the node encapsulation. That’s… not what I would have expected, really. I ran the test 3 times just to be sure :stuck_out_tongue:

EDIT 2:
GeometryBatch with grassBase.j3md shader fed with node > geo: 1390 / 61fps // Drawback: no shadows
GeometryBatch with grassBase.j3md shader fed directly with geo: 1390 / 68fps // Drawback: no shadows

Something is wrong. If you have only 1 material (treeMaterial) you should have 1 geometry, period. No matter what shape are the meshes or if you move them.
Either something is wrong with BatchNode either there is something you’re not telling us. There can be issues with batch node, but what you describe really sound like the most common case, and if there was this kind of trouble we would have notice before.

So there must be something that you overlook in your setup and that you’re not telling us.

Could you wrap up a text case for this issue?

Not sure how I could wrap this to a concise test case; it’s tens of thousands of lines of code. I’ve been adding up on this for 3 months now. It’s pretty complex.

But I’m using BatchNode some place else in the same project and it works fine, so I’m perplex about this problem. You must be right about having overlooked something. I’m under the impression that BatchNode sees a NULL material on a node and thinks everything further down is material-less even tough all geometries use the same material and so it doesn’t batch anything. I know I had this problem at the beginning because it would throw an exception like “You have to set a material prior to batching” and even tough I was setting one it would still complain until I moved the material setting line at the very top of my operations, so I’m sure it’s confused about the materials and plainly refuses to batch my geometries for some reason. As a matter of fact, if I recall, in the tests I did I tried to apply the material to the parent node and then to the geometries themselves and maybe that’s where the batching problem happened.

At the moment, I’m exploring the GeometryBatch way by feeding it only the geometries and it works damn great, seriously. Nearly 70fps (was like 30fps before or like 11fps without any optimization). I have achieved what I was after and it’s more than doubling the fps. Good enough for me at the moment. I’m also using ever-facing camera billboards (a.k.a. impostors) so I do not need to update the individual object rotations every now and then anymore at all, effectively avoiding the need for BatchNode. Geometries are left untouched forever after, pushing the fps to the roof.

Thx for your greatly appreciated advice and follow up.

I can honestly say to whoever travels the same path as me that the most fps were saved by feeding the batching processes (all of them) ONLY geometries and no node at all.

perhaps this can come in handy:

protected void printHierarchy(Spatial n, String indent) {
	System.out.println(indent+n.getName()+":"+n.getClass()+":"+n.getLocalTranslation()+" Shadow:"+n.getShadowMode());
	if(n instanceof Node)
		for(Spatial c : ((Node)n).getChildren())
			printHierarchy(c, indent+" ");
	
	for(int i = 0; i&lt;n.getNumControls(); i++)
		System.out.println(indent+"Controller:"+n.getControl(i).getClass());
	
	for(Light l : n.getLocalLightList())
		System.out.println(indent+"Light:"+l);
	
}

I have an action in my app to trigger the print when I need it. you can put more output into it, for example like the material for a geom…

What I have seen in the batchutility is, that it places x empty nodes into the batch result too, but that should not bother with rendering… It was present in the sdk too, but perhaps this was fixed…

@.Ben. said:

Unoptimized fed with node > geo: 15761 / 11fps
GeometryBatched fed with node > geo: 1454 / 57fps
SimpleBatchNode fed directly with geo: 4325 / 30fps
BatchNode fed directly with geo: 4325 / 30fps
BatchNode fed with node > geo: 5278 / 25fps // <-------- You can clearly see here that the node encapsulation raises the number of objects… but why?

… are those object counts coming from the stats display or something else? Only the stats display matters.

I agree with the idea of dumping the hierarchy. You have somehow managed to add more geometries than you think if that’s the stats display.

ok, hase seen that the code in the engine is still the old one in the batch util, here’s what i have done:

Index: src/tools/jme3tools/optimize/GeometryBatchFactory.java

— src/tools/jme3tools/optimize/GeometryBatchFactory.java (revision 10912)
+++ src/tools/jme3tools/optimize/GeometryBatchFactory.java (working copy)
@@ -385,14 +385,17 @@
gatherGeoms(scene, geoms);

     List&lt;Geometry&gt; batchedGeoms = makeBatches(geoms, useLods);
  •    if(batchedGeoms.size() &gt; 0) {
    
  •    	scene.detachAllChildren();
    
  •    }
       for (Geometry geom : batchedGeoms) {
           scene.attachChild(geom);
       }
    
  •    for (Iterator&lt;Geometry&gt; it = geoms.iterator(); it.hasNext();) {
    
  •        Geometry geometry = it.next();
    
  •        geometry.removeFromParent();
    
  •    }
    
  •    //TR: this leaves Nodes without Geoms below the scene
    

+// for (Iterator<Geometry> it = geoms.iterator(); it.hasNext():wink: {
+// Geometry geometry = it.next();
+// geometry.removeFromParent();
+// }

     // Since the scene is returned unaltered the transform must be reset
     scene.setLocalTransform(Transform.IDENTITY);

Hi Paul, the stats are coming directly from the lower/left corner native JME3 display.

Hi @ghoust

Thank you for this traversal code snippet. I am doing the same thing with the Scene Graph Visitor. I haven’t seen anything in the way of BatchNode that would prevent it from batching. I’m more concerned with the fact that maybe it saw a material-less node and decided it was ALL material-less…

Nodes never have materials.

Only Geometry objects have materials.

I meant SPATIAL, I’m sorry.

“Dogs have gills”
“Dogs don’t have gills”
“Sorry, I meant ANIMALS have gills”

@.Ben. said: I meant SPATIAL, I'm sorry.

Well, it’s important. Because only some SPATIALs have materials. ONLY Geometry has materials. You can have 5,00,000 Nodes in your scene and not a single one of them will have a material. If you have 5,000,000 Nodes in your scene and only one of them has a Geometry child then there is only one object in the stats display.

Nodes don’t matter in this case. Only Geometry. I thought this needed clarifying given how often the word Node is used incorrectly here combined with ghoust’s patch that doesn’t really do anything related to this conversation.

@.Ben. said: maybe it saw a material-less node and decided it was ALL material-less...

Specifically, the above makes absolutely no sense if you really mean Geometry.

So why don’t you just debug through the batch method? It seems you are on the coding side anyway, so why not do just a debugging session on batch creation?

Guess a breakpoint around

for (Map.Entry<Material, List<Geometry>> entry : matToGeom.entrySet()) {

would be interresting, in the GeometryBatchFactory…

At that point all geoms should be put to their corrsonding materials…

Hi Normen :stuck_out_tongue:

Come on guys. We’re just trying to learn here. You’re 3 JME3 developpers against 2 n00bs :stuck_out_tongue:

@pspeed you surely read that last sentence…

@ghoust said: What I have seen in the batchutility is, that it places x empty nodes into the batch result too, but that should not bother with rendering..

Just wanted to get sure Ben does not count nodes, as we now know he does count rendered objects.

@.Ben. said: Hi Normen :P

Come on guys. We’re just trying to learn here. You’re 3 JME3 developpers against 2 n00bs :stuck_out_tongue:

No one is upset… but covering your ears and yelling “lalalala” isn’t going to help you learn anything either.

You were pretty clearly mixing nodes and geometries which is only going to confuse you going forward. A Geometry cannot have a null material and even if it did it couldn’t possibly affect anything else because Geometry objects have no children. But anyway, a Geometry is a mesh and a material… without one of those things, your app would crash if it tried to render it.