- Home /
How to avoid changing transform.parent?
Given the following game object hierarchy in Unity 3D:
"Super Parent" scale (2, 34, 5), rotation(45, 16, 20)
|
----> "Parent of Container" fixed-scale (1, 1, 1), fixed-rotation(0, 0, 0)
|
----> "Container" scale (1, 2, 3), fixed-rotation(0, -180, 0)
|
----> "Nested" scale (4, 5, 6), rotation(14, 54, 71)
In the following snippet I am achieving ths following:
Change local scale of "Container" without affecting the size of "Nested" in world space.
Change the scale of "Nested" using the local space of "Parent of Container".
As many will know the local scale of a parent game object will alter the visual scale of nested objects so that when they are measured using world space appear different. To counteract this the local scale of "Nested" must also be updated to compensate for the change so that its size in the world remains unchanged whilst the scale of the container is increased.
I have implemented this (and it is working) with the following solution:
// Temporarily re-parent to "Parent of Container"
nestedTransform.parent = container.parent;
// I can now adjust the size of the container without affecting the
// size of the "Nested" when measured in world space.
containerTransform.localScale = newContainerScale;
// Assign new scale to "Nested" using local space of "Parent of Container"
nestedTransform.localScale = newScale;
// Re-parent "Nested" into "Container"
nestedTransform.parent = containerTransform;
// In the case where `nestedTransform.localScale` is not actually changed,
// after re-parenting it will be changed to (2, 2.5, 3) meaning that its
// size in world space is unchanged whilst "Container" is larger.
Whilst this is achieving exactly what I need, the process of re-parenting game objects does all sorts of other processor intensive stuff that is not wanted.
How can the above be achieved using just matrices and vectors? For each transform there is a local-to-world and world-to-local matrix which might be useful here.
Is container.transform the same as containerTransform? You don't use container.transform but I'm wondering if that's the same thing as your containerTransform
@justinl yes that's right, btw updated question with more clarity
I can write this conversion without reparenting, but it sounds to me that you might be overcomplicating something. Can you explain what's the actual use case?
@Paulius Liekis the use case is quite difficult to explain, but maintaining the scaling in the same way as the `transform.parent` seems to is absolutely essential.
Initially I tried to just use `Vector3.Scale` and adjust the scales accordingly, which worked when all rotations were set to (0, 0, 0), but when rotations were different the scale axis became completely incorrect.
So I went back to basics and just used `transform.parent` to separate these objects, make the necessary changes, and then reassemble them. If I knew how to use matrices properly then I would have done it that way ins$$anonymous$$d (which I guess is what is happening under the hood of `transform.parent`.
The only problem with this approach is that `transform.parent` does a lot of other things too which are costly performance-wise. So I just want the transform aspect of it.
I hope that I am not being too vague...
Problem is that if you have non-zero rotations and you want to use non-uniform scale, then it's not possible to do in Unity, because that leads to scale-stretch effects. Unity can render scale-stretched objects, because it caculates World$$anonymous$$atrices from Transforms before rendering. But you can not counter act scale-stretch effect, because you would need 3x3 matrix for storing scale and Unity gives you only Vector3 (localScale). So in reality it's not possible to implement full anti-parent-scale solution in Unity.
Answer by numberkruncher · Feb 19, 2013 at 03:22 PM
Problem solved by performing all calculations using matrices instead and then decomposing into the separate position
, rotation
and scale
values. These separate values can then be assigned to the transform component which correctly scales object without distorting it.
References:
This took me a little while to figure out, though here is some information which future readers may find useful:
Answer by Paulius-Liekis · Oct 01, 2012 at 11:41 AM
Why do you do this parenting stuff at all? assigning localScale will never change scale of parent.
If we're talking about uniform scales you can do this:
Vector3 oldPosition = nested.position;
controller.localScale = Vector3.one * newScale;
nested.position = oldPosition;
nested.localScale = Vector3.one * (1 / newScale);
The re-parenting solution works in the exact same way as it does when using the Unity editor. If you create two objects A and B and then set the scale of A to (2, 3, 4) and the scale of B to (1, 1, 1) and then drag B into A then the local scale of B is changed automatically using the same mechanism as `transform.parent`.
If I want to change the scale of object A (container) without affecting the world-size of B (nested) then I must first un-parent B, make my changes to A, and then move B back inside A. In the editor the only solution is obviously dragging and dropping.
This makes use of the local spaces of each object and somehow converts to and from world space to ensure that the scale is updated properly. There must be a way to implement this because Unity already supports what I am after (the problem is that it does other intensive stuff as well when re-parenting).
Yes, you're that Editor does same thing as reparenting, but you're wrong that it works in all cases. Try setting non-uniform scales on both objects, then rotating child. Unparent. Re-parent. The look won't match. In some cases it might look very similar (non-noticable), in other cases it will be wrong.
That should not pose an issue in this case because no rotation occurs whilst the object is temporarily un-parented. I have re-worded my question again with more explanation.
Also I have just tested what you said using the editor, and I cannot reproduce the error you speak of.
Here is an example: I made a scene. Unparented and reparented object about 10 times (no rotations in between). Results: http://dl.dropbox.com/u/7345821/Example/ScaleBefore.jpg http://dl.dropbox.com/u/7345821/Example/ScaleAfter.jpg
Your answer
Follow this Question
Related Questions
Is there such a thing as Unity Algebra? 0 Answers
Affine transformations to Object 3 Answers
Math behind Transform.TransformPoint? 1 Answer
How to get relative transform between two objects? 2 Answers
Why is transform.up different than transform.localToWorldMatrix.MultiplyVector(Vector3.up) ? 0 Answers