11
$\begingroup$

Transformation matrices in Blender (skip if you want)

Transformation matrices in Blender are by design limited to a certain type of 4x4-matrix that is less general than just any old invertible matrix. For example, shear operations are not possible. Blender's transformation matrices are precisely the matrices that satisfy the following conditions, I think:

  1. The first three columns are mutually perpendicular and end in a 0.
  2. The last column is of the form (a,b,c,1) where (a,b,c) represents a translation.

(I'm using the convention that a transformation matrix M is applied to column vectors v as M*v, as is usual in mathematics.)


My question

Suppose that M is the transformation matrix of a Blender object (and therefore satisfied the conditions above). I now apply a scaling of factor 3 along the global x-axis. How is the resulting transformation matrix calculated?

One would naively expect that the first row of M just gets multiplied by 3. (As opposed to scaling by 3 along the local x-axis, in which case the first column of M gets multiplied by 3.) But this is not what happens, as the resulting matrix would not satisfy the first condition above anymore. Instead, all of the columns of M get rescaled in some way.

How is the transformation matrix of an object changed when I scale along the global x-axis?


An illustration

Start with the default cube. Rotate it by 30 degrees along the y-axis (ry30Enter). Now rescale by 3 in the x-direction (sx3Enter). The object gets rescaled by 2.646 in its local x-direction and by 1.732 in the local z-direction. Where do these numbers come from? (They seem to equal sqrt(7) and sqrt(3), respectively. So their squares sum to 1+3^2, which is probably relevant.)


Observations (added)

If we rescale along a global axis by a factor x, and this results in rescaling along the local axes by factors (a,b,c), then we always have a^2+b^2+c^2 = x^2+1^2+1^2.

Also, rescaling along global x by 3 twice is not the same thing as rescaling along global x by 9.


Note: I don't need an explanation of the mathematics behind transformations, matrices or quaternions. I'm familiar with those.

$\endgroup$
11
  • $\begingroup$ I'm personally ignorant to dealing with these transformations at a matrix level, however I did have a thought here. Have you tried applying the scale and rotation 1st, and then looking at the matrix again to see if it was what you would expect? Just curious. $\endgroup$
    – Rick Riggs
    Apr 29, 2016 at 4:50
  • $\begingroup$ @RickRiggs - Applying the scaling first and then rotating is the same as first rotating and then scaling along the local x-axis (by hitting x twice), as one would expect. But I'm not sure how exactly the numbers 2.646 and 1.732 are calculated. $\endgroup$ Apr 29, 2016 at 17:20
  • $\begingroup$ As another illustration, start from the default cube. Rotate it by 45 degrees about the y-axis. Now scaling along the global x-axis is the same as scaling along the global z-axis (!). $\endgroup$ Apr 29, 2016 at 17:21
  • $\begingroup$ Maybe we are still talking two different things, and I want to make sure we are not. When I say "apply" I mean (with your mesh of focus selected) Ctrl+A >> Rotation & Scale. It sounds like maybe you were thinking "apply" means entering your rotation and scale values to the matrix directly. If this is the case, take my definition of it into account, and check your mesh matrix again to see if you get your expected values. $\endgroup$
    – Rick Riggs
    Apr 30, 2016 at 0:03
  • 1
    $\begingroup$ @RickRiggs - Oh, sorry, I didn't get what you meant. In any case, applying (ctrl+a) the rotation and scale just applies the object's transformation to the mesh data and resets the object's transformation to the identity. This is what I would expect. But it doesn't answer the question, unfortunately. $\endgroup$ Apr 30, 2016 at 0:13

3 Answers 3

2
$\begingroup$

I wondered the same, and when I saw that there was no answer here, I looked it up in the source. Dealing with signs is complicated, but without considering signs, the method is as follows. The sources work with 3x3 matrices (position doesn't influence scale), so I'll do the same here.

Let $S$ be the original scaling matrix, and $R$ be the original rotation matrix. Now, to scale by a new matrix $N$, calculate $A = S\times R\times N$ and obtain the new sizes on each axis by calculating the Euclidean norm of each row of $A$.

In your case:

Suppose that M is the transformation matrix of a Blender object (and therefore satisfied the conditions above). I now apply a scaling of factor 3 along the global x-axis. How is the resulting transformation matrix calculated?

Take the $3\times 3$ matrix $M' = S\times R$ by discarding the last row and column of $M$, then obtain $A = M'\times\left[\begin{matrix}3 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1\end{matrix}\right]$. Now, the new X scale is $\sqrt{a_{11}^2 + a_{12}^2 + a_{13}^2}$, the new Y scale is $\sqrt{a_{21}^2 + a_{22}^2 + a_{23}^2}$, and the new Z scale is $\sqrt{a_{31}^2 + a_{32}^2 + a_{33}^2}$. Use these as the elements of the diagonal of the new scaling matrix, $S'$. The new $3\times3$ matrix is obtained as $S'\times R$ and the $4\times4$ matrix by adding back the last row and column of the original $4\times4$ matrix.

For your example:

Start with the default cube. Rotate it by 30 degrees along the y-axis (ry30Enter). Now rescale by 3 in the x-direction (sx3Enter).

we have $S = I$ (no scaling on the cube to start with), $R = \left[\begin{matrix}\cos 30°&0&\sin 30°\\0&1&0\\-\sin 30°&0&\cos 30°\end{matrix}\right] = \left[\begin{matrix}\sqrt3/2&0&1/2\\0&1&0\\-1/2&0&\sqrt3/2\end{matrix}\right]$ and $N = \left[\begin{matrix}3 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1\end{matrix}\right]$. Now $A = S\times R\times N = \left[\begin{matrix}3\sqrt3/2&0&1/2\\0&1&0\\-3/2&0&\sqrt3/2\end{matrix}\right]$ so the new scale on X is $\sqrt{(3\sqrt3/2)^2+(1/2)^2} = \sqrt7\approx 2.646$, on Y is 1, and on Z is $\sqrt{(-3/2)^2+(\sqrt3/2)^2} = \sqrt3\approx 1.732$.

The code can be found in source/blender/editors/transform/transform.c in function ElementResize(). Function TransMat3ToSize() extracts the norm of each row and deals with signs.

$\endgroup$
1
  • $\begingroup$ I hope to see more of your questions and answers in near future. $\endgroup$ Nov 21, 2018 at 21:50
1
$\begingroup$

If you wish to scale along the normals after rotating, simply hit 'x' twice, then enter 3. This will provide you with the dimensions you are looking for/expecting.

In a simple way, think about how the X values of the rotated box are actually smaller than 1 if you apply the 30 degree rotation first. Then once you include the fractions for sine and cosine (M) for the rotation around an origin, the value of X will be even smaller than the simple multiplication by 3. The numbers you are seeing above are correct. But they are the result of a certain order of operations. Use the correct order of operations or scale on the normals for the expected results.

If you search for "scale rotate translate", you'll find videos and articles about this for game programmers.

Updated with calculations because my initial answers were vague:

The Z scale is the result of the 30 degree rotation multiplied by 2:

>>> (sqrt(3)/2) * 2
1.7320508075688772

The X scale is the result of 1) the ratio of the scale to 3:

>>> 2.6459962836960553/3
0.8819987612320185

and 2) the ratio multiplied by sqrt(3)/2 to compensate for the ability to calculate the radius of the increase on the X axis, like so:

