View-frustum culling and fps

Hello everyone, I put 3000 static not animated trees with LOD on a terrain and because of very low fps after this I tried some things. I had following stats in the scene in different cases:

Without trees:
triangles: 5.400
vertices: 3.500
fps: 120

With trees and setCullHint(Spatial.CullHint.Dynamic):
triangles: 28.000
vertices: 153.000
fps: 30

With trees and setCullHint(Spatial.CullHint.Always):
triangles: 5.400
vertices: 3.500
fps: 40

The fps are very low with the trees and “CullHint.Dynamic”. I think this is understandable for me because of the much triangles and vertices. But why are the fps low even with “CullHint.Always”? What is happenig in the background, that reduces the fps that much?

And another thing is, that I remeber (maybe wrong…), that I had way more triangles and vertices earlier in another scene, (but not with trees) and I think the fps were higher back then. Could it be, that a high number of vertices and triangles not in every case decrease the fps? I ask because I want to fgure out, what kind of models are best with view on performance (are there differences not just because of the number of tri/vert?).

Thanks in advance.

The problem isnt the number of triangles, i suspect it will be the huge number of seperate objects. Is each tree its own object (or even worse more than 1 object per tree)? Merging them (which can be done programatically) is likely to improve performance

As richtea indicates, you are likely draw call limited. Modern GPUs can eat through triangles so fast… really really fast. You’d probably have better performance with one single object with a million triangles.

Think of it this way, which one of these would be faster:

  1. pack up 50 sheets of paper in a box, label that box, put a stamp on the box… hand that to a dispatcher. The dispatcher needs to see if it really needs to go out and so weighs it and examines it. If it needs to go out, the dispatcher hands it to a truck+driver. That truck+driver drives it down the street to deliver it to another business. That business takes the paper and runs all 50 sheets through a shredder that takes 0.001 ms.
    Pack up another 50 sheets into another box. Do the whole process again.
    Do this 100 times.
  2. pack up 5000 sheets into a box, label that box, etc… Do all of the other things but now you’re done with only one box.

Which do you think will be faster over all?

The overhead for a single draw call is HUUUUUGE. Every single piece of geometry+mesh+material you have has a HUUUUGE amount of overhead as compared to rendering a single triangle.

A scene with one geometry with one triangle in it will render at roughly the same speed as a scene with one geometry with 100k triangles in it.

2 Likes

Thank you both very much. That information is very helpful.

If I put all the single geometries (for example the trees) in one geometry, I am not able after this to get one of the single geometries back again or remove it from this merged geometry, right? (Maybe if I would like to cut down just a single tree.) Or could I just remove the veritces of this single tree from the merged geometry (from its mesh)?

For merging the geoemtries programatically I would use “GeometryBatchFactory.mergeGeometries(…)”, right?

Yes, or you can also use BatchNode which lets you add or remove spatials anytime later on.

There is also an InstancedNode that uses the OpenGL instancing technique instead of batching. You may want to try it also.

4 Likes

Thank you too, for the advise. I tried the BatchNode.

What I realised first, is that the call of batch() takes a very long time. As I read in the description I have to call batch() everytime after attaching a new child to batch node? So maybe it would be better to use more than one BatchNode for all the trees and split them up into several BatchNodes?

What I realised second is, that the count of objects decrease very much and that my fps went up to 40, but the count of vertices an triangles increase a lot. By attaching the 3000 trees to one single BatchNode, I got now 11.400.000 triangles and 7.400.000 vertices. I am not sure, but could the reason be, that I add a LODControl to every single tree (before I tried the BatchNode), but using the BatchNode the LODControls are removed from the trees?

(I think the best way to reduce vertices/triangles is to simplify the tree model, but at the moment I also want to figue out how much “complexity” in the models is possible to have a runnable game at the end.)

I’d say yes. You can divide your terrain into sections. Some sort of quad tree stuff. And apply you batch nodes accordingly too. A single batch node is sharing culling (I think…). So having all in one batch node, ends up having one object but the culling is then terrible.

1 Like

Yeah, for example in my case I have split the scene in a grid so I can do batching or instancing for each section separately. I usually use instancing for large objects like trees and rocks and use batching for small objects like grass and flowers…

Edit:

This could be the reason why you see an increase in vertices counts in the stats view because once you batched 1000 trees they will become a single mesh so no matter whether you are looking at one tree or 1000 trees in the camera frustum, all vertices will be processed by the “vertex shader” I guess. (unless GPU does internal culling on vertices?)

Someone, please correct me if I am wrong.

2 Likes

Now I have another little question to the GeomtryBatchFactory.optimize(Node scene, boolean useLods). In the description I found:

“All Geometries found in the scene are detached from their parent and a new Node containing the optimized Geometries is attached.”

I tried the function on my treeNode which had just one single tree as child for this try. But it do not seems as if the attached tree would be detached. It just seems as if the new batched meshes are attached. I could also see this behavior in the SceneComposer using the “Tools…->BatchGeometry”-button. Do I misunderstand the description or is the description maybe not up to date?

Is the model for your tree being linked in the scene or is it attached reguarly?

Batching linked models will not remove the linked node, so it will continue to reload an extra non-batched copy of each tree when the scene is loaded unless you manually remove the link node after batching.

Ah thank you, now I understand. My treemodel was linked to another parentNode and I attached this parentNode to the treesNode. Attaching the treeGeomety directly to the treesNode, everything is as expected.