Duplicating active object at selected object positions

Scripting in Blender with Python, and working on the API

Moderators: jesterKing, stiv

guy lateur
Posts: 10
Joined: Sun May 27, 2012 11:00 am

Duplicating active object at selected object positions

Postby guy lateur » Thu Jan 03, 2013 4:05 pm

[blender 2.65.0 on win7 64-bit]

Hi all,

let's say i have 5 spheres in my scene, and I want to replace them all with cubes. I'd like to be able to select all the spheres, and then the cube, and run a script which takes care of this.

Ideally, I'd probably only want to relink the object data of the selected objects. Unfortunately, I don't know how to do that (or if this is possible at all). Does anyone have any idea?

What I've done for now is to duplicate the cube 5 times and move these duplicates to the positions of the other selected objects. I then delete the original objects. It took me quite a while to get this right, so I thought I'd share my script here.

Code: Select all

def CopyAt(dX = 0.0, dY = 0.0, dZ = 0.0, showNewNames=False):
    bpy.ops.object.mode_set(mode = 'OBJECT')
    actObj = bpy.context.scene.objects.active
    if actObj == None:
        raise Exception("no active object found")
    actObjName = actObj.name
    print("--", "actObjName: ", actObjName)

    listNames = list()
    for selObj in bpy.context.selected_objects:
        if (selObj == actObj):
        newLoc = [selObj.location[0] + dX, selObj.location[1] + dY, selObj.location[2] + dZ]
        bpy.ops.object.select_pattern(pattern=actObjName, extend=False)
        # don't forget this!
        bpy.context.scene.objects.active = actObj

        newObj = bpy.context.scene.objects.active
        newObj.location = newLoc
        if showNewNames:
    if showNewNames:
        print("--", "listNames:")

A few things to note. First of all: is it possible to duplicate an object by reference? So, instead if having to alter the context (selection/active object), I'd like something like this:

Code: Select all

newObj =  origObj.duplicate()

Secondly, as for setting the active object (the object to be duplicated), apparently, writing this isn't enough:

Code: Select all

bpy.context.scene.objects.active = actObj

You also need this:

Code: Select all

bpy.ops.object.select_pattern(pattern=actObjName, extend=False)

I would have thought that deselecting everything and then selecting a single object would also set the active object to this selected object. This doesn't seem to happen, so you also explicitely have to set the active object. Is this by design? Am I missing something?

Finally, seeing as the selection changes within each pass through the for-loop, I had anticipated that the for-loop would not work as it is written above. But to my surprise, it does work. Is this because I'm looping through a (temporary) copy of the list of selected objects?

Anyway, I'm glad I finally got it to work. Still, any reflections on any or all of the above would be appreciated!

best regards,

Posts: 894
Joined: Sun Apr 05, 2009 7:42 pm
Location: Germany

Postby CoDEmanX » Thu Jan 03, 2013 8:04 pm

you don't need an active object for the duplicate operator, it just has to be selected:

Code: Select all

ob = bpy.data.objects[0]
ob.select = True

the low-level way of duplicating objects is:

Code: Select all

ob = obj.copy() # duplicate linked
ob.data = obj.data.copy() # optional: make this a real duplicate (not linked)
bpy.context.scene.objects.link(ob) # add to scene

ob.location.y += 5

if you wanna relink objects only, you could do e.g.:

Code: Select all

import bpy

class SimpleOperator(bpy.types.Operator):
    bl_idname = "object.simple_operator"
    bl_label = "Simple Object Operator"

    def poll(cls, context):
        return context.active_object is not None and \
               len(context.selected_objects) > 1

    def execute(self, context):
        act = context.active_object
        sel = context.selected_objects
        for ob in sel:
            if ob == act:
            ob.data = act.data
        return {'FINISHED'}

def register():

def unregister():

if __name__ == "__main__":

    # test call
I'm sitting, waiting, wishing, building Blender in superstition...

guy lateur
Posts: 10
Joined: Sun May 27, 2012 11:00 am

Postby guy lateur » Thu Jan 03, 2013 9:27 pm

Alright, thank you CoDEmanX, for a very swift and clear reply! I only really needed relinking the data, which works perfectly as you described it.

It's a lot less resource hungry this way, and much more flexible, since I had some (array-) modifiers applied to the original objects (the 5 spheres). After relinking only the data, I still have fulll control over my modifiers, which is very nice indeed!


Return to “Python”

Who is online

Users browsing this forum: No registered users and 1 guest