how can I maintain a consistent scaling of a sphere regardless of the rotation of the model? For example, take the following (scaled) sphere:

Scaled sphere

In this image, we start with a sphere, looking at it directly through the Z-azis. The sphere is scaled by 0.7x on the Y (up/down) axis, giving it a 'squashed' appearance.

A 3D vector that describes the scaling of this sphere is [1.0, 0.7, 1.0]. The red dot indicates an arbitrarily chosen point on the surface of the sphere that we will mark as the 'top'.

Now, after the sphere rotates 90 degrees through the Z-axis, the same scaling coefficients [1.0, 0.7, 1.0] when applied will produce a result like this:

Rotated scaled sphere

My question is as follows:

Given a rotation quaternion Q that represents the rotation of the sphere, how can I use Q to correctly alter the scaling coefficients vector in order to produce a result like this instead:

Rotated, scaled sphere, where scaling is the same regardless of rotation

Notice that the eventual 'oriented shape' of the sphere is the same as in the first image, even though a 90-degree-through-Z rotation has been applied. In this instance, a corrected scaling coefficient vector would be something like [0.7, 1.0, 1.0].

I've tried simply multiplying the scaling coefficients vector by Q but this gives an incorrect result. This is actually trivial to see if you imagine rotating [1.0, 1.0, 1.0] by 45 degrees through any angle. The answer should always remain as [1.0, 1.0, 1.0] but it does not.

  • \$\begingroup\$ The scaling coefficient form you've described is only sufficient to represent axis-aligned scaling. But many intermediate rotations will require diagonal scaling, or equivalently a combination of scale and skew. (This is why in Unity when you try to read a "net" scale coefficient vector from a transform including interleaved scales and rotations it calls the property "lossyScale," to reflect that not all information is preserved & represented this way). To get arbitrary scales we'd need either a rotation+scale or a full 3x3 matrix. Would a representation like this work for your needs? \$\endgroup\$ – DMGregory Mar 29 '17 at 0:44
  • \$\begingroup\$ @DMGregory I can use whatever is appropriate. My preferred approach is to somehow calculate correct terms for the axis-aligned scaling values- but I don't mind how I get there. \$\endgroup\$ – Xenoprimate Mar 29 '17 at 0:57
  • \$\begingroup\$ "My preferred approach is to somehow calculate correct terms for the axis-aligned scaling values- but I don't mind how I get there." You won't be able to get to that output, is what I'm saying. There are some combinations of scale and rotation that do not correspond to any 3-vector of scale coefficients. So you'll need to accept a different output representation, not just a different stepping stone along the way. We'll also need to know whether you're scaling on just one axis as shown, or up to all three independently. \$\endgroup\$ – DMGregory Mar 29 '17 at 1:08
  • \$\begingroup\$ @DMGregory Oh I see. I didn't realise there were scale/rotation combinations that couldn't be represented this way. I can also set the transformation as a 4x4 SRT matrix in that case. \$\endgroup\$ – Xenoprimate Mar 29 '17 at 1:19

We can construct a matrix representing this transformation by simply reversing the order in which we normally apply scale and rotation:

 Matrix4x4 RotationInvariantScale(Vector3 axisAlignedScaleCoeffs, Quaternion orientation)
     Matrix4x4 scaleMatrix = Matrix4x4.Scale(axisAlignedScaleCoeffs);
     Matrix4x4 rotationMatrix = Matrix4x4.TRS(Vector3.zero, orientation, Vector3.one);
     return scaleMatrix * rotationMatrix;

Here I draw a model with this matrix as I change the input rotation:

Example of a sphere rotating without moving its scale axes

(Made in Unity, using Graphics.DrawMesh to render using my custom matrix, since Unity won't allow us to set the matrix on a Transform component directly)

Depending on your full setup, you may find this is easier to execute using parenting: place the sphere's visual as the child of an otherwise invisible parent. Apply scaling on the parent object, and rotation on the visible child object. This can avoid hacking in a skewed matrix manually.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.