24
$\begingroup$

I have been using the Copy Attributes add-on to copy some properties from active object to selected objects. This add-on is not enabled by default and must be explicitly enabled. But its a very useful workflow enhancing tool.

Copy Attributes Add-On in action

There is a limitation though. Not all properties can be copied and even those that can be copied are copied in groups (Its hard-coded in to the add-on).

My question is if there is a built-in feature or any another other way to copy any property from the active object to the selected objects?

$\endgroup$
0
28
$\begingroup$

It appears there are few other options for copying properties.

Built-In Features

  1. Choose the objects to which a property has to be copied (destination)

  2. Then choose the object from which to copy the property (source)

  3. In the Properties panel, RMB RMB on the property and select Copy To Selected.

  4. You can also Press and Hold ALT key and then change the property on active object so that the selected objects also get updated.

In the screenshot, the show_name property on an Cube object is about to be copied to the Lamp and Camera objects.

Copying properties by using the Copy to Selected menu item

enter image description here

Some properties can also be copied using the Object > Make Links menu available via Ctrl + L:

Make links menu

Add-On: System Property Chart

There is an add-on called System Property Chart, which is bundled with Blender but is not enabled by default. After enabling, you can use it like so:

  1. The Property Chart panel is located in the properties panel of the 3D View Editor.
  2. By default, some properties already exist for viewing and editing. You can save presets by clicking the + icon.
  3. If you want more properties you can find the property in the interface and the right click on it and choose Copy Data Path and then paste it in the text area below the presets menu.
  4. The first row displayed is the active object and the rest the selected objects.
  5. By clicking the clipboard icon next to the column text, properties from active object is copied to selected objects.

Note: This panel displays properties of selected objects only. If there is no selection in the viewport, the spreadsheet is not displayed.

System Property Chart Add-On

$\endgroup$
1
  • $\begingroup$ Very helpful. Is there a reason why Ctrl+L is not part of right click option "Copy to Selected"? It's too many options for same thing. $\endgroup$
    – vklidu
    Sep 16 '15 at 15:02
1
$\begingroup$

The Property Chart add-on covers edge-cases which are lacking from the Right Click > Copy to selected and the CTRL + L "Make Links" menu pretty well (eg. copying dimensions or object name) but I find it is a bit limited :

  • One has to know the python attribute name in order to type it in the Properties field.
  • The horizontal + vertical expansion of the panel makes it not well suited for the current use of the N Panel in the 3D viewport editor. It would be awesome as an addition in the new spreadsheet editor though !

This script will add an operator which will list all the properties one can copy from active object to all selected objects. It can be installed as an add-on if put inside a python (.py) file.

import bpy

from bpy.types import(
    Operator,
)

from bpy.props import(
    EnumProperty,
)


bl_info = {
    "name": "Copy ANY Property",
    "blender": (2, 80, 0),
    "category": "Object",
}

def copy_custom_prop(source, target, prop):
    "Copies custom prop from source to target"
    # Make sure the custom props dictionary is initialized (Mainly for empty objects) :
    rna_ui_id = '_RNA_UI'
    if rna_ui_id not in target.keys():
        target[rna_ui_id] = {}

    # Copy custom prop :
    target[prop] = source[prop]
    # Copy the subtype, min, max etc :
    try:
        target[rna_ui_id][prop] = source[rna_ui_id][prop].to_dict()
    except KeyError:
        # Custom prop is API defined. Don't mess with it.
        pass
    # "overridable" is a "special" attribute :
    target.property_overridable_library_set(
        f'["{prop}"]', source.is_property_overridable_library(f'["{prop}"]'))


def retrieve_props(self, context):
    """Retrieves all non read-only properties formatted to populate an EnumProperty"""
    retrieve_props.no_copy = "__DO_NOT_COPY_ANY_PROP"
    items = []
    ao = context.active_object

    [items.append((p.identifier, p.name, p.description))
        for p in ao.bl_rna.properties
        if not p.is_readonly]
    if '_RNA_UI' in ao.keys():
        [items.append((p, p, p))
            for p in ao.keys()
            if not p.startswith('_')  # Make sure it's not "private"
            if p in ao['_RNA_UI'].keys()  # Make sure it's not API defined
         ]
    items.sort(key=lambda e: e[1])
    items.insert(0, (retrieve_props.no_copy, "NONE", "Do not copy any property"))
    return items


