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?

Hi everyone, and @Steven-Walker
I know this post is very old but someone may come here to solve their problem with euler angle.

I solved this issue by transforming all euler angles to quaternion.
We can use negative values with quaternion. But if we use eulerAngle and if we set negative value on the editor, we’ll see positive value in script. (As result: 360 - x.)

So, I assume we need to limit rotation between -50 and 50.

Quaternion rotationMin = Quaternion.Euler(new Vector3 (0f, 0f, -50f));
Quaternion rotationMax = Quaternion.Euler(new Vector3 (0f, 0f, 50f));

float moveHorizontal = Input.GetAxis ("Horizontal");

Quaternion rotation = transform.rotation;

if (moveHorizontal < 0 && rotation.z < rotationMax.z) {
	rotation.z += Quaternion.Euler (new Vector3 (0f, 0f, 10f * Time.deltaTime)).z;
}

if (moveHorizontal > 0 && rotation.z > rotationMin.z) {
	rotation.z -= Quaternion.Euler (new Vector3 (0f, 0f, 10f * Time.deltaTime)).z;
}

transform.rotation = rotation;

And I know this code may refactoring. But I just wanted to show logic. I hope it can help someones.

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.

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.

Hi Everyone and @selahattin-unlu and @Bunny83

Again I know this post is super old but I am having similar issues and can’t seem to figure it out. I am still very new to programming and Unity.

This is my current code, as people have mentioned, localEulerAngles doesn’t seem to take a negative number and I tried using some of the examples other uses have shown but still can’t get it to work. Thank you!

void Update ()
{
    float _mouseY = Input.GetAxis("Mouse Y");

    Vector3 newRotation = transform.localEulerAngles;

    newRotation.x = Mathf.Clamp (newRotation.x - _mouseY, min, max);
 
    transform.localEulerAngles = newRotation;
}