Jme3 Beginner: Understanding the Animation Performance

I am using Cinematics for my animation, and everything works great as I am testing everything now with a few spatials. Eventually I will have a large number of those spatials (where each is imported from Blender having 3-5 materials each). I would like to know the following:



(1) How can I measure the performance of my graphics? Should I keep the Frame per second higher than a certain number? Maximum number of objects? Max number of meshes? any link to read all these info and not sound like a complete noob ;)?



(2) If I attach all the spatials into one node (and eventually attach that to the rootNode) instead of attaching each to the rootNode that sounds to me like a better approach. Would that impact my performance? Would the GPU see it as one mesh?



(3) I suppose reducing the quality in the spatial object itself from Blender would improve my performance. Anything in particular I need to eliminate or reduce?



Again sorry these are REALLY BASIC questions but I am trying to understand how it exactly works before proceeding and regretting it later.



Thanks in advance

  1. http://hub.jmonkeyengine.org/groups/general/forum/topic/object-count-performance-sourvey-everyone-please-participate/

    Target fps was 60, cause that is what most lcd’s have for refresh rate, faster won’t bring much. Counted was the amount of meshes displaable for that.



    2)

    if any change it would be worse, cause culling might not work efficiently. What works would be attaching parts of map togheter, taht are seen togheter to get a little improvement in the frustrum culling. But realy, mostly you attach just like logic is, aka a tank turret to a tank.



    3)

    Less polygons would be more performance, less meshes would be more performance, texturesize would not gain anything, untill you reach graficcard ram limit, then they have hughe impact.
1 Like

Thanks!!



so let’s say I had 1000 spatials that move around the scene or a given map. Attaching them individually to the rootNode is a good approach??

If they are independent of each other moving, then yes. If not probably

Well there certainly is a limit on the amount of objects which can be processed before you encounter a bottleneck. I remember somebody doing some tests and Kyrill mentioned something like 5000 nodes or something (don’t remember it right now). The problem is not the actual geometry processing (which is determined by your GPU power) but rather the managing overhead which gets to a point where it becomes unfeasible for CPU and RAM.



So try to group together as much geometry as possible and just try to keep the number of nodes as small as possible. Unfortunately JME does not support geometry shader which could be used for Instancing (although that introduces another amount of headaches which need to be dealt with, e.g. asynchronous animations etc.)

Dodikles,

So try to group together as much geometry as possible and just try to keep the number of nodes as small as possible.

by that you mean the created blender object materials must be reduced as much as possible? cuz my spatials objects are really simple: two metaballs with two different colors meaning 2 materials or two geometries, correct? so could you be more specific on how would I be able to compare that with the 5000 nodes limit you suggested?
PS: to my noob understanding, each spatial is a node that contain 2 geometries.

Its outlined in the wiki how you can optimize your scene graph, you can also use jMP to do that, simply right-click a node and select “optimize geometry” if many of the sub-geometries have the same material. This way you make them one big geometry each.

My mistake, with nodes I actually meant spatials.

You need to find a reasonable number of nodes so that culling can occur in a performant way although that 5000-something limit still applies also to them of course. I meant that you keep your number of spatials down. Consider you have a car which has many static parts and you have divided it into many spatials like “door” and “tire” and “engine” etc. If they don’t have any real meaning for game logic etc. it would be wise to merge them and their geometry into one single spatial. In your case, where you have multiple spatials that share one geometry you are going to be fine by just clone()'ing them (not deepClone()!) and you will probably need every ball as a spatial.



A spatial is just something that sits in the scene graph. It does not imply what it contains or not. In your case it holds 2 geometries because blender saves it that way…

ideas :


  1. how about converting enemies into a particle ? with all possible animations from all possible angles.

    All possible pictures will be converted into a texture (texture atlas).

    You can define the cameraThresshold e.g take a picture every 1 degree or every 30 degrees.

    Then you could easily have 10000 enemies(same model) at 500 fps. Also it will ignore the mesh polygons e.g i could have a mesh with 1000000 polygons and it wouldn’t affect performance (its just a picture / quad).



    Does jme have a class that does that ? i think jme2 had a class called ImposterNode, why was it removed.

can anyone answer this really basic question? just to make sure I got your point:



My object in blender is a mix of 2 metaballs with a different material each (2 materials, 2 metaballs). So Jme sees that object as 2 geometries compared to the 5000 limit you were talking about?

Also


In your case, where you have multiple spatials that share one geometry you are going to be fine by just clone()’ing them (not deepClone()!) and you will probably need every ball as a spatial.


I have a 1000 copies of the same object that I create using a loop function createSpatial(). Is that the right approach or are you saying I should be using .clone() instead of re-importing the object every time?

