Monday, January 3, 2011

[Rigging FAQ] Addedum Info on Drivers System

Re-reading my earlier post on the Drivers system, I realised that I overlooked mentioning a few things that I had intended to mention. Also, there have been a few small changes since then which I thought should be mentioned.

(Sometimes it's all too easy to forget which aspects I've mentioned and which I haven't, and where I might've or mightn't have mentioned them... such is the nature of answering these questions countless times on forum posts before trying to write blog-posts to act as a somewhat-definitive source of reference)


Driving Material Settings
Perhaps this is one of the most common questions that arises regarding the use of the driver system. How exactly do you drive material settings, in particular colour, etc.?

As it turns out, I've already covered this in a post here before: see "Why can't I drive Material/Texture/etc. settings? Isn't 2.5 supposed to allow that?" in http://aligorith.blogspot.com/2010/07/deja-vu-no-more-blender-25-faq.html

In my post on the driver settings, I also mentioned the rationale behind why this (and other cases) won't work, and even the way towards the solution (see "Where do drivers live?" on http://aligorith.blogspot.com/2010/09/rigging-faq-basics-of-new-driver-system.html , especially the last part). In another post, I've also described the "datablocks" method described in the first FAQ post in more detail and with annotated screenshots! (see "Defining Keying Sets" -> "Method 3: Datablocks Editor" on http://aligorith.blogspot.com/2010/12/animating-in-25-getting-to-grips-with.html)

Hopefully doing a Google search will now return all the relevant links to this issue once and for all.

Using Custom Functions in Driver Expressions
In 2.4x, you could specify some functions in a special textblock named "pydrivers.py", which you could then use in your PyDriver expressions.

At the time of writing the previous post, this functionality had not yet been restored (and was noted as such). However, since late November/early December, this is no longer the case (see revision 33348).

The basic idea behind the new system is that you don't have to have any fancy names for the script where the functions/defines to be available for driver expressions need to be. Instead in any Python script (preferably one that you've set to "auto-register" - which essentially just runs the script on file-load) you can define your functions OR constant values, and then "register" them much like UI panels, etc. are (though the syntax is just a bit different).

Enough fluff, let's see a contrived example ;)
In this example, we're going to see how we can define drivers in several different text-blocks, and then use this info in a driver expression.

my_rigging_addon_1.py
import bpy
from math import *

# ... some operator class defines - e.g. finger straightener tool ...

# define some math functions
def abcFunc(alpha, beta, gamma):
    return alpha*beta + gamma

RUM = 4.965
YUCK = 3.121

def xyzRum(x,y,z):
    return sqrt(x*x*RUM + y*y*RUM + z*z*RUM)

# now, make some of these defines available for driver use
bpy.app.driver_namespace['abcFunc'] = abcFunc
bpy.app.driver_namespace['xyzRum'] = xyzRum
bpy.app.driver_namespace['YK'] = YUCK # the name that driver expressions will use doesn't have to be the real name
# 'RUM' won't be directly available via drivers...

generic_stuff.py
def sinc(x):
    if fabs(x) < 0.0001:
        return 1.0
    else:
        return sin(pi * x) / (pi * x)
bpy.app.driver_namespace['sinc'] = sinc
In a driver expression somewhere, we can now do...
abcFunc(v1, v2, v3) * xyzRum(v1, v2, v3) + YK*sinc(v1*v2/v3)
with v1,v2,v3 being driver-variables created the standard way and named 'v1', 'v2', and 'v3' :)

Key Lessons:
All you need to do is, in some script, have a line:
bpy.add.driver_namespace['{funcName}'] = {funcName}

and then you can use {funcName} in whatever driver expressions you like.

4 comments:

  1. Ok... This was nice info indeed. But after about 3 articles, I still can't really understand this one thing from http://aligorith.blogspot.com/2010/09/rigging-faq-basics-of-new-driver-system.html

    "Just one word of caution: if you want to use this to get some transform of an object/bone, this will not take constraints into account. This is purely the values the the animation system sets via keyframes, and the values you haven't keyframed yet."

    So why is that? If you say "dependency graph", I can understand that for now. But I hope it will not be final... If the constraints aren't taken into account, that just kills automation rather effectively or at least makes it quite tedious.

    So some basic stuff, I have a dog like character that has some corrective shape keys on the legs. Bending the leg forward should effect one shape key and bending backwards, another. The rotational difference doesn't really do the trick here. Another example would be arm twist where one could use corrective shape keys along with deforming the elbow... Rotational difference don't know the difference between axes here.

    I can go with another option too like action constraint kinda thing but those don't really work for shape keys and I don't want to animate everything manually every time.

    ReplyDelete
  2. Never mind that... Found it on my own from blenderartists.com. But you really should at least tell people that there's a reason why the old method is gone. Even that would help a lot so people can start to search new ways to do it rather than insisting going back.

    Still the "workarounds" that there are atm are rather, tedious at least. So if it is possible, it would be much appreciated if a checkbox named "include constraints" would be under the "local" checkbox in the driver variables. Just add a warning to the description...

    ReplyDelete
  3. Cool

    So where does this place the 'script' constraint under 'Add Constraints'? That slot seems somewhat redundant.

    ReplyDelete
  4. Great. Have been searching for this in a lot of places. Works great. Thanks for a very nice example.
    Thanks. Regards Hugin

    ReplyDelete