Preserving Child Transform After Removing Parent

Hey, i’m having trouble understanding the math behind such an operation, and was wondering if anyone could help. Basically what I’m trying to do is keep the child in exactly the same position, orientation and scale when it is removed as when the parent influences it, as when removed the child will lose all the transformation operations it inherited from the parent.

I can preserve the scale and the translation, but the rotation I can’t currently preserve as it is relative to the parent. Rotating the parent rotates the child in an entirely different way then if i were to just rotate the child by the same amount because of the object’s location and the parent’s own local axis, and i’m rather stumped on how to perform the necessary conversions. Don’t suppose anyone can help? D:

1 Like

Use matrix world… will keep location / rotation / scale all for you in one.


import bpy


for a in bpy.context.selected_objects:
    if a.parent:
        matrixcopy = a.matrix_world.copy()
        a.parent = None
        a.matrix_world = matrixcopy

2 Likes

Sorry for not responding sooner, this worked perfectly. I just copy the matrix of the child before clearing the parent, and restore it after ^-^. This definition also preserves the child’s location using the 3D cursor.


def ClearParent(child):
    # Prepare the 3D cursor so it can keep the object in it's current location
    # After it stops being a component
    cursor_loc = bpy.data.scenes[bpy.context.scene.name].cursor_location
    previous_cursor_loc = [cursor_loc[0], cursor_loc[1], cursor_loc[2]]
    
    # Save the transform matrix before de-parenting
    matrixcopy = child.matrix_world.copy()
        
    # Move the cursor to the selected object
    FocusObject(child.name)
    bpy.ops.view3D.snap_cursor_to_selected()
    
    # Clear the parent
    bpy.ops.object.select_all(action='DESELECT')
    child.select = True
    bpy.ops.object.parent_clear()
    
    # Now move the object
    bpy.ops.view3D.snap_selected_to_cursor()
    
    # Restore the original cursor location and matrix
    bpy.data.scenes[bpy.context.scene.name].cursor_location = previous_cursor_loc
    child.matrix_world = matrixcopy

I am pretty sure you can reduce this code to the following:


def ClearParent(child):    
    # Save the transform matrix before de-parenting
    matrixcopy = child.matrix_world.copy()
    
    # Clear the parent
    child.parent = None
        
    # Restore childs location / rotation / scale
    child.matrix_world = matrixcopy

One thing i have learnt over the years of python coding for blender, is that the bpy.ops commands are slow… if there is an alternative way to do it, i would suggest going with that (ie setting child.parent = None instead of bpy.ops.object.parent_clear() )

4 Likes

I am a total novice and tried pasting the above code into the Python console with no success, can you please help?

It’s working well with Blender 2.93 in September 2021!!
I wrote a function that performs both parenting and un-parenting with a little edit.

import bpy
D = bpy.data

def parent(child,parent):
    matrixcopy = child.matrix_world.copy()
    if parent == None:
        child.parent = None
    else:
        child.parent = parent
    child.matrix_world = matrixcopy

# un-parent
parent(D.objects["child_1"],None)

# parent
parent(D.objects["child_2"],D.objects["parent"])
2 Likes