3
\$\begingroup\$

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.

\$\endgroup\$
4
  • \$\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, 2017 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\$ Mar 29, 2017 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, 2017 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\$ Mar 29, 2017 at 1:19

1 Answer 1

2
\$\begingroup\$

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.

\$\endgroup\$

You must log in to answer this question.

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