[blender 2.65.0 on win7 64-bit]
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.
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 + dX, selObj.location + dY, selObj.location + dZ]
# don't forget this!
bpy.context.scene.objects.active = actObj
newObj = bpy.context.scene.objects.active
newObj.location = newLoc
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:
|newObj = origObj.duplicate() |
Secondly, as for setting the active object (the object to be duplicated), apparently, writing this isn't enough:
|bpy.context.scene.objects.active = actObj |
You also need this:
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!
you don't need an active object for the duplicate operator, it just has to be selected:
|ob = bpy.data.objects
ob.select = True
the low-level way of duplicating objects is:
|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.:
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
if __name__ == "__main__":
# test call
I'm sitting, waiting, wishing, building Blender in superstition...
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!