# Setting camera to position where it can render a seamless repetable orthographic scene

I'm using 3d to speed up production of 2d graphics of machines and structures (which have a lot of straight lines, objects and little details repeated all over the place).

The goal is to have an isometric background image that repeats seamless. I set the camera with orthographic projection and 45° of rotation.

And manually cut the vertical borders in an image editor in the position where it repeats. Then I can do something like this:

Instead of cutting it manually every time I do a test, I would like to set the camera view position and height from Blender. Then I can render an already seamless repeated image.

Those two Empty objects in the boundaries are where the camera borders should be. However I have no clue how to accurately set up the camera in this case. How can I do this?

The trick with Orthographic cameras in Blender is that they use a specific scale system, such that 1 Blender unit always matches the largest dimension of the render output.

That means if you are rendering an image of $1920\times1080$ with a scale factor of $1$ then $1920$ pixels in your image will match exactly one Blender scene unit.

If the image is say $2048\times4096$ with a scale of $2$ that means that $4096$ pixels will match exactly two Blender units.

That being said in your case you need to do some math.

Place you camera such that it points exactly at the center point C midway between your two marker empties $A$ and $B$, while being rotated exactly an angle of $45°$ in the X axis. Distance is unimportant.

You can select both empties $A$ and $B$ and easily place the 3D cursor to the selection with Cursor to Selected, and then use the operator Center View to Cursor to center the camera between the two.

Now determine the distance between the two empties $[AB]$. Since it forms a right-angled triangle, with the distance being its hypotenuse, then the exact scale of the camera will be the square root of this distance. In my example above they dist exactly two units apart, so $\sqrt{2} = 1,4142$ will be exactly the scale factor you must place in the orthographic camera.

• Just curious, are the measurement tools in your example built into Blender, or is it an add-on? Oct 13, 2016 at 6:31
• Ah no, actually it was just purpose made from curves and a few text objects, for the sake of clarity. But if you need similar functionality, however, you can look into the Measure It Addon that ships by default with Blender 2.78 Oct 13, 2016 at 12:16
• I found that there is a "Camera Fit Frame to Selected" operator that does it if I have a mesh. However, because these methods only deal with scale, the image size don't change. In your sample, for example, how would I fit the border in the plane width and height? Oct 13, 2016 at 12:38
• That would use the rule I mentioned, the largest value in the pixel size of the render will be used for scaling and is equivalent to one scene unit. So just have to measure your plane object, if your mesh object were 4.5 units and you want to fit it, just add an orthographic scale of 4.5 and the camera will fit the largest dimension (width or height) to the plane size Oct 13, 2016 at 22:28
• @DuarteFarrajotaRamos Actually, the scale isn't the hypotenuse but the adjacent or opposite side. plane_height * cos(camera_angle). Oct 13, 2016 at 22:51

Thanks to @DuarteFarrajotaRamos answer I got how to view this situation mathematically. So I come up with an operator that change the camera scale and render dimensions to fit the boundary box of a mesh.

I can create a plane where I want the borders.

Then I find the adjacent (plane_height * cos(camera.rotation_euler.x)). Divide the render width by the aspect ratio of plane_width / projected_plane_height to find the render height.

The operator align the camera, keeps the render width I want and change height to match.

import bpy
import math
import mathutils

class FitRenderBorder(bpy.types.Operator):
"""Tooltip"""
bl_idname = "view3d.fit_render_border"
bl_label = "Fit camera and resolution to selected object"

@classmethod
def poll(cls, context):
return context.active_object is not None

def execute(self, context):
render = context.scene.render
camera = context.scene.camera
frame = context.active_object

# Size
frame_projected_height = frame.dimensions.y * math.cos(camera.rotation_euler.x)
height = render.resolution_x / (frame.dimensions.x / frame_projected_height)

# Set location
bpy.ops.view3d.camera_to_view_selected()
position = mathutils.Vector((0.0, 0.0, frame_projected_height))
inverse = camera.matrix_world.copy()
inverse.invert()
new_position = position * inverse
camera.location = camera.location + new_position

# Render settings
camera.data.ortho_scale = frame.dimensions.x
render.resolution_y = height

return {'FINISHED'}

def register():
bpy.utils.register_class(FitRenderBorder)

def unregister():
bpy.utils.unregister_class(FitRenderBorder)

if __name__ == "__main__":
register()