How can the position, rotation and scale components be extracted from a transform matrix?
The components of a matrix can be extracted as follows:
// Extract new local position
Vector3 position = m.GetColumn(3);
// Extract new local rotation
Quaternion rotation = Quaternion.LookRotation(
m.GetColumn(2),
m.GetColumn(1)
);
// Extract new local scale
Vector3 scale = new Vector3(
m.GetColumn(0).magnitude,
m.GetColumn(1).magnitude,
m.GetColumn(2).magnitude
);
Note: The purpose of this question was to share this knowledge in Q&A style
Here’s a Monobehaviour Script I’ve been working on for a few hours for doing it the Hard Way, for those interested…
public class DisplayTransformMatrix : MonoBehaviour
{
[Header("Matrix4x4.localToWorldMatrix")]
public Vector3 MatrixRow1;
public Vector3 MatrixRow2;
public Vector3 MatrixRow3;
public Vector3 MatrixCol3;
public string MatrixRow4;
[Header("Local Transform")]
public Vector3 localPosition;
public string localRotation;
public Vector3 localEuler;
public Vector3 localScale;
[Header("World Transform")]
public Vector3 worldPosition;
public string worldRotation;
public Vector3 worldEuler;
public Vector3 worldScale;
[Header("UI Element")]
public Text textToUpdate;
void Update()
{
// Update Matrix4x4 Information in Inspector
Matrix4x4 m = transform.localToWorldMatrix;
MatrixRow1.x = m[0, 0];
MatrixRow1.y = m[0, 1];
MatrixRow1.z = m[0, 2];
MatrixRow2.x = m[1, 0];
MatrixRow2.y = m[1, 1];
MatrixRow2.z = m[1, 2];
MatrixRow3.x = m[2, 0];
MatrixRow3.y = m[2, 1];
MatrixRow3.z = m[2, 2];
MatrixCol3.x = m[0, 3];
MatrixCol3.y = m[1, 3];
MatrixCol3.z = m[2, 3];
MatrixRow4 = "" + m[3, 0] + " " + m[3, 1] + " " + m[3, 2] + " " + m[3, 3];
// Update Local Transform in Inspector
localPosition = transform.localPosition;
localRotation = string.Format("{0} {1} {2} {3}", transform.localRotation.w,
transform.localRotation.x, transform.localRotation.y, transform.localRotation.z);
localEuler = QuaternionToEuler(transform.localRotation);
localScale = transform.localScale;
// Update World Transform in Inspector
worldPosition = GetPosition(m);
worldRotation = string.Format("{0} {1} {2} {3}", GetRotation(m).w,
GetRotation(m).x, GetRotation(m).y, GetRotation(m).z);
worldEuler = QuaternionToEuler(GetRotation(m));
worldScale = GetScale(m);
// Update UI Element
if (textToUpdate)
textToUpdate.text = m.ToString();
}
public Vector3 GetPosition(Matrix4x4 m)
{
return new Vector3(m[0, 3], m[1, 3], m[2, 3]);
}
public Vector3 GetScale(Matrix4x4 m)
{
return new Vector3
(m.GetColumn(0).magnitude, m.GetColumn(1).magnitude, m.GetColumn(2).magnitude);
}
public Quaternion GetRotation(Matrix4x4 m)
{
Vector3 s = GetScale(m);
// Normalize Scale from Matrix4x4
float m00 = m[0, 0] / s.x;
float m01 = m[0, 1] / s.y;
float m02 = m[0, 2] / s.z;
float m10 = m[1, 0] / s.x;
float m11 = m[1, 1] / s.y;
float m12 = m[1, 2] / s.z;
float m20 = m[2, 0] / s.x;
float m21 = m[2, 1] / s.y;
float m22 = m[2, 2] / s.z;
Quaternion q = new Quaternion();
q.w = Mathf.Sqrt(Mathf.Max(0, 1 + m00 + m11 + m22)) / 2;
q.x = Mathf.Sqrt(Mathf.Max(0, 1 + m00 - m11 - m22)) / 2;
q.y = Mathf.Sqrt(Mathf.Max(0, 1 - m00 + m11 - m22)) / 2;
q.z = Mathf.Sqrt(Mathf.Max(0, 1 - m00 - m11 + m22)) / 2;
q.x *= Mathf.Sign(q.x * (m21 - m12));
q.y *= Mathf.Sign(q.y * (m02 - m20));
q.z *= Mathf.Sign(q.z * (m10 - m01));
// q.Normalize()
float qMagnitude = Mathf.Sqrt(q.w * q.w + q.x * q.x + q.y * q.y + q.z * q.z);
q.w /= qMagnitude;
q.x /= qMagnitude;
q.y /= qMagnitude;
q.z /= qMagnitude;
return q;
}
public Vector3 QuaternionToEuler(Quaternion q)
{
Vector3 result;
float test = q.x * q.y + q.z * q.w;
// singularity at north pole
if (test > 0.499)
{
result.x = 0;
result.y = 2 * Mathf.Atan2(q.x, q.w);
result.z = Mathf.PI / 2;
}
// singularity at south pole
else if (test < -0.499)
{
result.x = 0;
result.y = -2 * Mathf.Atan2(q.x, q.w);
result.z = -Mathf.PI / 2;
}
else
{
result.x = Mathf.Rad2Deg * Mathf.Atan2(2 * q.x * q.w - 2 * q.y * q.z, 1 - 2 * q.x * q.x - 2 * q.z * q.z);
result.y = Mathf.Rad2Deg * Mathf.Atan2(2 * q.y * q.w - 2 * q.x * q.z, 1 - 2 * q.y * q.y - 2 * q.z * q.z);
result.z = Mathf.Rad2Deg * Mathf.Asin(2 * q.x * q.y + 2 * q.z * q.w);
if (result.x < 0) result.x += 360;
if (result.y < 0) result.y += 360;
if (result.z < 0) result.z += 360;
}
return result;
}
}
Hi, i need apply my own MATRIX4X4= [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] to my gameobject, how can i do that?
I need to apply it to obtain a new transformation to my object.
this is correct?
Matrix4x4 worldToLocal = [15,0,0,0,0,15,0,0,0,0,15,0,0,0,0,1];
gameObj.Transform.localToWorldMatrix = worldToLocal.inverse;
Here is an example of Matrix TRS from extrusion demo in .js:
for (var i=0;i<sections.length;i++)//for every vertex as edges of 2 pairs
{
if (autoCalculateOrientation)
{
if (i == 0)
{
var direction = sections[0].point - sections[1].point;
var rotation = Quaternion.LookRotation(direction, Vector3.up);
previousRotation = rotation;
finalSections _= worldToLocal * Matrix4x4.TRS(position, rotation, Vector3.one); _
-
}*
-
// all elements get the direction by looking up the next section*
-
else if (i != sections.length - 1)*
-
{ *
_ direction = sections*.point - sections[i+1].point;_
_ rotation = Quaternion.LookRotation(direction, Vector3.up);*_
* // When the angle of the rotation compared to the last segment is too high*
* // smooth the rotation a little bit. Optimally we would smooth the entire sections array.*
* if (Quaternion.Angle (previousRotation, rotation) > 20)*
* rotation = Quaternion.Slerp(previousRotation, rotation, 0.5);*
* previousRotation = rotation;*
finalSections = worldToLocal * Matrix4x4.TRS(sections*.point, rotation, Vector3.one);*
* }*
* // except the last one, which just copies the previous one*
* else*
* {*
_ finalSections = finalSections[i-1];
* }
}
else*
* {
if (i == 0)
{
finalSections = Matrix4x4.identity;
}
else*
* {_
finalSections _= worldToLocal * sections.matrix;
}
}
}*_