hamel123 hamel123 - 2 months ago 7
C# Question

Camera doesn't smoothly interpolate its rotation

I'm facing a problem in my scene. What i'm doing is there are two panels both panel has one button which performing

OnClick()
listener with the method name
RotateCamera()
.

Image 1

Also in hierarchy there is a
MainMenu
gameobject
which attached with one script. When I play the scene and click on
panel one
button than
MainCamera
rotate with 90 angle to the direction of second panel. Script works fine but I want to smoothly rotate camera to that panel when I click on that button - right now, it is rotating instantly. I don't know what I'm doing wrong on this script.

public class CameraSmooth : MonoBehaviour {

private bool check = false;
private Transform from;
private Transform to;

void Start(){
from = Camera.main.transform;
}

void Update(){
if (to != null) {
Camera.main.transform.rotation = Quaternion.Slerp (from.rotation, to.rotation, 3 * Time.deltaTime);
}
}

public void RotateCamera(){
if (!check) {
Camera.main.transform.Rotate (0,90f,0f);
to = Camera.main.transform;
check = true;
}
else if (check) {
Camera.main.transform.rotation = Quaternion.identity;
to = Camera.main.transform;
check = false;
}
}
}

Answer

The main problem here is that when you're calling Camera.main.transform.Rotate() in RotateCamera(). This causes the rotation to be applied to the camera immediately, resulting in the instant rotation you're seeing.

Another small misconception - since Transform is a reference type, from and to always actually point to the same instance (the Transform of the camera)! Lastly, the value of 3 * Time.deltaTime will always average around 3/60, and will likely never end up close to 1, which is needed for an interpolation to be complete. As such, the following line:

Camera.main.transform.rotation = Quaternion.Slerp (from.rotation, to.rotation, 3 * Time.deltaTime);

will not be able to do anything even if the first issue is addressed.

The situation calls for a different solution, in my view:

  1. Storing the target rotations in Quaternion variables rather than setting them directly on the Transform, and keeping track of the camera's initial rotation

  2. Maintaining a timer which keeps track of the progress of the rotation (or you can abandon Slerp() and just apply an incremental rotation directly, that's also a valid approach)

Here's my suggested update to your code:

public class CameraSmooth : MonoBehaviour {

    private bool check = false;
    private float rotationProgress = 1;
    private Quaternion initial;
    private Quaternion from;
    private Quaternion to;

    void Start(){
        // Cache the starting rotation, so we can calculate rotations relative to it
        initial = Camera.main.transform.rotation;
    }

    void Update(){
        if (rotationProgress < 1) {
            rotationProgress += 3 * Time.deltaTime;
            Camera.main.transform.rotation = Quaternion.Slerp (from, to, rotationProgress);
        }
    }

    public void RotateCamera(){
        from = Camera.main.transform.rotation;
        rotationProgress = 0;

        if (!check) {
            to = initial * Quaternion.Euler(0,90f,0f);
            check = true;
        }
        else if (check) {
            to = initial;
            check = false;
        }
    }
}

(Haven't tested this code, so please let me know if there are any issues.) Hope this helps! Let me know if you have any questions!

Comments