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?
4 Answers
You don't need a script, this is built into the f-curve modifier copy/paste feature. Just copy the modifier using the button next to it, then select all the curves you want to paste it to and hit the paste button. Then make sure "Only Active" is unchecked.
Posted some screenshots here:
How to copy F-Curve Modifier(s) from one object to multiple objects in Blender 2.8x
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)
>>>
-
1$\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$ Commented Dec 27, 2019 at 18:17
In addition to the copy and paste, and the scripting methods, Samy Tichadou (tonton) wrote an add-on, FCurve Helper, to help manage F-Curve modifiers. It allows the user to filter between bone and object animations, create a modifier of a given type for each selected curve, batch update existing modifiers, or delete them.
It is extremely useful to quickly adjust stepped animation settings while blocking a shot, or get rid of all the modifiers once you don’t need them.
Fasty's answer is probably the best solution if you're using Blender 2.8+, but for users still using older versions, here's an alternate approach as suggested by naman.khare. It doesn't copy user-adjusted settings, but if someone were looking to assign the modifiers en masse with the vanilla settings, this could be very helpful (admittedly, probably more helpful for something like the "Cycles" modifier):