# Is there a way to fit the viewport to the current field of view?

Since there seems to be no direct way to get the camera's projection matrix, I'm hoping that it's possible to fit the viewport to the current field of view (the area encompassed by passepartout), because then the viewport projection matrix would in effect be the camera projection matrix, and that matrix can be retrieved via region_3d.perspective_matrix.

So, in pictures, I'm looking to do the following via Python:

Before:

After:

Is that possible?

I'm looking to export the projection matrix for an external application, so that my view there matches blender's camera view.

For that purpose, this is a roundabout way to ask, but my previous question was (in my view, incorrectly) marked as a duplicate.

• Perhaps if you explained your technical goal in a little larger sense perhaps readers could give you some good ideas. Is this a rendering need ? A viewing need? Oct 6 '14 at 18:50
• @atomicbezierslinger I think the OP wants to get the projection matrix of the camera in python
– gandalf3
Oct 6 '14 at 19:02
• What do you want the projection matrix for? - worth including in the question. Oct 6 '14 at 20:21

Python has access to all the variables used to make the camera matrix, it shouldn't be so much work to check on the C code and get it working in Python, note that the camera frame may have shift applied, so a matrix alone wont give give you the camera bounds.

• I found perspective_m4 in math_geom.c. That seems like it should work, but the arguments (xmin, xmax, ymin, ymax) go through a very long and confusing pipeline (part of which can be seen in BKE_camera_params_compute_viewplane), which involves other hard to track values, and additional function calls. So, it doesn't really seem that easy to me. Oct 7 '14 at 3:35
• re: BKE_camera_params_compute_viewplane - this takes width/height & aspect, Python has access to these. Oct 7 '14 at 6:31

While trying to figure out how to manipulate bpy.context.screen.areas[5].spaces[0].region_3d.view_camera_zoom , I accidentally discovered that the Home key will make the camera bounds fill the viewport. If you try 'View All' from the spacebar menu it doesn't work exactly like the Home key (could not be bothered to hunt down why).

While not exactly useful, the examples at http://web.purplefrog.com/~thoth/blender/python-cookbook/screenshot-sequence.html might get you a little closer to the solution. Specifically

def viewMatrixFromCamera(cam):
"""
:param cam: the camera whose point of view is of interest
:return: the view matrix suitable for use in region_3d.view_matrix
"""
m2 = cam.rotation_euler.to_matrix()
m2.resize_4x4()
m3 = mathutils.Matrix.Translation(cam.location)
return (m3*m2).inverted()

def viewFrom(screen):
"""
:param screen:
:return: the "first" area in the specified screen that is a 3D view.
"""
for obj in screen.areas:
if (obj.type == 'VIEW_3D'):
return obj
return None

v3d = viewFrom(bpy.context.screen)
m1 = viewMatrixFromCamera(bpy.context.scene.camera)
print(m1)
v3d.spaces[0].region_3d.view_matrix = m1


Unfortunately this exact code is NOT what you need when you are actually looking through the camera. It only works to set the view when you are NOT looking through the camera.

Another problem is that while the code does move your focal point to the camera position, and gives you the correct orientation, it is highly unlikely to match the focal length of the camera. I have not been able to find any setting on the 3D view that allows you to adjust the focal length when you are not looking through the camera. When you "zoom in" you really just move the 3d view's focal point closer to the center point.

• Home does the same thing as @atomicbezierslinger's answer for me, which AFAICT doesn't seem to answer the OP's question of how to fit the view to the camera (including aspect ratio?).
– gandalf3
Oct 6 '14 at 20:16
• If you want to adjust the aspect ratio, that's going to involve adjusting the size of the "area", and then you have to fight with toolbars. I'm not saying it's impossible, but it will be difficult. The biggest roadblock is that view_offset is opaque, and probably relevant to the position of the camera rectangle (in case you dragged it around). Oct 6 '14 at 20:20

If you want to "fill" the screen with the camera view while looking through a camera, this little nugget should do the trick:

import bpy
import mathutils

def viewFrom(screen):
"""
:param screen:
:return: the "first" area in the specified screen that is a 3D view.
"""
for obj in screen.areas:
if (obj.type == 'VIEW_3D'):
return obj
return None

def wonk(factor):
return 50*(2*math.sqrt(factor) - math.sqrt(2))

#

v3d = viewFrom(bpy.context.screen)
r3d = v3d.spaces[0].region_3d

r3d.view_camera_offset = (0,0)
r3d.view_camera_zoom = 29.29 # (2-sqrt(2))*50

a1 = v3d.regions[4].width / v3d.regions[4].height
a2 = scn.render.resolution_x / scn.render.resolution_y

if a2<a1 :
r3d.view_camera_zoom = wonk(a2/a1)


If you want to set your view point and angle to be the same as the camera while not looking through the camera, see my other example.

Spacebar menu ..... view camera center.

bpy.ops.view3d.camera_to_view()

• This fits the camera to the view, it doesn't fit the view to the camera like in the OP's example.
– gandalf3
Oct 6 '14 at 19:02
• By my inspection, View Camera Center appears to be exactly what the OP's examples display. The opposite would be Align Camera To View (C-A-Num0). Oct 6 '14 at 20:33