9
$\begingroup$

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.

enter image description here

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

enter image description here

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?

Scene from another angle

$\endgroup$
8
$\begingroup$

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.

Camera

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.

$\endgroup$
  • $\begingroup$ Just curious, are the measurement tools in your example built into Blender, or is it an add-on? $\endgroup$ – Danial Oct 13 '16 at 6:31
  • $\begingroup$ 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 $\endgroup$ – Duarte Farrajota Ramos Oct 13 '16 at 12:16
  • $\begingroup$ 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? $\endgroup$ – Christian Afonso Ferreira Oct 13 '16 at 12:38
  • $\begingroup$ 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 $\endgroup$ – Duarte Farrajota Ramos Oct 13 '16 at 22:28
  • $\begingroup$ @DuarteFarrajotaRamos Actually, the scale isn't the hypotenuse but the adjacent or opposite side. plane_height * cos(camera_angle). $\endgroup$ – Christian Afonso Ferreira Oct 13 '16 at 22:51
1
$\begingroup$

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.

enter image description here

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()

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.