This site uses strictly necessary cookies. More Information

X- Home /

**closed**Feb 17, 2018 at 09:52 AM by pako for the following reason:

The question is answered, right answer was accepted

# How to Decompose a TRS Matrix?

How can the position, rotation and scale components be extracted from a transform matrix?

Hi, i need apply my own $$anonymous$$ATRIX4X4= [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? $$anonymous$$atrix4x4 worldToLocal = [15,0,0,0,0,15,0,0,0,0,15,0,0,0,0,1]; gameObj.Transform.localToWorld$$anonymous$$atrix = worldToLocal.inverse;

You should post this as a separate question, since the original question has been already answered.

**Answer** by numberkruncher
·
Feb 19, 2013 at 03:13 PM

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 :-)*

This method is not able to extract negative scale values (flip transforms).

I agree it's not good but real world is such. In my case, I need to import GoogleEarth $$anonymous$$$$anonymous$$Z models (Collada inside), which often have a number of such flip transforms produced by Google SketchUp. Probably other 3D-editors also can produce such models. Unfortunately my project managers will not agree to drop this feature because of Google immorality.

@vagran_zulu Can you not just write a script to generate a new mesh which does not have flipped transforms? i.e. recompose your mesh... just an idea I thought I'd throw in there for you to play with ;)

Yes, it can be done, it will work, and can be used as workaround. The bad think is that mesh data will be duplicated and will waste a lot of resources. Typically a model has nodes graph, each node has some transform and may have some meshes attached to it. The same mesh can be attached to many nodes thus just having different overall transform applied (and different material bound). So in model which has many parts shared in such a way the wasting factor could be significant.

Actually I have found another workaround but it also has problems: the answer can be extended by checking determinant value of the matrix and in case it is negative, one (any) component of scale vector should be negated. It works for vertex coordinates but unfortunately the Unity is unable to apply this transform also to normals - they became inverted. Seems when it calculates matrix for normals it does not account scaling sign (however according to documentation it accounts scaling as such - it makes some workaround for non-uniform scaling). Before that I tried using Graphics.Draw$$anonymous$$esh with matrix but there is also a problem. Seems the provided matrix applied to both positions and normals as is. Usually for normals separate matrix is calculated if necessary (orthonormal matrix, transpose of inverse of 3x3 upper-left submatrix), but Unity does not do it.

**Answer** by frogsbo
·
Mar 12, 2014 at 07:26 AM

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[i] = 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[i].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[i] = worldToLocal * Matrix4x4.TRS(sections[i].point, rotation, Vector3.one);
}
// except the last one, which just copies the previous one
else
{
finalSections[i] = finalSections[i-1];
}
}
else
{
if (i == 0)
{
finalSections[i] = Matrix4x4.identity;
}
else
{
finalSections[i] = worldToLocal * sections[i].matrix;
}
}
}
```

Your answer shows how to **Compose** a TRS matrix whereas the purpose of this question/topic is to **Decompose** a TRS matrix.

**Answer** by ETdoFresh
·
Jan 02, 2016 at 05:59 PM

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;
}
}
```

If the value of scale is negative,the result of calculation is incorrect

### Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.