Creating a Steady Cam Effect

Here’s a quick overview of how I managed my idle camera movement for Jettomero. I really enjoy spending a lot of time of camera behaviour to get things feeling natural and effective at motivating gameplay. To capture that ‘giant monster’ movie feel I wanted to have a constant drifting of the camera – almost as a handheld camera simulation.

My camera control in Jettomero is actually surprisingly complex since I have 2 objects which use smoothing for their position and rotation – the camera object itself, and a camera target object that changes behaviour based on the game context (whether we’re flying around space or walking on a planet). I may go into depth about the camera system in another post but for now we’ll just look at the idle movement.

steadycam

I was originally modifying position, rotation and zoom level all using the same technique but I’ve since simplified it to only adjust rotation because I found there was too much movement happening previously. So in the Start() function of my SteadyCam script I call this Coroutine.

    IEnumerator RotFlux()
    {
        while (true)
        {
            yield return new WaitForSeconds(Random.Range(0.5f, 1.5f));
            rotOffsetTarget = Quaternion.Euler(Random.Range(rotRange, rotRange), Random.Range(rotRange, rotRange), Random.Range(rotRange, rotRange));
            yield return null;
        }
    }

The variable rotOffsetTarget is a Quaternion that I declare at the top of the script, so this coroutine modifies it every 0.5 to 1.5 seconds – using a range that I’ve also defined at the top of script, as 3.0f. Now that I have a randomized rotation variation being set frequently I can include it in my Update function.

To simplify things – these are the two lines that affects my Camera rotation in the update function:

rotOffset = Quaternion.Lerp(rotOffset, rotOffsetTarget, Time.deltaTime);

transform.rotation = Quaternion.Lerp(transform.rotation, CameraFollow.Instance.transform.rotation * rotOffset, Time.deltaTime * rotSpeed);

First, I take my rotOffsetTarget and smooth to it using a Quaternion Lerp from rotOffset. Yes, I do a lot of smoothing.

As I had mentioned earlier, I have 2 levels of smoothing on the Camera, so CameraFollow.Instance.transform refers to the second level of smoothing, which I want my steady cam to follow and mimic. I take the rotation of that tranform, add my random rotation variation to it (Quaternions are added through multiplication) and then Lerp between my Camera object’s current rotation and this target rotation. My variable rotSpeed (set at 2.0f earlier in my script) determines how quickly I settle in to the new rotation.

I don’t have a professional background in code so I’m sure there’s a more effective way to do all this, but I’m happy to share my technique. If you have any further questions about my Camera behaviour feel free to drop me a line on Twitter.