For learning purpose, I am trying to calculate transform.localToWorldMatrix
and transform.worldToLocalMatrix
manually. I found if a child object has a single parent, TRS matrix made by Matrix4x4.TRS()
, which I think it is just a transformation matrix storing the gameobject’s position, rotation, and scale, is the same as localToWorldMatrix
and its inverse matrix is the same as worldToLocalMatrix
, as the link below says.
But If a child’s parent has another parent, then that would not work well. So I figured out I need multiplication of each parent 's transformation matrix. Since Unity uses column major matrices, a world vertex position should be calculated as SuperParentMatrix * InternalParentMatrix * localVertex
. I tried it as the code below, but it outputs a wrong value. What am I doing wrong? and How can I calculate it correctly?
public class MultiParentTest : MonoBehaviour
{
[SerializeField]
Transform[] parents;
[SerializeField]
GameObject child;
// Start is called before the first frame update
void Start()
{
LogPositionInfo();
}
[ContextMenu("Log Position Info")]
void LogPositionInfo()
{
if (parents != null && parents.Length == 2 && child != null)
{
Matrix4x4 l2wMat = parents[0].GetTRSMatrix() * parents[1].GetTRSMatrix(); // why wrong?
//Matrix4x4 l2wMat = parents[1].localToWorldMatrix; // correct
var pos = child.transform.position;
var posInfo = $"Correct World Position:
({pos.x}, {pos.y}, {pos.z})
";
pos = l2wMat.MultiplyPoint3x4(child.transform.localPosition);
posInfo += $"localToWorld:
({pos.x}, {pos.y}, {pos.z})
";
Matrix4x4 w2lMat = parents[1].GetTRSMatrix().inverse * parents[0].GetTRSMatrix().inverse; // why wrong?
//Matrix4x4 w2lMat = parents[1].worldToLocalMatrix; // correct
pos = child.transform.localPosition;
posInfo += $"Correct Local Position:
({pos.x}, {pos.y}, {pos.z})
";
pos = w2lMat.MultiplyPoint3x4(child.transform.position);
posInfo += $"worldToLocal:
({pos.x}, {pos.y}, {pos.z})
";
Debug.Log(posInfo);
}
}
}
static public class TransformExtension
{
static public Matrix4x4 GetTRSMatrix(this Transform transform)
{
return Matrix4x4.TRS(transform.position, transform.rotation, transform.lossyScale);
}
}
Description of my scene that uses the code above:
made 3 GameObject as parent0, parent1, and child. parent0 is a parent of parent1 and parent1 is a parent of child. set different transform values of them and put parent0 and parent1 into Transform parents as parent0 is the first element, and put child into GameObject child.