Is jme3 using any form of distance tree graph to optimize e.g. culling? Or does it go through every node in the scene every time? I assume that if you create group nodes at the highest level the bounding box of all these are used to cull all of them? If this is the case I guess one could use the node hierarchy for simple spatial culling, although one would need logic to move objects between these higher order nodes.



And how about controllers? Are they still executed if the nodes are culled? For example if you have a lot of billboard controllers for each grass turf, will this controller be ignored when the node is out of the frustrum? In this case it should be since its directly linked to the visibility of the geometry, but I guess some controllers still need execution even if the geometry/node is culled?



Sorry if these questions seem noobish but I am just learning and trying to code in an efficient way wondering whether I should bother with my own cullling code in addition to the one already present or if I could just go ahead and fill the scene with objects and terrain and let the engine take care of all the culling. I did experiment a bit with view frustrum adjustment which should at least be adjusted to where the fog will make objects invisible. That seemed to double the fps in a scene packed with objects in my test case. I guess I also should work with LOD levels as well.



Which leads me to another question: Is there a simple way to add a LOD level to a node that simply culls the geometry at a certain distance?

For distance culling just set the cam far frustum as you discovered.

In 99% of the cases you don’t need to worry about culling. Your scenes will need to be enormous in order to require spatial partitioning, since today’s GPUs almost always prefer larger batches vs. more objects. In my tests using the octree partitioning algorithm reduced performance rather increased it when running on modern (even low-end) GPUs such as GeForce 8400M GS. For old GPUs such as pre-shader cards from NVIDIA and ATI it will be a concern, also, the same applies to Intel cards.



Culling is handled as a hierarchy, so if a parent node is culled then all of its children are culled as well and are not checked, unless the bounding volume of the parent intersects the frustum. For controls, the update() method is executed for all spatials in the scene, while the render() method is executed only for visible spatials.

1 Like

Ah thank you for the reply. But I guess for large open ended Morrowind/Oblivion/Skyrim like sceneries one would be wise to divide the world into segments so that large areas are culled if they are not needed (obviously if you need to see distant land you need to make sure these are not culled but only the detailed objects put on it). Although in this case one would have to worry about streaming anyway and the partitioning comes rather naturally through dynamic adding and removing of terrain/geometry like the TerrainGrid implementation.



But its also good to know that controls update is executed for all spatials in the scene even if they are culled, meaning that you have to be careful with these as they can gobble a lot of CPU time even if they are never seen. In other words one have to consider only using Controls for spatials that you need to keep track of as a game logic thing (which is what they are intended for from what I can see), and not for visuals (like billboards controls).

@johncl said:
But its also good to know that controls update is executed for all spatials in the scene even if they are culled, meaning that you have to be careful with these as they can gobble a lot of CPU time even if they are never seen. In other words one have to consider only using Controls for spatials that you need to keep track of as a game logic thing (which is what they are intended for from what I can see), and not for visuals (like billboards controls).

You don't get it, controls have an update AND a render method. update is always called, render is only called if the object is not culled. So you can use control for anything.

For example the skinning for the SkeletonControl occurs in the render method because you don't need your object to do complex animation if it's not visible.

Ah ok. So you can use update and render to distinguish between these two cases (update for vital changes of the node even when it is not seen, and render for when it is showing). I guess I was confused as traditionally update is where you do all model updates and render is stuff done only during the rendering pipeline.



Taking a look at some controls I spot the following:



BillboardControl: All changes are done in controlRender() meaning that the rotation of the node only happens when the node is visible. In other words no CPU wasted for these when they are culled (it was very noticeable in my test case where I had 1000 billboards).



AnimControl; All changes are done in controlUpdate() meaning that animation is always done, even if the node is not visible. An NPC drinking from a cup on the other side of the mountain is still animated, even if you cant see him (and have been culled). So one is wise to have some “control” over your controls. :slight_smile: I guess its possible to inherit the control and only call the super when the NPC is within a certain range of the camera to conserve some CPU time.



Sorry for sounding nit-pickety, but I am just trying to find best practices of the engine to get the highest performance. Every day I learn something new. :slight_smile:

@johncl said:
Ah ok. So you can use update and render to distinguish between these two cases (update for vital changes of the node even when it is not seen, and render for when it is showing). I guess I was confused as traditionally update is where you do all model updates and render is stuff done only during the rendering pipeline.

Well you have to be careful though, changing transforms, attaching/detaching nodes should not, most of the time, occur in the render method, as they will only be taken into account on the next frame.
If you do, you have to manually update you geometries so that transforms are applied on this frame.
The BillBoardControl is a good example of that. There is no need for a billboard to face the camera if it's not rendered. hence the rotation toward the cam occurs in the render method. But, the rotation is applied manually by calling updateGeometricState on the spatial so the billboard is not one frame late.
1 Like