Heavy scene lag affects tool performance?

Hi all, sorry if my thread title is off. I have written up a gui in which it allows real time update towards group nodes generated by the tool, and also there have been some scriptJobs such that it is a bi-directional feedback whenever there are changes (eg. tweaking of the translate attributes) made in the scene or within the tool.

However, while trying to use this tool of mine in a heavy scene, even before my tool is open, there is already a bit of ‘lagginess’ when trying to navigate the scene. And so, when my tool is opened, the lagginess also appears to have affected it too.

My question here is - could my tool lagginess be due to this ‘real-time’ update feature that I have implemented? Or is it a common case in maya whenever dealing with heavy scenes?

Lastly if anyone have any suggestions that I could try implementing to improve my tool efficiency/ resolving the lagginess, please do tell.

Many thanks in advance.

There is no way to know for sure without seeing the code in question, but it is always possible for script-job driven code to slow down a scene.

You can always attempt to profile your code with python’s cProfile module.

How is the scriptJob registered and de-registered? I tend to use callbacks in these cases through the API.

I’d probably use the API myself as well, though the one advantage to using a scriptJob in this case is that it can be parented to the UI and cleanup should happen properly when the UI is destroyed. Though even with this, you need to be sure that you’re actually killing the UI when it isn’t in use, and not just hiding it, as the scriptJobs will continue to do their thing even though they aren’t actually needed.

Honestly it probably comes down to how the code is written, and what kind of actions hare being triggered by the scriptJobs, if you’re walking through all the objects in a scene every time an event happens, and you’ve got a heavy scene, that will be slow.

Some mel commands are also inherently slow, and this translates over to their python counterparts in maya.cmds sometimes you can write code that will be a bit faster, but you need to profile and test to be sure that is actually the problem.

And honestly, sometimes Maya is just slow, if you’re throwing a lot at it, dense complex DAG graphs can drag the whole program down.

1 Like

Hi all, so in terms of script jobs, I am using 1 where it detects the ui closure.
And I actually have 3 MEventMessage events where it deals with “NameChanged”, “Undo”, “SelectionChanged” and the last one being MAnimMessage where it detects the change in animation data.

The creation of these jobs/events are done when the tool is called, and removed when the tool is closed (the only scriptJob)

My code is pretty long though, can I actually post external links here (eg. PasteBin?)

Oh yeah, pastebin or github gists are totally welcome.

Hi all, here are my scripts:

main.py
utils.py
refplanes.py
ui file (Created from qt designer)

In one of the ‘very’ small lag that I have found - during the selection made within my tool, if you selected an image plane with an expression, the mouse cursor does changes into a loading icon (lasted like half a second or so) . Or when you tried to hide/unhide the image plane using my tool, it feels somewhat slow as compared to selecting the same image plane in the scene and performing Ctrl+H/Shift+H.

P.S: I am also having some undo issues too where for example - trying to perform a rename etc, requires one to hit Ctrl+Z one or two more times to undo the action.

Many thanks and appreciate in advance for any replies.

Hey @xenas,

Are you using PySide2? - You can import QtWidget directly:

from PySide2 import QTWidgets

from maya.app.general.mayaMixin import MayaQWidgetDockableMixin

class MyClass(MayaQWidgetDockableMixin, QtWidgets.QtWidget):
  pass

QtWidgets.QtWidgets does have a close event which you should be able to override negating your scriptJob. - I need to debug some more as to why you need it in the first place.

 def closeEvent(self, *args, **kwargs):
   apiOM.MMessage.removeCallback(self._callback)

Close Event Docs:

https://doc.qt.io/qtforpython/PySide2/QtWidgets/QWidget.html#PySide2.QtWidgets.PySide2.QtWidgets.QWidget.closeEvent

Regardless of the widget being docked or not - on close this event should fire:

This event handler is called with the given event when Qt receives a window close request for a top-level widget from the window system.

By default, the event is accepted and the widget is closed. You can reimplement this function to change the way the widget responds to window close requests.

I think what might help is to be a very simple widget with the callbacks just printing values, and see if overriding the closeEvent actually de-registers them.

Additionally:

I think it would be advisable to check if you events already exist and de-register them prior to instantiation of the class:


def __init__(self):
   
  # Something *like* this...

 if self.event_callbacks:
    OpenMaya.MMessage.removeCallbacks(self.event_callbacks)

 self.create_custom_events()

Hi Chalk, many thanks for replying back.

I will try out some of the points that you have mentioned. Even so, any ideas on the lag or perhaps the undo?

As for the former, I am more interested to know if it could be a ‘general-maya’ issue or what not.

Debugging…

So, on init you call self.create_custom_events which registers the undo callback self.track_undo - this in turn calls self.list_widget_update()

So dependency flow: create_custom_events --> track_undo --> list_widget_update

Next list_widget_update calls several internal functions (I’m skipping calls that look like PyQt calls):

  1. utils.get_scene_cameras()

    a. Looks ok, not sure what,

    res = apkg_utils.find_closest_parent(cam, "apkgStack")

    is doing - is this doing large scene querying? - might be a slow down.

  2. self.refPlanes.get_all_ref_planes() - looks fine.

  3. utils.get_visibility(img_plane) - looks fine.

  4. self.update_camera_combo() - looks good.

Rough understanding here - you want to query image planes in the scene when the uses hits undo/redo by the looks of it. It gets called 6 times and seems to do the heavy lifting in the interface both getting cameras and planes.

Your undo context looks correct - not sure if you need chunk name a module member if its always the same thing.

What might be the kicker is this callback:

kf_edit_event = OpenMayaAnim.MAnimMessage.addAnimKeyframeEditedCallback(self.node_update)

This method registers a callback that is called whenever an
a group of keys are modified. The callback is invoked once per
atomic change to single or group of keyframes. For example, if
a user selects a group 5 of keys and moves them 5 units in the value
axis, then a single callback event will be invoked with a MObject
> for each of the 5 keyframes. The MObjects can then be used in the
MFnKeyframeDelta function set. Refer to MFnKeyframeDelta function set
documentation for more info.

Emphasis mine - are you working with lots of keys? It’s going to rebuild the interface for every key even if they are moved/changed as a group.

Can you disable the node event callbacks and test if the undo one functions correctly without lag - I feel something else is going on here.

1 Like

Hi @chalk, sorry for the lack in response.

I managed to pinpoint down certain slowdowns which is primarily to do with some of the duplicated methods being called.

As for the number of keyframes, the image planes may or may not have tons of keyframes. Even when using image planes with no keyframes, it is still functioning somewhat laggy in which I suppose it is mostly due to my maya scene which are high in polycount