x


Euler angle problems with rotation limit script

I have a script that limits the rotation of an object, which can be set in the inspector with any min/max value. This works as long as my rotation min/max values are positive, but breaks with negative values. So for example, limiting rotation between -45 and 45 degrees breaks. The problem I know has to do with euler angles, since they don't have negative values. A negative number x is converted to 360-x.

I suspect I can get around this using quaternions, but I don't really know how to do it. I need to read the X, Y and Z rotation values (the same values displayed in the Transform) and then apply the min/max limits.

Anybody understand quaternions well enough to point me in the right direction?

more ▼

asked Sep 21 '11 at 11:55 PM

Steven Walker gravatar image

Steven Walker
862 25 32 49

One other note... I really need to work with negative values because there may be cases where I want limits to be something like -360 to +360, which means the object should be able to rotate one full turn each direction and not any further. Euler angles would oversimplify this and allow the object to rotate continuously.

Sep 22 '11 at 12:44 AM Steven Walker
(comments are locked)
10|3000 characters needed characters left

2 answers: sort voted first

I'm going to answer my own question with the solution I found, but it's a bit less than ideal. I could find no way to get negative euler rotation values from quaternions. Somehow Unity is doing it in the Transform inspector, but I can't figure out how (maybe it's a UI trick). So instead, I'm offsetting my limit calculations so they always occur between 0 and 360. For example, with a rotation limit of -45 to 45, I'm offsetting the input values by 45 so the range calculated is 0 to 90, then offsetting it back -45. This solution works fine for rotation limits with a span less than 360 degrees.

more ▼

answered Sep 22 '11 at 01:42 AM

Steven Walker gravatar image

Steven Walker
862 25 32 49

(comments are locked)
10|3000 characters needed characters left

The rotations are always stored as Quaternion. Quaternions doesn't even work with angles in degree. A Quaternion defines a 3D-rotation as one thing and not like eulerAngles with 3 consecutive rotations. It describes the rotation by a 3D rotation-axis-vector and another float value that describes the rotation around that axis. But they work with normalized complex numbers and you can't work with them like you're used to (the euler-angles-representation)

This is the original inspector for the Transform component. As you can see the rotation that you see in the inspector is the Vector3 that is returned by localEulerAngles. However if the rotation is affected by the physics-system it can clamp the values or two of them jump by 180° when it would run into a gimbal-lock.

internal class TransformInspector : Editor
    {
       private bool firstSet = true;
       private Vector3 rotation;
       private Quaternion oldQuaternion;
       public override void OnInspectorGUI()
       {
         EditorGUIUtility.LookLikeControls();
         Transform transform = base.target as Transform;
         EditorGUI.indentLevel = 0;
         if (this.firstSet || this.oldQuaternion != transform.localRotation)
         {
          this.firstSet = false;
          this.rotation = transform.localEulerAngles;
          this.oldQuaternion = transform.localRotation;
         }
         Vector3 v = EditorGUILayout.Vector3Field("Position", transform.localPosition, new GUILayoutOption[0]);
         this.rotation = EditorGUILayout.Vector3Field("Rotation", this.rotation, new GUILayoutOption[0]);
         Vector3 v2 = EditorGUILayout.Vector3Field("Scale", transform.localScale, new GUILayoutOption[0]);
         if (GUI.changed)
         {
          Undo.RegisterUndo(transform, "Transform Change");
          this.rotation = this.FixIfNaN(this.rotation);
          transform.localPosition = this.FixIfNaN(v);
          transform.localEulerAngles = this.rotation;
          this.oldQuaternion = transform.localRotation;
          transform.localScale = this.FixIfNaN(v2);
         }
         EditorGUIUtility.LookLikeInspector();
       }
       private Vector3 FixIfNaN(Vector3 v)
       {
         if (float.IsNaN(v.x))
         {
          v.x = 0f;
         }
         if (float.IsNaN(v.y))
         {
          v.y = 0f;
         }
         if (float.IsNaN(v.z))
         {
          v.z = 0f;
         }
         return v;
       }
    }
}

There's no much you can do about that. Well, it depends on your case. If you have full control over the rotation you can use a Vector3 to store the 3 angles and use Quaternion.Euler to convert them into a rotation.

more ▼

answered Sep 22 '11 at 01:42 AM

Bunny83 gravatar image

Bunny83
45.5k 11 49 207

Thanks for this thorough reply! There's one thing I still don't understand about the Transform inspector. How does this line work? this.rotation = EditorGUILayout.Vector3Field("Rotation", this.rotation, new GUILayoutOption[0]);

It seems to me this is wrong... shouldn't it be localEulerAngles, since rotation is Quaternion?

And is it just a UI trick that negative numbers are displayed? If the UI is just storing the float values entered by the user, it could be converting them under the hood to euler angles while still preserving the appearance of negative values.

Sep 22 '11 at 02:12 AM Steven Walker

rotation inside the TransformInspector is defined as private Vector3 rotation; at the top. When the object is selected it copies the localEulerAngles into the Vector3. However localEulerAngles will return negative values, but only when you set them manually to a negative value. All "automatic" conversions into eulerAngles will always be wrapped between 0-360. It seems Unity stores the given eulerangles internally inside the transform, but it doesn't serialize the values. If you set the x rotation to -360, save the scene and reload it or press play and stop again it will jump to 0.

So it's not really a trick by the UI. It's a trick by the Transform itself but only for the UI. The conversion from quaternion into eulerangles which happens at runtime will always return positive angles.

Sep 23 '11 at 01:12 AM Bunny83

That makes sense. Thanks for the extra explanation.

Sep 23 '11 at 06:06 AM Steven Walker
(comments are locked)
10|3000 characters needed characters left
Your answer
toggle preview:

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Topics:

x3465
x2173
x443
x134
x8

asked: Sep 21 '11 at 11:55 PM

Seen: 2377 times

Last Updated: Sep 23 '11 at 06:06 AM