11
$\begingroup$

I have two objects each of them hold in a variable. Now I want to parent them so object A is the parent of object B. How can I do this using Blender's Python API? I know there is a parent_set operator in Blender but I don't know how to set up the selection in the scene via Python so I just have to call

bpy.ops.object.parent_set(...)

It looks like there is a parent attribute on objects which I can use like

b.parent = a

How can I use that?

$\endgroup$
15
$\begingroup$

Avoid all the dancing around using bpy.ops and that setting selection and active. Most of those bpy.ops commands are meant to be called by the UI once a user clicks a ' parent to x ' button , etc.

You are on the right path by using the .parent attribute. All you really need are the names or references to the objects and you can parent much, much simpler.

import bpy

objects = bpy.data.objects
a = objects['Cube']
b = objects['Cube.001']
b.parent = a

There are times using a bpy.ops is a reasonable solution, but in this case the lower level solution of using b.parent = a is functionally equivalent and fewer lines of code.

Edit

In the comments of this answer we discuss how to decide when to use a member of bpy.ops, but CoDEmanX has a fine clarification here

$\endgroup$
  • $\begingroup$ Right, in which cases do you think it makes sense to use the operator? $\endgroup$ – p2or Apr 21 '15 at 18:03
  • 1
    $\begingroup$ When there is no low level alternative, or the low level alternative is very involved. Then it's a showdown between how much effort you want to put into getting the context right for the operators and time spent writing the low level solution. $\endgroup$ – zeffii Apr 21 '15 at 18:06
  • 1
    $\begingroup$ @poor, for instance we see a tonne of people trying to bake sound using the operato (and a lot of ugly code trying to set context) r, it would make sense to have that as a separate util function or even command line tool, If people are really serious they would use that instead to bake the graph $\endgroup$ – zeffii Apr 21 '15 at 18:09
  • 2
    $\begingroup$ This doesn't not behave equally to bpy.ops.object.parent_set. When using the bpy.ops API, everything is as expected. However, when setting a.parent = b, a strange transformation is applied to the child object. Any idea? $\endgroup$ – schlamar May 22 '15 at 11:44
  • 1
    $\begingroup$ @schlamar did you ask about this problem with low-level parenting? The transformation added is very annoying and there should be some simple method of avoiding it. Please let me know where can I find this solution. $\endgroup$ – piotao Apr 20 '16 at 1:22
7
$\begingroup$

If the child object moves after setting the parent, use the following to move it back:

# After both parent and child have been link()ed to the scene:
childObject.parent = parentObject
childObject.matrix_parent_inverse = parentObject.matrix_world.inverted()

To unparent and keep the child object location (without using operators):

parented_wm = childObject.matrix_world.copy()
childObject.parent = None
childObject.matrix_world = parented_wm

As mentioned in the comments, the matrices need to be up to date, which can be done with bpy.context.scene.update()

$\endgroup$
  • $\begingroup$ Or bpy.ops.object.parent_no_inverse_set() $\endgroup$ – foobarbecue Mar 1 '18 at 17:31
  • 2
    $\begingroup$ One thing to note, that wasn't immediately obvious (but maybe should have been), is that if you have also added the objects childObject and parentObject programatically you may have to perform a bpy.context.scene.update() prior to this answer's code before you will be able to access the correct matrix values. $\endgroup$ – Ray Mairlot Feb 27 at 18:41
  • $\begingroup$ Thanks for the tip @RayMairlot. I updated the answer. $\endgroup$ – Justas Jul 18 at 20:07
5
$\begingroup$

You can use b.parent = a but you can of course use :

bpy.ops.object.parent_set()

I made a little code for this:

import bpy

a = bpy.data.objects['Cube']
b = bpy.data.objects['Cube.001']

bpy.ops.object.select_all(action='DESELECT') #deselect all object

a.select = True
b.select = True     #select the object for the 'parenting'

bpy.context.scene.objects.active = a    #the active object will be the parent of all selected object

bpy.ops.object.parent_set()

#Now The parent of b is a

For setting the parameter of the parent_set you can go to the blender python api. Blender also give you this in the python console :

parent_set()
bpy.ops.object.parent_set(type='OBJECT', xmirror=False, keep_transform=False)
$\endgroup$

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.