Lemur performance cost of Mouse collision events

I recently added a single 2D Lemur button to my application, and noticed a significant degradation in performance of my app. I tracked the problem down to mouse collision events being calculated on the 3D scene graph, even though I was only using Lemur for 2D controls.
It looks like Lemur by default will still calculate mouse collision events on the full 3D object graph, even if there are no 3D controls in use.

If you are using Lemur, and not using it for 3D Gui controls, try adding these lines:

MouseAppState mouseAppState = getStateManager().getState(MouseAppState.class);
mouseAppState.removeCollisionRoot(terrain3D.getRootNode());

Note that this performance cost presumably scales with the complexity of your scene graph, so this may not be causing an actual problem, depending on your application. This made a huge difference to me, and brought the performance back to how it was prior to adding Lemur.

This is not a criticism of Lemur, just something you may not be aware of if you are using Lemur.

If anyone knows more details on this please chime in!

3 Likes

What is your app fps before and after removing the root node from collision roots?

I think Lemur does a Ray check with all the registered collision roots at 60 fps to dispatch motion events. Maybe an enhancement could be to add an option to disable motion event check on a collision root if we do not need it (e.g. we are only interested in click events on rootNode) or to make the motion ray check frequency configurable on each collision root (instead of the fixed 60fps).

Maybe another option would be to move (if possible?) cursor motion ray checking into a separate thread in Lemur PickEventSession.

JME is not multithreaded. You cannot access/read/access/modify/read/read/access/read/modify/read/read or read the scene graph from another thread.

What you suggest is therefore impossible because it would require reading the scene graph from another thread.

There is already this option as the OP shows an example.

This will completely remove it from collision checking. I mean to have click events enabled while disabling motion events.

The click events use the motion events. You cannot have one without the other. Clicking does not dispatch a new pick.

More future-proof to get BasePickState.class instead of MouseAppState.class since it will work on android also.

From SimpleApplication’s simpleInit() you can also just use stateMgr.getState(BasePickState.class).removeCollisionRoot(rootNode);

From any app state that extends BaseAppState grabbing the state is easier but grabbing the root node is not.
getState(BasePickState.class).removeCollisionRoot(((SimpleApplication)getApplication()).getRootNode());

Edit: also, I’m sorry this was not mentioned in the documentation. I thought it was but I just rechecked. Good sleuthing to figure it out.

2 Likes

The FPS before removing removing the root node from collision roots averages around 30FPS, while moving the mouse.
The FPS after removing the root node from collision roots is averaging around 40 FPS (varies between 30-55).
However, this is when my application is not doing any CPU intensive work. You are just standing in one place looking around,
As soon as I start to move the player around (and so new terrain is loaded in, calculating new meshes etc; requiring CPU) the FPS drops to around 2-10.
It is more this dramatic FPS variation that I was noticing. With collision detection disabled there is no noticeable drop in FPS.

1 Like

@pspeed This may be a stupid question (I know basically nothing about Lemur); but would it be possible to only add the root node as a collision root if a 3D object has been added to Lemur? So this manual removal wouldn’t be required in my case?

Yeah, on some types of geometry, JME’s picking can be really slow… especially if meshes change a lot and need their collision data recalculated.

If you ever need 3D scene picking back again then there are ways to mitigate this depending on the desired outcome.

Nice that you were able to track down how to remove the 3D scene from the collision roots.

By default Lemur allows 3D scene picking just like 2D scene picking and cannot really know when an application adds a listener to one versus another. (There is no way to tell which viewport a Spatial is in… and it can be in many.)

Lemur only does picking when cursor events are enabled (ie: a UI is up and the mouse is active) so for most games (like first person cameras, third person camers, etc.), I guess this never comes up. And in the other cases, the scenes are usually of the type where it won’t matter.

1 Like

Maybe I am missing something, but looks like motion events are dispatched regularly from the update loop

then in

whereas Button events are dispatched separately in which internally uses cursorMoved(x,y) which causes a pick.

Maybe it’s that cursor button events miss some collision data or something.

…but I have plenty of listeners that remember their motion event so that they can properly do something on click. I’d have to look into it to remember why.

Some things won’t even work properly if they haven’t been activated with a mouse enter event. So it gets weird anyway.

Right, I remember I have seen somewhere in your comments mentioned about this bug in Lemur that collision result could be null if obtained from button events.