So, the best (only) way I've found of doing this is to modify the projection matrix before rendering. Given a scale and a center position,
var center = new Vector2(....);
var scale = new Vector2(....);
var zoomPanMatrix = Matrix4x4.Scale(scale);
/// offset view X (screen)
zoomPanMatrix.m03 += (1 - 2 * center.x) * scale.x;
/// offset view Y (screen)
zoomPanMatrix.m13 += (1 - 2 * center.y) * scale.y;
This creates a matrix that zooms in (scale) and pans to (center) the area of interest, in screen space.
On a side note, this also works if you want to, say, render a part of a larger image for a display wall, super-high res tiled image files, etc.
When rendering (I'm rendering to a texture, so this code is in OnRenderImage()
)
var originalProjectionMatrix = cam.projectionMatrix;
cam.projectionMatrix = zoomPanMatrix * originalProjectionMatrix;
cam.Render();
cam.projectionMatrix = originalProjectionMatrix;
If you want to take advantage of this for frustum culling, do the above and clip against the resulting frustum.
There's probably a way to do this with an oblique projection matrix. Good luck with that. I also played with concatenating an offset orthographic matrix - which should work - but didn't spend a lot of time on it,
I have to modify center
based on which eye is rendering to get real stereo, but it works fine.