How to run Python code when object is edited?

Is it possible to run Python code whenever an object is edited? (e.g. edit mode is toggled)?

This code could be potentially expensive, so I’m wondering what’s the most efficient way than just putting it in depsgraph_update_pre_handler?

1 Like

not that I am aware of- and unfortunately depsgraph handlers will be triggered for any updates (changing the selected geometry, for example) which makes them not super useful when all you need is to run something when the mesh has changed. I have long requested some kind of “bmesh update” event, as it would be extremely useful.

What are you trying to build? there might be another way around the issue depending on what you’re trying to do.

@testure hmm, that’s a shame. I’m building an add-on of which one of the features calculates geometric qualities, which can be things like areas, volumes, lengths, perimeters, etc of shapes. Currently, calculation requires the user manually triggering an operator. I’m wondering if this could be done “on the fly”.

Other options I am considering is simply marking shapes as “dirty” during the depsgraph handler, and then doing the expensive calculations on save.

yeah, the depsgraph update handler itself is not a significant performance hit, so if you had a way of detecting relevant changes before you did some of your more intense tasks it would probably be possible.

since a depsgraph update will be triggered for virtually any type of change, from viewport navigation to UI interactions- you basically just need to separate out geometry edits from everything else. Luckily there’s DepsgraphUpdate.is_geometry_update flag (docs) which will let you know if the update in question is geometry-related, but it also gets triggered for things like selection changes. So you really just need a way of determining whether a change is a real geometry edit or not.

This is all off the top of my head- none of it has been tested, just ‘thinking out loud’. You could cache the number of vertices a mesh has between updates, and if the current vert count doesn’t match the cached vert count you know that geometry was either added or removed- but this doesn’t account for geometry transformations. For that you could probably do something like calculate the average vert position (even with numpy, not fast enough) or compare bounding boxes (not accurate enough). Probably easier to actually solve for the ‘selection’ edge case and identify it as a false positive that you can then early out from.

If you cache the indices of the selected elements after each depsgraph update, you can compare it to the next update and see if any of the indices changed. If the number of vertices did not change, and the selected indices list does not contain the same indices- I would think you could be reasonably confident that it was just a selection change and can dismiss it as such.

keep in mind that for all of this you would still need to create a bmesh on every depsgraph update, which is basically free- building a list of selected indices is not, however (not sure how dense your meshes are, but the test I just did was about 9ms for a cube subdivided to ~70k). 9ms for a 70k vert mesh is probably not too bad, but if you extrapolate that out to 1mil verts you’re probably looking at closer to 350ms, which is a significant amount of lag to add to every selection change. That said, Blender is virtually unusable on meshes larger than ~200k verts in edit mode so maybe you’re safe? Either way, just an idea- maybe somebody has a better one, I would be very interested in hearing one for some of my own back-burnered projects.

Anyway, hopefully this stream of consciousness rambling was useful :stuck_out_tongue:

1 Like