0
$\begingroup$

I have a rigged and animated character with over 100 bones. Don't ask why, but I want to add the "Noise" F-Curve Modifier for the rotation and scale channels (F-Curves) of every single one of these bones. Selecting every single F-Curve, adding the F-Curve Modifier and specifying the settings for every single F-Curve of every single bone is a VERY time-consuming and tedious process. How do I do as effectively as possible?

$\endgroup$
2
$\begingroup$

With a script

These things are most easily done with a script.

The script below, looks for all pose bone fcurves, all posebone scale fcurves and all posebone quaternion fcurves and assigns them to variables pbfcurves, scalefcurves and rotfcurves respectively. Note if you are using Euler rotation change to rotation_quaternion to rotation_euler

If you know the action is named "Snurfball" then uncomment and edit #action = bpy.data.actions["Running"] to

action = bpy.data.actions["Snurfball"]

Uncomment, (delete #) to remove all modifiers from all posebone fcurves

demod(pbfcurves)    

To add strength 2 noise to all scale fcurves

noise(scalefcurves, strength=2.0)

To add strength 2, depth 4 noise to all quaternions

noise(rotfcurves, strength=2, depth=4)

Make your edits, Select the rig object and run script. A single CtrlZ generally does a good job undoing, but as always: please backup first.

import bpy

context = bpy.context
ob = context.object
action = ob.animation_data.action
#action = bpy.data.actions["Running"]

def demod(fcurves):
    fcs = fcurves[:]
    while fcs:
        fcurves.remove(fcs.pop())

def noise(fcurves, scale=1.0, strength=1, depth=0, phase=1.0, offset=0.0):
    for fc in fcurves:
        m = fc.modifiers.new(type='NOISE')
        m.scale = scale
        m.strength = strength
        m.depth = depth
        m.phase = phase
        m.offset = offset


pbfcurves = [fc for fc in action.fcurves if fc.data_path.startswith("pose.bones")]


scalefcurves = [fc for fc in pbfcurves if fc.data_path.endswith(".scale")]

rotfcurves = [fc for fc in pbfcurves if fc.data_path.endswith(".rotation_quaternion")]

# clean modifiers from all fcurves

#demod(pbfcurves)

# add noise to all scale fcurves

noise(scalefcurves, scale=0.4, strength=2.0, offset=-5)

Further to this if you are adventurous, can do this from the python console. Here I've found all the fcurves with a datapath, converted to lower case that contains the word "arm"

>>> action = D.actions['metarigAction']
>>> armfcurves = [fc for fc in action.fcurves if fc.data_path.lower().find("arm") > -1]
>>> for fc in armfcurves:
...     fc.data_path, fc.array_index
...     
('pose.bones["upper_arm.L"].location', 0)
('pose.bones["upper_arm.L"].location', 1)
('pose.bones["upper_arm.L"].location', 2)
('pose.bones["upper_arm.L"].rotation_quaternion', 0)
('pose.bones["upper_arm.L"].rotation_quaternion', 1)
('pose.bones["upper_arm.L"].rotation_quaternion', 2)
('pose.bones["upper_arm.L"].rotation_quaternion', 3)
('pose.bones["upper_arm.L"].scale', 0)
('pose.bones["upper_arm.L"].scale', 1)
('pose.bones["upper_arm.L"].scale', 2)
('pose.bones["forearm.L"].location', 0)
('pose.bones["forearm.L"].location', 1)

All location.y arm fcurves

>>> armfcurves = [fc for fc in action.fcurves if fc.data_path.lower().find("arm") > -1 and fc.array_index == 1 and fc.data_path.endswith("location")]
>>> for fc in armfcurves:
...     fc.data_path, fc.array_index
...     
('pose.bones["upper_arm.L"].location', 1)
('pose.bones["forearm.L"].location', 1)
('pose.bones["upper_arm.R"].location', 1)
('pose.bones["forearm.R"].location', 1)

>>> 
$\endgroup$
  • $\begingroup$ Thank you batFINGER, I do really appreciate it! However, as a Blender beginner, I find it very intimidating when I ask for something that (according to me) should be as simple as copying the modifier from one F-Curve (CMD+C), selecting all the other F-Curves (CMD+A) and pasting (CMD+V). It's because of simple things like these, where Blender shows how "not-user-friendly-at-all" it is, that makes people flee away from Blender to other alternatives such as Cinema 4D, 3DS Max, and Maya. $\endgroup$ – StillerMauritz Dec 27 '19 at 18:17
  • $\begingroup$ There maybe a copy and paste solution. Not so much a mousketeer. sure if there is someone will offer as an answer. I like the logic of scripting, and for me a script like above is easy to slap together or process in the python console. Doesn't matter how easy you try and make it for some... it's just toooooooo hard. As for all those fleeing... DILLIGAF. $\endgroup$ – batFINGER Dec 27 '19 at 18:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.