1
$\begingroup$

I'm trying to place a copy of an action onto another object. My code seems to work, except when I try to set the action on the new object. (I'm copying the animated viewport display rgb values, from the material of source_cube to the viewport display colors of target_cube)

The error that eludes me is: Error: Could not set action 'the_new_action.002' onto ID 'OBtarget', as it does not have suitably rooted paths for this purpose

Any clues what I'm missing here?

import bpy

# Gets the action from material of object
def get_material_action(object):
    # current_object, material, action
    current_material = object.material_slots[0].material
    action = current_material.animation_data.action
    print ('getter: found:', action.name)
    return action
    
    #print ('current object', current_object.name)
    #print ('current material', current_material.name)
    #print ('current material action', current_material_action.name)

# Copies the action
def copy_action(action):
    current_action = bpy.data.actions.get(action)
    
    ### Create a copy of that action
    new_action = current_action.copy()
    new_action.name = 'the_new_action'
    print ('copier made: ', new_action.name)
    return new_action
    
# Sets the action on material of object    
def set_action(object, new_action):
    current_material = object.material_slots[0].material
    # create empty action
    object.animation_data_create()
    object.animation_data.action = bpy.data.actions.get(new_action.name)


# Define source and target objects
source_object = bpy.data.objects['source']
target_object = bpy.data.objects['target']


# get current action from source 
# Then copy and name it
# Then set action on target
source_action = get_material_action(source_object)    
new_action = copy_action(source_action.name)
set_action(target_object, new_action)



print ('done')
$\endgroup$

1 Answer 1

2
$\begingroup$

Action ID root

The error is informing of attempting to link an action which expects to be for a material onto an object.

The created action from keyframing property of a material has 'MATERIAL' set as its ID root.

ID root

Type of ID block that action can be used on - DO NOT CHANGE UNLESS YOU KNOW WHAT YOU ARE DOING

Py console example

>>> source = C.object
>>> mat = source.active_material
>>> mat
bpy.data.materials['Material']

>>> action = mat.animation_data.action
>>> action
bpy.data.actions['MaterialAction']

>>> action.id_root
'MATERIAL'

An object's action would expect this value to be 'OBJECT'.

Material action -> Object action

Example, material action with only keyframes for diffuse_color of material

>>> for f in action.fcurves:
...     f.data_path, f.array_index
...     
('diffuse_color', 0)
('diffuse_color', 1)
('diffuse_color', 2)
('diffuse_color', 3)

the data path from an object to "viewport color" is color

At the very simplest, could as above copy the action, iterate over the fcurves, make our necessary datapath change, set object id root and assign to the object.

action = action.copy()
for fc in action.fcurves:
    fc.data_path.replace("diffuse_color", "color")
action.id_root = 'OBJECT' 

Context

Customary in blender is to use the active object as a source and other selected objects as the destination.

source = context.object
targets = context.selected_objects
targets.remove(source)

for operators, having a poll method removes the need to test for context.object being None

$\endgroup$
1
  • 1
    $\begingroup$ worked like a charm when I set it up that way. Thank you batFINGER $\endgroup$
    – Henk Kok
    Commented Sep 21, 2020 at 10:02

You must log in to answer this question.

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