# How do I set an object parent without moving the child location as relative

Lets say I have an object relationship

- first
- second
- third


And I have absolute position/location/coordinates

first: 1.0, 0.0, 0.0
second: 0.0, 1.0, 0.0
third: 0.0, 0.0, 1.0


I read that we're supposed to use magic setter named matrix_parent_invert, like so child.matrix_parent_inverse = parent.matrix_world.inverted()

so as follows is a quick script to do that, and my object positions remain relative with various order of operations of the following"

import bpy

first = bpy.data.objects.new('first', None)
first.location = (1., 0., 0.)

snd = bpy.data.objects.new('second', None)
snd.location = (0., 1., 0.)
snd.parent = first
snd.matrix_parent_inverse = first.matrix_world.inverted()

trd = bpy.data.objects.new('third', None)
trd.location = (0., 0., 1.)
trd.parent = snd
trd.matrix_parent_inverse = snd.matrix_world.inverted()

expectation
reality

Since updating the View Layer can be too slow, here's how you would do it in a more performant way:

import bpy
from mathutils import Euler, Matrix, Vector

first = bpy.data.objects.new('first', None)
location = (1, 0, 0)
rotation = Euler((0, 0,0))
scale = Vector((1, 1, 1))  # Vector needed because of to_4d()
T = Matrix.Translation(location)
R = rotation.to_matrix().to_4x4()
S = Matrix.Diagonal(scale.to_4d())
M = T @ R @ S
first.matrix_world = M  # just using T would work but I wanted to show how to deal with rotations and scale

snd = bpy.data.objects.new('second', None)
snd.parent = first
snd.matrix_world = Matrix.Translation((0, 1, 0))

trd = bpy.data.objects.new('third', None)
trd.parent = snd
trd.matrix_world = Matrix.Translation((0, 0, 1))

• oh wow, you were not kidding about updating the view layer being slow. 3s -> 183s for a few thousand parents. oof Commented Jun 4, 2022 at 5:20

When you parent a object from interface, matrix_local and matrix_parent_inverse of the child object will change.

But setting the parent from a script without using bpy.ops, it doesn't change matrix_local and matrix_parent_inverse. So, you need to change them manually.

import bpy

first = bpy.data.objects.new('first', None)
first.location = (1., 0., 0.)

snd = bpy.data.objects.new('second', None)
snd.location = (0., 1., 0.)
snd.parent = first
bpy.context.view_layer.update() # <--- important
snd.matrix_parent_inverse = first.matrix_world.inverted()