Quaternion.Lerp: How to interpolate faster to one axis than the other?


I wrote a script where the camera follows a vehicle, optimized for loopings, jumps and “wall-rides”.

using UnityEngine;
using System.Collections;

public class CamFollow : MonoBehaviour {
	public Transform target;
	public Vector3 targetOffset = new Vector3(0f, 1f, 0f);
	public Vector3 checkGroundOffset = new Vector3(0f, -0.5f, 0f);
	public float distance = 10;
	public float angle = 20;
	public float turnSpeed = 1;
	public float detectGroundSpeed = 5;
	float onGround;
	Quaternion smoothRot;
	void FixedUpdate() {
		Vector3 targetPos = target.position;
		Quaternion targetRot = target.rotation;
		// is the target touching ground?
		if (Physics.Raycast(targetPos + targetRot * checkGroundOffset, -target.up, 1f)) {
			onGround = Mathf.Lerp(onGround, 1f, Time.deltaTime * detectGroundSpeed);
		} else {
			onGround = Mathf.Lerp(onGround, 0f, Time.deltaTime * detectGroundSpeed);
		// align target rotation
		smoothRot = Quaternion.Lerp(smoothRot, targetRot, turnSpeed * Time.fixedDeltaTime * onGround);
		// move camera to offset position
		transform.position = targetPos + smoothRot * targetOffset;
		// look-at target
		Vector3 cameraLook = targetPos + smoothRot * (targetOffset - new Vector3(0, angle, angle-90f));
		// up-vector
		float misalign = 2f*(1f-Vector3.Dot(Vector3.up, target.up));
		Vector3 camUp = Vector3.Lerp(Vector3.up, target.up, misalign * onGround);
		transform.LookAt(cameraLook, camUp);
		// move to distance
		transform.Translate(0, 0, -distance);

It works good so far, but I want that the helper rotation “smoothRot” aligns faster to the up-down movement than the left-right. So basically I want to somehow split this rotation into 2 parts to control each lerp speeds separately.

Maybe making a second helper rotation which aligns faster and than somehow combine both, but I’m not sure how exactly this could be achieved. I don’t think converting the Quaternions to Euler and than building an Euler from these would work, but any suggestion is appreciated.

You can split rotations like this:

using UnityEngine;
using System.Collections;

public class RotationTest : MonoBehaviour {

    public Transform targetTM;
    private Vector3 directionVec;
    public float UpDownMultiplier = .05f;
    public float RightLeftMultiplier = .01f;
    private Vector3 upVec;
	// Use this for initialization
	void Start () {
        directionVec = targetTM.forward;
        upVec = targetTM.up;
	// Update is called once per frame
	void Update () {

        Vector3 currentDirectionVec = targetTM.forward;
        directionVec = new Vector3(Mathf.Lerp(directionVec.x, currentDirectionVec.x, RightLeftMultiplier),  currentDirectionVec.y,directionVec.z);
        Vector3 currentUpVec = targetTM.up;
        upVec = Vector3.Lerp(upVec, currentUpVec, UpDownMultiplier);
        transform.rotation = Quaternion.LookRotation(directionVec, upVec);


using UnityEngine;
using System.Collections;

public class RotationTest : MonoBehaviour {
	public Transform target;
	public float UpDownSpeed = 5;
	public float RightLeftSpeed = 1;
	Vector3 directionVec;
	Vector3 upVec;
	void Update() {
		// align target rotation
		directionVec = Vector3.Lerp(directionVec, target.right, RightLeftSpeed * Time.deltaTime);
		upVec = Vector3.Lerp(upVec, target.up, UpDownSpeed * Time.deltaTime);
		transform.rotation = Quaternion.FromToRotation(target.right, target.forward) * Quaternion.LookRotation(directionVec, upVec);

Works :slight_smile: