Tuesday, May 5, 2015

Leash Camera Example

The leash camera is simple to implement and tracks a moving camera target intuitively without much polish. It can even be implemented without resorting to euler angles or quaternions since it deals entirely with the offset between the camera and the target over time.

The camera will work as long as the target speed and the distance between the camera and the target are within reason, which is usually true in platforming games.

The idea is that as the target moves away from the camera, the camera moves straight towards (or away from) the target to maintain the desired distance. Think of this as walking a dog that is running all over the place, and the leash will be stretched straight from the dog walker to the dog. The dog walker will rotate and move far less than the dog but still keep up with it. (For this example to work you also need to assume that the leash is a straight rod and not really a leash at all.)

Leash Camera Direction tracking a target moving from left to right.

To summarize, here is the trivial version of a leash camera update:

Cf : Camera Forward
Ch : Horizontal position of the camera
Cv : Vertical position of the camera
Th : Target horizontal position
Tv : Target vertical position

  • Update Target position
  • Ch = distance * (Ch - Th) / || Ch - Th || + Th
  • Cv = Tv + height
  • Cf = (T - C) / || T - C ||
Great! The complete camera update for both position and direction in just a few lines of code! But not much control over the behavior, no place to insert user input, and the target can only be in the center of the screen so let’s pull things apart a bit.

The first step is to identify that the result of the update is to apply a rotation to the camera direction based on the offset from the target to the camera.
We care about the rotation being clockwise or counter clockwise so an arcsine from the result of a cross product is promising. The result is a vector of the size of the product of the length of two vectors multiplied with the sine of the angle between them.

Since we only care about the rotation around the vertical axis we can find this by:

Ph : Horizontal offset from the previous camera position to the previous target position
Oh : Horizontal offset from the previous camera position to the current target position
V : Vertical axis
∆a: angle between vectors
PhOh = ||Ph|| ||Oh|| sin(∆a) V

∆a = sin-1( (V ᐧ (PhOh)) / ||Ph|| / ||Oh|| )

The dot product can obviously be omitted since you already know what the vertical axis is, and since you know the vertical axis of the previous and current offset are zero you only need the vertical component. If you for example define X as right, Y as forward, Z as up  and rotation positive counter clockwise you end up with:

∆a = sin-1( (PxOy - PyOx) / √((Px2+Py2) (Ox2+Oy2)) )

Now we have an angle we can apply to the rotation around the vertical axis of the camera forward as part of a full camera update. One thing to note is that in many camera modes applying a smoothing function to the camera forward angle change is an improvement, but for the leash camera the unfiltered angle change works better.

Normally I don’t store the camera direction as angles since that is part of the camera matrix anyway. From experience I don’t have a problem evaluating the angles for the camera at the start of the camera update and applying them to the camera matrix when the rotation is completed.

Combining the leash camera direction update with positioning a target on the screen is the beginning of a simple camera system. What you’ll notice first if you start with this setup is probably pitch angle update (rotation around horizontal axis) and basic user input for camera control.

This camera mode shows how minimizing the rotation and movement of the camera is a good quality for a game camera.

No comments:

Post a Comment