Understanding parent Transforms

Hi Guys,

I’m having some pretty heavy confusion over how exactly parenting works in relation to position/rotation/scale. I discovered pretty early that depending on how you attach a GameObject to another changes how it’s own transform is affected. From what I see there’s 4 ways to attach a GameObject. All with different effects:

  • Drag and Drop a GameObject onto Another - When you do this the object will stay in the same position as it was in the world, however it’s localPosition, localScale, and localRotation will change to keep that object in the same position. All parent movements and transform changes affect the child.
  • Set Parent by Calling in Script ‘transform.parent = someObject.transform’ - When you do this, the object’s localScale, localRotation, and localPosition will stay the same relative to the parent. However that means the world position will change. It looks like the object teleports into a strange position and rotation, and possibly skew, depending on the parent’s transform.
  • Set Parent by Calling ‘transform.SetParent(someTransform, false)’ - This will keep the same world position, like dragging and dropping. However it bears no semblance to the first option, in the sense that when the parent is transformed in any way, the child will not follow suit. Ever.
  • Set Parent by Calling ‘transform.SetParent(someTransform, true)’ - Exactly the same as 2.

I just need to check that this is correct. Secondly. Supposing you want to do the equivalent of the first one; dragging and dropping the GameObject. Where the real world position/rotation/scale is kept the same, however the child’s relative local position/scale/rotation changes. Allowing the parent’s transform to still affect the child. I’ve noticed by doing transform.SetParent() does not perform this task.

People’s thoughts on this?

I want to have a number of transform options, moving forward with Unity projects. For example it’d be good to allow a specific aspect of a parent’s transform to affect the child. Like only the position, or only the rotation, or the scale. Alternately, to allow the parenting to keep the same world position for the child, changing the relative local’s of the child according to the parent’s transform, WHILE allowing the object to follow the parent’s transform changes from then on. Does anyone have any advice on how to change this?

2 Likes

2 is wrong. Setting the parent property of a transform will not in any way move or scale the transform.

3 is wrong. Using the false option here is the only option that causes the child to move.

4 is wrong - in the sense that yes, it’s the same thing as 2, but you’re wrong about 2.

Note that all information about “what does setting the parent do” goes straight out the window if you’re talking about UI elements on a Canvas - that world has it’s own rules.

Setting transform A as the parent of transform B does two things:

Every change in transform A will also affect transform B, in a 1/1 fashion. This means moving, rotating and scaling.
Every change in transform B’s local properties (localPosition, localRotation, localScale) will be relative to those properties in transform A

Nothing more.

the SetParent(someTransform, false) call is the odd child out here. From what I can see, setParent works like this:

//Note that this is a method on Transfrom, so it's not transfrom.parent, but this.parent, etc.
//Also, this probably actually happens by manipulating the 4x4 matrix representing the transform, so this is the functionality, not the implementation
public void SetParent(Transform parent, bool worldPositionStays) {
    if(worldPositionStays) {
        this.parent = parent;
        return;
    }
    
    Vector3 oldLocalPosition = localPosition;
    Vector3 oldLocalRotation = localRotation;
    Vector3 oldLocalScale = localScale;
    this.parent = parent;
    localPosition = oldLocalPosition;
    localRotation = oldLocalRotation;
    localScale = oldLocalScale;
}

The interesting part is that with the false argument, the object’s relative position to whatever their old parent was will stay.

Here’s a demonstration. We have three shapes:

We call greenTransform.setParent(blueTransform, false); If the green transform is already a child of the red transform, the result is this:

If it’s not a child of anything, this is the result instead:

The world position of the green transform (before setting the parent) was (7, 1, 0). If we move all of the objects up 5 on the y-axis, the end result becomes this instead:

Remember, if there’s no parent object, the local transform values is the same as the world values. Or rather, the local values are relative to the zero-vector for both position, scale and rotation.

You should play around with this for some proper understanding, here’s the script I tested this with:

public enum Mode {
    parentProperty,
    setParentFalse,
    setParentTrue
}

public Mode mode;
public Transform child;

private void Start() {
    switch (mode) {
        case Mode.parentProperty:
            child.parent = transform;
            break;
        case Mode.setParentFalse:
            child.SetParent(transform, false);
            break;
        default:
            child.SetParent(transform, true);
            break;
    }
}

Feel free to ask questions!

3 Likes

Thanks a lot for taking the time to properly answer @Baste .

Okay what you’re saying makes sense to me. So how would you handle giving an object a parent, which previously had no parent. Making sure that any changes of the parent transform does change the child’s transform like normal, but when you first set the parent as the parent, the object stays in the same world position. Like in your example, when you set the green’s parent from red to blue, it moves. How would you do it so that it doesn’t change position at first, but any actions after that point (like moving the blue along the x-axis for example), would also move the green?

All of my examples are uses of SetParent(…, false), which is the only instance where setting the parent would move the obhect. Just doing:

transform.parent = someTransform

does exactly what you’re describing. If something else is happening, there’s a bug somewhere else in your code.

Oh, so SetParent(,false) keeps the original position… but then after that it copy’s the parent’s transform’s changes?

No. SetParent(,false) keeps the original local position in relation to the parent. So the values in the inspector will be unchanged, but the actual world position, rotation and scale (what you see in the game) will change.

Remember - if the inspector says that something is at x:3, that means that it’s 3 away from it’s parent on the x-axis, where 3 is scaled to the parent’s x-scale. When you do a normal transform.position =, the values in the inspector changes, as what they’re relative to changes. The world values stays the same.

Another way to think of this is:
transform.SetParent(,true): Keeps the original transform.position. This is the same as setting transfom.parent.
transform.SetParent(,false): Keeps the original transform.localPosition

the same goes for rotation/localrotation and scale/localScale

1 Like