1
$\begingroup$

I don't want it to move all the shape keys from 0 to 1 at the same time. I only want it to start moving the next shape key after the previous one has reached 1.

$\endgroup$
3
  • 1
    $\begingroup$ On a scripting level you could consider a frame_change handler for this, that sets an "active shape key"'s value based on the value you want to drive with, otherwise you will need a driver on each shape key using, for example, an offset approach as sambler suggests. $\endgroup$
    – batFINGER
    Mar 11, 2016 at 14:40
  • 1
    $\begingroup$ From the raw driver variables it wont work from a single place, because all a driver does is return a value. If you register a python function it is possible, if not then you will have to create one for each shapekey. Each one could check the property of another and return that value to use for the current ones calculation. $\endgroup$
    – Rick Riggs
    Mar 11, 2016 at 15:37
  • $\begingroup$ Thanks to everyone. I will try some of this today. I'm terrible at drivers besides the most basic stuff and have no experience with Python so we'll see. I'm basically learning Blender through this book. $\endgroup$
    – SRCP
    Mar 11, 2016 at 17:56

4 Answers 4

2
$\begingroup$

Frame Change Hander

Here is a frame change handler approach. A property, multi_shape_key is added to mesh objects. For example sake I prepended a slider on the shapekeys panel.

Note: edit and change the name Cube to the name of your mesh with shapekeys.

import bpy
from math import floor
from bpy.props import FloatProperty

# update method
def multi_shape_key(self, context):        
    v = self.multi_shape_key
    vf = floor(v)
    vr = vf + 1
    for i, key in enumerate(self.shape_keys.key_blocks):
        if not i:
            continue # ignore Basis
        if i <= vf:
            key.value = 1.0
        elif i > vr:
            key.value = 0.0
        else:
            key.value = v - vf
            # could change the active_shape_key_index too.
            #context.object.active_shape_key_index = vr

# property on mesh to "drive" shapekeys        
# set max to number of shapekeys.        
bpy.types.Mesh.multi_shape_key = FloatProperty(min=0.0, max=5.0, name="Multi",
                                               description="Slide to apply multi shapes",
                                               update=multi_shape_key)

# draw method to prepend to shapekeys panel
def draw_slider(self, context):
    layout = self.layout
    layout.prop(context.mesh, "multi_shape_key", slider=True)

bpy.types.DATA_PT_shape_keys.prepend(draw_slider)

# if you are going to keyframe prop we'll put in a hander
def handle_frame_change(scene):
    # change Cube to name of your mesh, or some other method to find
    mesh = bpy.data.meshes.get("Cube")
    if mesh:
        multi_shape_key(mesh, None)      
    return None    

bpy.app.handlers.frame_change_post.append(handle_frame_change) 

enter image description here

$\endgroup$
5
  • $\begingroup$ Where do I enter all of this? $\endgroup$
    – SRCP
    Mar 13, 2016 at 18:22
  • 1
    $\begingroup$ Copy the script, paste it into text editor, edit Cube to the name of your mesh, right click, run script & should look like image above. $\endgroup$
    – batFINGER
    Mar 13, 2016 at 18:30
  • $\begingroup$ I just did it. It gives me an error about indentation. i.imgur.com/1O6aG3t.png $\endgroup$
    – SRCP
    Mar 13, 2016 at 18:35
  • 1
    $\begingroup$ import bpy is line 1. You've missed a bit when copying at this end. $\endgroup$
    – batFINGER
    Mar 13, 2016 at 18:40
  • $\begingroup$ Thanks man! That's amazing. I can just use the max value to stop at a certain shape key, I like that. I'll study this thing. $\endgroup$
    – SRCP
    Mar 13, 2016 at 18:43
2
$\begingroup$

By adding your own function to the driver space you can customise a driver to suit your needs. The following function returns a value between 0.0 and 1.0 based off an input value and and offset.

import bpy

def multi_driver(var, offset):
    val = var - offset
    if val < 0.0:
        return 0.0
    elif val > 1.0:
        return 1.0
    else:
        return val

bpy.app.driver_namespace["multi_driver"] = multi_driver

The last line adds the function to the driver namespace so you can use it as multi_driver(x, y) in any driver you setup.

In this example I am using a custom property as the value input, you can change this for a bone or object location etc. The first shapekey uses an offset of 0, the second an offset of 1, the third an offset of 2 ...

driver properties

$\endgroup$
1
$\begingroup$

This is almost exactly like the project at http://web.purplefrog.com/~thoth/blender/python-cookbook/docking-tube.html . The trick is in setting the coordinates of the Generator driver modifier. You will probably have to add the modifier to the driver yourself. Each shape key will use different coefficients to make the key respond over a different range of the input variable. If the generator results in a value outside [0..1] it will be clamped, so no worries.

$\endgroup$
0
$\begingroup$

https://www.youtube.com/watch?v=o4qYHNA_x4Q This tutorial will show you what you want to do.

$\endgroup$
1
  • $\begingroup$ That doesn't show how to make one driver control 2 or more shape keys the way I want. $\endgroup$
    – SRCP
    Mar 11, 2016 at 3:40

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .