Changed how perspective is computed. My original formula was wrong. I was merely trying to run the perspective projection formula backwards. This gave a decent approximation at middle distances, but showed warping at extremes. Today I realized I had over-simplified the problem.
The new version (most of which lives in KVAbstractRenderer) is based around raycasting, given the lens's known FOV and aspect ratio. It's memoized a little too aggressively -- I should be able to square-root the footprint later, since raycasting is separable across X and Y in this case.
As a side effect, the vector computations implicitly scale the scene, so I was able to remove some GL scaling code.