18
$\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$

4 Answers 4

27
$\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$
8
  • $\begingroup$ Right, in which cases do you think it makes sense to use the operator? $\endgroup$
    – p2or
    Apr 21, 2015 at 18:03
  • 2
    $\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, 2015 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, 2015 at 18:09
  • 4
    $\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, 2015 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, 2016 at 1:22
21
$\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$
3
  • $\begingroup$ Or bpy.ops.object.parent_no_inverse_set() $\endgroup$ Mar 1, 2018 at 17:31
  • 3
    $\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$ Feb 27, 2019 at 18:41
  • $\begingroup$ Thanks for the tip @RayMairlot. I updated the answer. $\endgroup$
    – Justas
    Jul 18, 2019 at 20:07
9
$\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$
1
3
$\begingroup$

lucblender answer was helpfull but I got errors with blender 2.83 here's a working code :

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_set(True)
b.select_set(True)     # select the object for the 'parenting'

bpy.context.view_layer.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
$\endgroup$
2
  • 2
    $\begingroup$ Hi. Please don't use the answer option to ask new questions. Instead, ask a new question and post a link to this original question. $\endgroup$ May 18, 2020 at 22:30
  • 4
    $\begingroup$ Hello, it's not a question, it's a fix to the previous answer which is not working anymore in 2.83 $\endgroup$
    – cscholl
    May 19, 2020 at 9:28

You must log in to answer this question.

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