I would like to be able to execute a custom script every time a particular object is moved in the viewport. Is there a clean way to do this?
I am using an empty object to guide deformation of a mesh. Right now, I move the empty, and then call my custom operator (by a custom defined keystroke). I’d really like it to work at interactive rates though.
I know that there is an “update” callback function that gets called for custom parameters. But I don’t see how to make that work for a built-in parameter like “location”.
But seriously, I had not considered drivers. I will look into that possibility more closely.
It seems a bit strange to use a driver, because there no particular single parameter that I want to drive, I just want to be able to auto-run a script. (Like printing text the console or something, every time the object is moved.) But maybe I could set up a dummy parameter, like an irrelevant color, and in the process of “driving” that, my script will execute.
I think you have to use “modal operator” for that kind of operations. A modal operator keeps running a code in the background that you specify.
Here is a file toggle_bones.blend (73.8 KB) that Liero did for a question I made .
That may help you.
Also check this help for more info about modal operator.
When you jump into this realm, you have to consider renderability. A modal operator, while working in the GUI, might not actually work when rendering your animation. You lose the context when you render. Drivers would be my first choice.
On reflection, a handler may be the option you are after. Below is a simple example.
import bpy
data = {} #keep data in a dictionary
TOL = 1.0e-4 #how much the cube needs to move in a frame
def loc_change(scene):
# run some scripts if the cube has moved.
cube = scene.objects.get("Cube")
loc = cube.location
dloc = loc - data["CubeLoc"]
if dloc.length > TOL:
print("FRAME:%d Cube has moved" % scene.frame_current)
data["CubeLoc"] = loc.copy()
bpy.app.handlers.frame_change_pre.append(loc_change)
# initialise data
data["CubeLoc"] = bpy.data.objects.get("Cube").location.copy()
@batFinger: That will work when the frame changes. In the first post the user is looking for an interactive way to call the update routine. When I create my own custom properties I can point them to an update def. I am wondering if there is a way to hi-jack a standard property to do the same thing? That way we could point a change in object location to our own update call, or your loc_change without having to change the frame at all.
Oh ok… change to scene_update_pre handler instead.
With the update, you kinda need to fire that event by changing the prop via the UI or a script. I use that method to make a UI have a live refresh by simply calling x.prop = x.prop in a handler. If i drive that prop to change it the update event isn’t called. Trying to do too much with updates causes grief in my experience.
In the end, I needed to use “scene_update_post”. When using pre-updating, I got foiled by recursion, because my script modifies the scene, which then invokes my script again, which modifies the scene again, etc.
Here’s a (temporary) link to show what I was able to do with this. I’m working on constraint-based deformation (a.k.a. direct manipulation FFD).
I would be very interested in exactly the same thing. It looks like scene_update_post and scene_update_pre don’t exist anymore though. Anyone know how to do this seemingly simple thing?