I wanted to share this solution and get some thoughts on how it might compare to other solutions. This is based on how I might work with a complete transform in a high-end 3D software package.
It assumes that destroying a simple GameObject would have essentially zero performance or garbage-collection issues, as everything I have read says it is extremely light.
C#: (I just like colors and PHP is the only option, right?)
public void SetWorldScale(Transform xform, Transform sourceXform)
{
// Make a reference transform and set it to the source's lossyScale, which
// is Unity's estimate of "world scale". Since this new object doesn't
// have a parent (it is in world space) set it to carry the lossyScale.
GameObject refGO = new GameObject(); // Used to destroy later.
Transform refXform = refGO.transform;
refXform.localScale = sourceXform.lossyScale;
// Cast in to the local space for reference...
// Parent the reference transform to xform's parent so they are in the same
// space, now we have a local scale to use.
refXform.parent = xform.parent;
xform.localScale = refXform.localScale;
// Destroy the ref. Don't worry about Garbage Collection since this is a
// very simple object with no references - basically just a transform
Destroy(refGO);
}
This is part of a constraint component I wrote for PoolManager2, which we will be releasing soon. While this constraint is a minor, optional tool, I want it to be just as performance friendly as the rest of PoolManager.
In the real version:
Everything is cached (the transform, its parent and the target transform)
I’m thinking about trying to implement a ‘dirty’ state so it only runs when the target is updated, but unless there is a state I can grab from Unity, I’m thinking the check will be more intense then just running it. Thoughts?
Scale, Rotation and Position are each optional.
I will also have an option to only run it once, for situations where an update isn’t needed, only an ‘alignment’.
Runs via co-routine so it can be turned on and off completely (no update events used)
If this is as sleek as I expect it to be, I’ll post the complete source code for the community.
OK that version wasn’t as stable as I had hoped. I was able to break it by setting the parent of the object being set to a non-uniform scale (e.g. 0.9, 1.5, 2.3). I guess lossyScale got confused? Anyway…
This version seems to be stable even in a complex hierarchy. I’m not exactly sure why I need to add in a rotation match, but when working with scales I suppose it is logical (which is why I tried it to see if it helped.)
(I didn’t test this exact version, mine doesn’t need the first argument since I am using this.xform in my class. It should be right though…)
/// <summary>
/// Sets this transform's scale to equal the target in world space.
/// </summary>
/// <param name="sourceXform"></param>
public void SetWorldScale(Transform xform, Transform sourceXform)
{
// Make a reference transform and set it to the source's lossyScale, which
// is Unity's estimate of "world scale". Since this new object doesn't
// have a parent (it is in world space) set it to carry the lossyScale.
GameObject refGO = new GameObject(); // Used to destroy later.
Transform refXform = refGO.transform;
// Cast the reference transform in to the space of the source Xform using
// Parenting, then cast it back to set.
refXform.parent = sourceXform;
refXform.localRotation = Quaternion.identity;
refXform.localScale = Vector3.one;
// Parent the reference transform to this object so they are in the same
// space, now we have a local scale to use.
refXform.parent = xform.parent;
// Set the scale now that both Transforms are in the same space
xform.localScale = refXform.localScale;
//Debug.DebugBreak();
// Destroy the ref. Don't worry about Garbage Collection since this is a
// very simple object with no references - basically just a transform
Destroy(refGO);
}
A Disclaimer and a Warning:
With a hierarchy of scaled and rotated objects it works but obviously geometry wouldn’t match (my two cubes looked totally different, but their colliders matched almost perfectly). There was a slight difference, but very little. I sincerely hope nobody is actually working this way. Scaling is bad in most cases. I really only made it this complex for testing. I have a UI element which has to be scaled down (uniformly) during run-time but that is only one object and for a specific need. Nothing in our game is scaled at the asset level.
I just want to say again how disappointed I am that Unity doesn’t have the ability to get and set a Transform (struct-like). Softimage XSI worked this way and it was so easy to manipulate things even if you don’t have any idea how to do matrix math. I could get a transform, manipulate anything, usually through simple methods, and then set it back. This lead to a much simpler workflow, code, learning curve, etc.