>>> (2.6459962836960553/3) * (sqrt(3)/2)
0.7638333333333335

Now with the scale ratio included into the 30 degree calculation, you can see the resulting X value of a vertice on the long end of the scaled and rotated cube:

>>> 3 * ((2.6459962836960553/3) * (sqrt(3)/2))
2.2915000000000005

Which from the other side, means that the scaling factor for X can be arrived at this way:

>>> 0.7638333333333335 * 3
2.2915000000000005
>>> (0.7638333333333335 * 3)/(sqrt(3)/2)
2.6459962836960558

Also, if you are curious about calculating the X and Z values, don't forget to calculate the length from the origin point to the corner of the cube before scaling or rotating.

>>> sqrt((1**2)+(1**2))
1.4142135623730951
$\endgroup$
16
  • $\begingroup$ Yes, I know that hitting x twice will rotate around the local x-axis. This is not what I'm asking about. You write 'use ... for the expected results'. But I didn't expect it to scale along the local x-axis. I just want to know how the numbers 2.646 and 1.732 are calculated. $\endgroup$ Apr 29, 2016 at 17:18
  • $\begingroup$ I attempted to point you in the right direction in paragraphs 2 & 3. $\endgroup$ Apr 30, 2016 at 2:26
  • $\begingroup$ Here's the crux. once you rotate the cube, prior to scaling, you expose the Z axis to further scaling as well, because your vertices(which are really the numbers you should be referencing rather than scale factor) are what are actually getting modified. You might think of the changes to Z as sharing a ratio of requested changes to X. This is why the scale factor for both gets changed, where X is not quite 3 and Z is slightly modified. $\endgroup$ Apr 30, 2016 at 2:27
  • 1
    $\begingroup$ Yes, 2.646 and 1.732 are those distances, by definition. You write '... may involve some trig...'. It's the trig I'm looking for. $\endgroup$ Apr 30, 2016 at 15:10
  • 1
    $\begingroup$ Please see my amended answer for calculations. $\endgroup$ May 1, 2016 at 11:03
0
$\begingroup$

From what I can tell (I was able to get one of your stated values 1.732) the numbers being stored in the matrix to the local X is a projection value to it's local mid-point in world space as seen in the screenshot below. As for your scale value I would hope that would be the 2.732 value instead of your stated illustration value of 2.646, so on that one I'm at a loss.

WorldProjectionToLocalCoordinates

$\endgroup$
2
  • $\begingroup$ @kheetor - Sorry, I just saw that there were hidden comments to this post, and you had the same idea. I will gladly withdraw my answer if you post it. $\endgroup$
    – Rick Riggs
    Apr 30, 2016 at 12:02
  • $\begingroup$ Aha, at least we have the value 1.732 showing up somewhere! I'll play around a bit with this idea to see whether I can explain both numbers (the 2.646 is correct). $\endgroup$ Apr 30, 2016 at 15:07

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .