Scaling along arbitrary axis

Started by
5 comments, last by Pragma 14 years, 9 months ago
I want to add a "squash" and "stretch" effect to some of the characters in my game. To do that I need to be able to scale them along a given vector that isn't necessarily aligned to an axis. But I'm not sure how to do that. At first I thought I could calculate a rotation matrix to align the character's +Y axis to the vector, then calculate the inverse of that, and then another matrix to scale along the Y, then do something like this: M = R * S * R-1 to give me a new matrix that could scale along the vector I wanted, but the more I thought about it the more I decided it wouldn't work. Then I thought about: M = (R * S) * (S-1 * R-1) but I still don't think I'm getting anywhere. Has anyone managed to pull this off?
I like the DARK layout!
Advertisement
Nevermind, I'm wrong.


EDIT: I think your first idea is correct. The rotation matrix is hard to choose. Also (R * S) * (S-1 * R-1) = I, because (R * S) * (S-1 * R-1) = R * (S * S-1) * R-1 = R * I * R-1 = I
You had the right idea with (R * S * R-1), although you might have to swap the rotation and inverse rotation depending on whether you're using row vectors or column vectors. In short, the rotation 'R' should be "closest" to the vertex.
Your first M is the right idea. Let W be a unit-length direction along which the scaling s should be applied. Let U and V be unit-length vectors for which {U,V,W} are mutually perpendicular. The set should be right-handed in that W = Cross(U,V). The matrix R whose columns are U, V, and W is a rotation matrix. Let P be the origin of a coordinate system with coordinate directions U, V, W.

Any point may be written as X = P + y0*U + y1*V + y2*W = P + R*Y, where Y is a 3x1 vector with components y0, y1, and y2. The point with the desired scaling is X' = P + y0*U + y1*V + s*y2*W = P + R*D*Y, where D is the diagonal matrix Diag(1,1,s). Then Y = R^T*(X-P), where R^T is the transpose of R and X'-P = R*D*R^T*(X-P).

If you were to choose P = 0, then X' = R*D*R^T*X. But R^T = R^{-1} (the inverse of R), which is what you proposed.
Dave is right, but this is more easily expressed in pseudocode. Let W be your (normalized) scaling axis and s be the scale factor. Then your matrix is just:

M[i,j] = (s - 1) * W * W[j] + (i==j?1:0)
"Math is hard" -Barbie
Quote:Original post by Pragma
Dave is right, but this is more easily expressed in pseudocode. Let W be your (normalized) scaling axis and s be the scale factor. Then your matrix is just:

M[i,j] = (s - 1) * W * W[j] + (i==j?1:0)


Yes, when the origin is chosen as P = 0. Your formula is derived as follows. The identity matrix is I = R*R^T = U*U^T + V*V^T + W*W^T. Then R*D*R^T = U*U^T + V*V^T + s*W*W^T = (I - W*W^T) + s*W*W^T = I + (s-1)*W*W^T.

The behavior of "scaling" depends on your choice of P. I suspect that the OP wants P to be the origin of his character, not the world origin.
That is a good point. To stretch about a point P you can tack on a translation by

(1-s) * dot(P,W) * W
"Math is hard" -Barbie

This topic is closed to new replies.

Advertisement