class GU_OT_property_copy(Operator):
    """Copy Property"""
    bl_idname = "property.copy"
    bl_label = "Copy Any Property from active to selected"
    bl_settings = {'INTERNAL'}
    bl_options = {'UNDO', 'REGISTER'}

    prop_copy: EnumProperty(
        name="Copy Property",
        description="Choose which property to copy from active to selected.\n Silently passes if target object doesn't have property",
        items=retrieve_props,)

    @ classmethod
    def poll(cls, context):
        return context.active_object is not None and len(context.selected_objects) > 0

    def invoke(self, context, event):
        # Reset prop to prevent random mishaps :
        self.prop_copy = retrieve_props.no_copy
        return context.window_manager.invoke_props_dialog(self)

    def execute(self, context):
        if self.prop_copy == retrieve_props.no_copy:
            return {"FINISHED"}
        ao = context.active_object
        if self.prop_copy in ao.keys():
            for obj in context.selected_objects:
                if ao == obj:
                    continue
                copy_custom_prop(ao, obj, self.prop_copy)
        else:
            value = getattr(ao, self.prop_copy, None)
            for obj in context.selected_objects:
                if ao == obj:
                    continue
                try:
                    setattr(obj, self.prop_copy, value)
                except TypeError as e:
                    # Edge case : Only empties can have an instance_type of 'COLLECTION'
                    print(f"Could not copy property from {ao.name} to {obj.name}\n{e}")
                except AttributeError as e:
                    # For some reason some properties are readonly despite is_readonly being False
                    print(f"Could not copy property from {ao.name} to {obj.name}\n{e}")

        return {"FINISHED"}

def draw_props_links(self, context):
    self.layout.operator(GU_OT_property_copy.bl_idname, text="Copy ANY Property")

def register():
    bpy.utils.register_class(GU_OT_property_copy)
    bpy.types.VIEW3D_MT_make_links.append(draw_props_links)

def unregister():
    bpy.types.VIEW3D_MT_make_links.remove(draw_props_links)
    bpy.utils.unregister_class(GU_OT_property_copy)
    
if __name__ == "__main__":
    register()

It adds the operator to the CTRL + L "Make Links" menu :

enter image description here

$\endgroup$
6
  • 1
    $\begingroup$ Nice one. Would make a small change and calc value = getattr(context.active_object, self.prop_copy, None) first, then if it is None and in keys it's a custom prop, (consider copying over RNA_UI details) and not currently defined via bpy.types.Foo.bar = bpy.props... and unset. This will (_theoretically) allow for update, set, get methods on property to be thrown. $\endgroup$
    – batFINGER
    Jul 23 '21 at 14:07
  • $\begingroup$ @batFINGER thanks for the feedback ! I'll take a look :) $\endgroup$
    – Gorgious
    Jul 23 '21 at 21:24
  • $\begingroup$ @batFINGER I've made some changes, hopefully it covers most edge cases ! I have not tested what happens with eg CollectionProperty copying but I think? it shouldn't break things. I am a bit stumped though by use_mesh_mirror_z and y which are not readonly according to is_readonly but throws an exception when copied... Curisouly it doesn't complain on X axis and it doesn't throw exception on mesh object > mesh object but it does on mesh object > other type $\endgroup$
    – Gorgious
    Jul 24 '21 at 10:04
  • $\begingroup$ Not sure where use_mesh_mirror is. $\endgroup$
    – batFINGER
    Jul 24 '21 at 13:35
  • $\begingroup$ Wondered, using a pre-historic version. 2.91 mostly atm. Any way related to self.data.use_mirror_x if self is a mesh object? $\endgroup$
    – batFINGER
    Jul 24 '21 at 14:01

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.