Bark of BKNFR insists that this post about ROTOPO’s camera be a short one, not one with rambles and one rant after another and another. Just the technical stuff, to get to the point, because developers want this pure information the most. Developers want this the most because it is easily-digested and they are busy. Like other developers, BKNFR is also busy and understands the sentiment completely and doesn’t hold it against other developers to want pure information with no expositions and fluff like there is in BKNFR’s other posts.
By far the most taxing aspect of ROTOPO’s development was animating the camera. Moving a player around a shape was a problem I solved in a matter of hours. Moving the camera to try to balance clarity with whiplash took weeks, and I’ll admit it’s not 100% there, but I’m mostly happy with it. Here’s a bit of what I picked up along the way.
Jesus Hamiltonian Christ, I’ve read the wikipedia article on quaternions (go ahead and read it for a good time) a whole bunch of times but I still wonder if the mathematician himself ever wrote wrote
on a chalkboard, and thought “D’oh, seems so obvious now!”
I remember my computer graphics professor in college flashing this equation on a powerpoint slide and telling us to treat it like magic. You know “some genius figured it out so you don’t have to.”
Basically, a quaternion is a 4-dimensional vector that’s used to store information about an object’s orientation (how it’s rotated), and “slerping” between two quaternions is a way to transition smoothly from one orientation to another (turn a thing). As we all know instinctively, the shortest distance between two points is a straight line or “lerp” (linear interpolation), and so, the shortest distance between two orientations is a “slerp” (spherical linear interpolation).
You might think that the task of picking your hand up off your desk and placing it on your forehead (to rub out that headache), is a simple maneuver, but the mathematics of motion at play here are quite involved. Your mind has to imagine the changing location and orientation of your hand, and then, working backwards, motivate the joints of your shoulder, elbow and wrist just so to avoid smacking yourself in the face.
Now, before you go patting yourself on the back for your ability to pat yourself on the back, keep in mind that your brain’s had quite a lot of practice: think about how many years it took you to develop the coordination to wipe your own backside.
But good thing you did, and with your powers you could theoretically make a decent amount of money moving containers around or even operating a camera in a film shoot. Except that you don’t have to anymore, because the quaternion slerp does it for free.
So with that little explanation out of the way, here’s a neat trick that I used in ROTOPO to solve a seemingly innocent problem that resulted from this topsy turvy puzzler.
On occasion during gameplay, and especially when transitioning between levels, I needed a way to move the camera fluidly from a starting location/orientation to an ending location/orientation (which could be any which way in space) such that the animation wasn’t completely nauseating.
The first idea would be to “lerp” (go in a straight line) the camera’s position from the starting location to the ending location, while lerping a target point (which the camera is always looking at) from start to end as well. (For example, from where the player dies to where the player is respawned).
Unfortunately there are a lot of problems here. For one, the camera might clip (pass) through the center of the puzzle, and two, simply animating the target point doesn’t assure that the camera is oriented correctly. In other words, it knows where to look, but it doesn’t know which way is up.
For the problem of clipping, I realized I needed to mandate that the camera always look in a sensible direction towards, and be at a similar distance from, the puzzling area.
This gave me the me the idea to use a polar representation of the camera’s location, such that the animation would occur by angle and radius around the origin instead of a straight path. (The camera then moves in an arc around the center of the playing area). The target point would animate linearly, and the camera would end up looking in the right place without clipping. Unfortunately, this left me with the problem of computing an up vector on every frame that correctly twisted the camera around its viewing direction (again, which way is up?), and I wasn’t up to the task.
Clearly what I needed to solve the up-problem was some way to slerp the camera’s orientation from the starting orientation to the final one – but how to calculate the location if the orientation is zipping around?
On every frame, I’d slerp between the orientations, find the new direction that the camera is facing, and subtract this vector from the lerped target point by a (likewise lerped) distance scalar to find the camera’s per-frame location.
Let’s see if I can explain that a little better.
Imagine, for example, you have a camera sitting on a tripod and, for whatever reason, it’s set to spin automatically around its pivot point. If you watched the film, it’d be like when you spun around in circles as a kid to get dizzy.
Now imagine a filmmaker is holding the tripod (which she cannot rotate), and is trying her best to reduce motion sickness by keeping the camera pointed at a target (say a cute puppy). She’d have to run in circles around the the puppy she’s to keep it in the center of the frame.
Likewise, the slerping orientation of my camera is treated as a magical force telling my camera how to orient itself around its pivot point, and then it’s a matter of working backwards from whatever I want the camera to be looking at to find its location. I figure out which way the camera is looking on every frame, and move it so that direction lines up with my target point.