World space positioning changes after parent is removed

Hi, I am facing a strange issue, or possibly I am missing something basic, so some help would be much appreciated to pinpoint the issue, or to improve my understanding of how Unity works.

Actually the problem I need to solve is pretty easy: I have a bunch of GameObjects, which are randomly generated to fill a specific flat shape and then I need to rotate all of those objects to align with a plane in 3D.

My solution: once the objects are generated I add them to a new temporary parent, rotate the parent (at this point everything is actually aligned perfectly) and then I wanted to remove the parent and scrap it. And when I do this the objects loose their perfect positioning. I also added TrailRenderers and can see in the editor how the object moves when manually removed from parent.

Here is the code:

// Create temporary object and fill the generated objects as childs
GameObject go = new GameObject("temp");
go.transform.position = transformToAlignTo.position;
go.transform.rotation = Quaternion.identity;
foreach (GameObject obj in generatedObjects) {
    obj.transform.parent = go.transform;
}

// This is the alignment I actually need to perform
go.transform.rotation = transformToAlignTo.rotation;

// At this point everything is aligned perfectly, if I comment the code below it also stays fine, however i need to remove the parent object

foreach (GameObject obj in generatedObjects) {
    obj.transform.SetParent(null, true);
}
Destroy(go);

I thought SetParent(null, true) should keep the current global position? What am I missing?

How much did they move? If it’s tiny that’s just how floating point precision works.

“Think of [floating point] as JPEG of numbers.” - orionsyndrome on the Unity3D Forums

When you parent/deparent you “grind” all the coordinates through dozens of multiplies and additions in various Transform matrices, so the numbers will almost never be perfect.

Floating (float) point imprecision:

Never test floating point (float) quantities for equality / inequality. Here’s why:

https://starmanta.gitbooks.io/unitytipsredux/content/floating-point.html

https://discussions.unity.com/t/851400/4

https://discussions.unity.com/t/843503/4

Literal float / double issues:

https://discussions.unity.com/t/836836/2

Add this link to your Kurt-n-Paste, Kurt.

https://www.h-schmidt.net/FloatConverter/IEEE754.html

2 Likes

Thanks for the fast reply. I should not have used the word “perfect”, it raises the expectations bar.

The objects move quite a lot actually. Is a bit hard to track how much exactly, but if applied on all generated objects the whole orientation becomes wrong. This is how I saw the issue in a first place.

Here is a screenshot from the editor - the “perfect” positioning when still with parent:

And when the parent is removed:

Just setting to null, as in the code above. Yes, the scale is 1/1/1.
I mean the fix is pretty simple, but either a) looks like a bug, or b) I am missing something pretty basic

If you Debug.Log the position before and after, do the values read differently?

One work around would be to cache the world position of each of these objects and apply that position after you’ve de-parented it.

Yes, this is exactly what I meant with easy fix - it also works as expected. However, I still don’t understand why the code without cashing/storing the position is not working.

So, in short:

Does not work - position is changed quite a lot:

foreach (GameObject obj in generatedObjects) {
    obj.transform.SetParent(null, true);
}

Works:

foreach (GameObject obj in generatedObjects) {
    Vector3 tempPosition = obj.transform.position;
    obj.transform.SetParent(null, true);
    obj.transform.position = tempPosition;
}
1 Like

My opinion is that the local transform of the child is not affected by parent’s transform permanently. Once you de-parent you lose the displacement, rotation, and scale inherited from the parent. Theoretically. Since I’m relatively new to Unity, I’m open to being wrong about this.

I’m guessing de-parenting changes the world coordinates of the child. That’s why caching the transform works. Otherwise it would not.

So obj.transform.position == “parent position” + “local position”. But after de-parenting obj.transform.position == “local position” == “world position”.

Yeah, looks that way. Which is confusing, since the API says otherwise: the last parameter true claims the global position would be preserved…
https://docs.unity3d.com/ScriptReference/Transform.SetParent.html

1 Like

Sorry, it appears I’m wrong. I’m doing some parenting, transforming and de-parenting, and i’m not experiencing any distortion like I thought. I was starting to think about child missiles on a parent ship, and how de-parenting should work correctly for that, and would be wrong otherwise.

Well, to me that just looks like you’r choosen “pivot” point is not really inside the flat plane you want to “rotate”. As a consequence your plane does not only rotate but would be shifted as it essentially rotates at a certain distance from the pivot point. Can you actually visualize the position of your transformToAlignTo ?

If you just wanted to rotate all those objects relative to its own plane, you would have to calculate the center point of that plane by averaging the positions of the objects inside that plane and use that as the rotation pivot.

If the green lines in the second picture of the post No 4 represents the actual displacements of each object, the pivot seems to be on top of the plane and slightly to the left. So the plane simply hinges around that point.

You may check the localPositions of your objects while they are parented to the object.

If that’s not the case, it would help if you could be more specific about how you generated those objects in the first place and as I just said, tell us where that “transformToAlignTo” is located.

Yes, you are right - the rotation point is definitely not on the rotated plane. The visualization of transformToAlignTo is already in the screenshots from post Nr 4 - it is the blue “ring”. To be precise - all to-be-aligned objects (the stones/asteroids) are put into an empty object having same position as the blue ring, then I set the rotation also to the same. Scale is 1/1/1, while this is not the case with the blue ring. The result of all this is on the first image (without any green lines) - the positioning as I need it. Second image is when I remove the parent - via the API or manually (without the workaround, with it the positioning remains as it should).

So yes, the actual displacement is not via the position, but via the rotation. But still, the API sounds like it would take care of this as well…

hey everyone. A bit late :), but I’ve just encountered this problem and can’t seem to find the solution did you guys find any solution or …

Hi, the solution is pretty easy - just store the position, as shown above.
This is not explaining why the issue occurs in a first place, imo the API is pretty clear in this regards and transform.SetParent(null, true) should keep the world position, which is not the case. Weird, but I moved on.