I’ve been having a lot of fun recently playing through the Ocarina of Time PC port. Released March 2022, it’s accumulated a lot of nice enhancements as open source ports tend to do. It runs in 60fps with the viewport scaled to the resolution and aspect ratio of your choice. There’s a host of gameplay tweaks, and the option to use a freely orbiting camera controlled by the right analog stick, as seen in modern games.

During my playthrough I was pondering what enhancements of my own to add, and after vanquishing Ganon in 4k I decided the free camera would be most impactful thing I could improve.

It orbits at a fixed distance (controllable in the settings,) and while it was fun to navigating the game with a wider camera angle at a higher vantage point, I found myself wanting the lens to swing close to link when it was down parallel to the ground.

After a bit of research, I decided to have the camera move in a curve from a position behind and just below link’s head, to a position high above him.

This is shown on the right (seen side-on) in a diagram from the camera chapter in Game AI Pro.

Note that the diagram shows a spline. I’ve used a cubic bezier instead, to keep things simple.

The existing freecam code uses polar coordinates to have the camera orbit the focal point (link’s head.) The analog stick X and Y values are added to the pitch and yaw of that rotation (quaternion I think it’s called? It’s a 4 vector) directly. The radius is set to the configured camera distance value.

In my new implementation, the yaw is set the same way as before, directly from the controller. I define my four bezier points relative to link, and get the new camera position using the bezier function, setting t to the analog Y axis. Presto!

The SoH UI toolkit made it super easy to create new sliders in the camera config UI and to bind these to values in a manner similar to unity. This was useful not only for experimenting with different curve shapes once I had everything working, but also fantastically helpful in learning and exploring the different functions in the OOT engine.

I bound a bunch of different sliders to lots of different parameters and through trial and error was able to map out what most of the moving parts did in this crazy code from a quarter century ago. This interactive approach was way faster than peering at numbers in the debugger.

I’m confident that I would have made zero progress had I done it that way, and instead I managed to get a working solution in a couple of afternoons, along with a newfound intuition about how to define and navigate 3D spaces programmatically. In the end I plugged in the numbers and it worked first time. I could hardly believe it.

The branch is here if you want to take a look. It’s in pretty rough shape at the time of writing. Here are some things still to address:

Overall this was a really fun project, that yielded results very quickly. If you’re still reading this, you’ll definitely want to check out the github repo for the port, as well as the OOT decomp project it was based on.