here I have simple setup (see attachment), object dimension property controlled by driver’s “Distance” variable, which measures distance between Empty and object itself.
I want that driver’s value could only grow up, but never go down, in order to achieve trigger effect like on this GIF animation with cube in the middle:
You should be able to do this with a driver function and a custom property.
Youll have to run the script and may have to update dependencies before the driver works.
Ive attached a modified example.
It was written for 2.70a, so it may need to be modified.
import bpy
def driverFunc(var):
ob = bpy.context.scene.objects['Cube.001']
if var > ob['prop']:
ob['prop'] = var
return ob['prop']
bpy.app.driver_namespace['driverFunc'] = driverFunc
Or you can just swap out one object for another. After the Empty passed by and your animation is done animate the hide_render icon (Camera) in the Outliner to turn off. So you would need a duplicate of the object, without the driver, that you would animate on (in the same location) at the same time you animate off the object with the driver. The old slight-of-hand trick. No code needed but code can work too.
dirty-stick
Thank you so much! Though it doesn’t work perfectly, it still works!
To make it more user friendly I wrote few more operators (place obj name into expression), few workarounds (“Update Dependencies” is not accessible from python) to make things automatic.
Handlers examples in official docs are so generic, that I’m not sure how to apply them in my case.
Node based animation system is the cure to my problem indeed, but there are so many of them, and not a single one with official support (which means they all die as soon as official implementation arrives), so I’d rather wait till Blender officials made their opinion on node based systems, and invest my time into learning Blender API which will benefit me in the long run.
Ive attached a .app.handler example.
Does the same thing, just easier to setup.
It should work after pressing run script, no drivers required.
Its best to clear .app.handlers when not using them by the way.
To clear, add a # in front of ‘bpy.app.handlers.scene_update_pre.append(app_handler)’, then run the script again.
.app.handler code.
import bpy, math
def dist3(x1,y1,z1,x2,y2,z2):
return math.sqrt((x1-x2)**2+(y1-y2)**2+(z1-z2)**2)
obs = []
obs.append(['Cube',0.5])
obs.append(['Cube.001',0.5])
obs.append(['Cube.002',0.5])
def app_handler(scene):
em = bpy.context.scene.objects['Empty']
for ob in obs:
obj = bpy.context.scene.objects[ob[0]]
dist = dist3(em.location.x,em.location.y,em.location.z,obj.location.x,obj.location.y,obj.location.z)
ob[1] = 4-dist/2
if ob[1] > obj.dimensions[0]:
obj.dimensions[0] = ob[1]
# scene update
bpy.app.handlers.scene_update_pre.clear()
bpy.app.handlers.scene_update_pre.append(app_handler)
# render update
#bpy.app.handlers.render_pre.clear()
#bpy.app.handlers.render_pre.append(app_handler)
Wow, thanks! But I can’t say it’s a better way than driver function for two reasons:
Lack of artistic control — it’s fine if I want to use linear interpolation when animating dimensions property, but if I want to use Ease In Out with with Exponential or Cubic Interpolation, or Stepped interpolation? Even if I know the formula, it’s still much more complicated than drivers.
Performance — three objects are fine, but when I’m trying to make it work with more than hundred, even if I’m not touching anything it’s affecting CPU performance really heavy, and never stops till I clear the handle, which is not acceptable at all.
But thanks to you now I have my set of animation tools that already helped me to finish my projects, plus now I have a better understanding of Blender API and Python.
Referencing objects by the context is not recommended try using the provided scene instead. If the context ends up blank or None while rendering your code will fail.
Change.
em = bpy.context.scene.objects['Empty']
To…
em = scene.objects.get('Empty')
if em != None:
#Process code here.
Also test if the returned object is None before proceeding.
Atoms referring to the handler function.
The app_handler(scene): has a scene pointer, which is derived from bpy.context.scene, I think.
The handlers like frame_change_post and frame_change_pre are more cpu friendly.
If using the driver function method, I dont think youll have to use custom properties.
You should be able to just update the dimension if the var is > dimensions[0].
import bpy
def driverFunc(var, name):
dm = bpy.context.scene.objects[name].dimensions[0]
if var > dm:
dm = var
return dm
bpy.app.driver_namespace['driverFunc'] = driverFunc
I couldnt find an operator to update dependencies via python.
There are some operations that trigger an update, modifying the driver expression via python for example.
If using the driver function method, I dont think youll have to use custom properties.
Already did that ^^
There are some operations that trigger an update, modifying the driver expression via python for example.
This exactly what I’m doing, couldn’t find any kind of operator:
objs = context.scene.objects
for obj in objs:
if (obj.data and obj.data.shape_keys and
obj.data.shape_keys.animation_data and
obj.data.shape_keys.animation_data.drivers):
fcus = obj.data.shape_keys.animation_data.drivers
for fcu in fcus:
if fcu.data_path == 'eval_time':
fcu.driver.expression = fcu.driver.expression