# Per-Axis (Euler) Rotation Control While Avoiding Gimbal Lock

I am writing a target-following script with numerous per-axis settings. Below is the most distilled example I can provide of the rotation portion:

``````private void Rotate()
{
var _target = Quaternion.LookRotation(Target.position - transform.position, Target.up).eulerAngles;
var _next = transform.eulerAngles;

for (var i = 0; i < 3; i++)
_next <em>= Mathf.LerpAngle(_next<em>, _target<em>, smoothRotateSpeed _* Time.deltaTime);_</em></em></em>
``````

transform.localRotation = Quaternion.Euler(_next);
}
In the example above, “smoothRotationSpeed” is a Vector3 that applies a different smoothing value to each axis.
Unfortunately, because I am modifying each axis individually, I am running into Gimbal lock issues. How can one avoid or compensate for Gimbal lock without losing per-axis (euler) control?

I can’t guarantee this will work. But give it a try. I basically only deal with the euler angles of the rotation between current and target. I adjust how much impact that rotation has, and bring it back to quaternions. Dealing with quats as much as possible.

I generalized the ‘FromToRotation’ as its own static method. That’s because I have my own “QuaternionUtil” class that contains a lot of methods likes this. I’m really annoyed by the lack of methods built into the Quaternion from Unity. They have a FromToRotation to get a quaternion between two vectors, but not between two quaternions. For shame.

Note I also renamed the variables.

``````using UnityEngine;
using System.Collections;

public class GimbalTest : MonoBehaviour {

public Transform _target;
public Vector3 smoothRotateSpeed;

// Use this for initialization
void Start ()
{

}

// Update is called once per frame
void Update ()
{
//var target = Quaternion.LookRotation(_target.position - this.transform.position, _target.up).eulerAngles;
//var next = transform.eulerAngles;

//for (var i = 0; i < 3; i++)
//    next <em>= Mathf.LerpAngle(next<em>, target<em>, smoothRotateSpeed _* Time.deltaTime);_</em></em></em>
``````

//transform.localRotation = Quaternion.Euler(next);

var targetRot = Quaternion.LookRotation(_target.position - this.transform.position, _target.up);
var delta = FromToRotation(this.transform.rotation, targetRot);
var deltaEuler = delta.eulerAngles;

for (var i = 0; i < 3; i++)
deltaEuler = Mathf.LerpAngle(0f, deltaEuler, smoothRotateSpeed * Time.deltaTime);

transform.rotation *= Quaternion.Euler(deltaEuler);
}

public static Quaternion FromToRotation(Quaternion start, Quaternion end)
{
return Quaternion.Inverse(start) * end;
}
}