3
$\begingroup$

I have a lot of camera background images for reference in an architectural project. I made an animation where, for each frame:

  • The camera position is defined, corresponding to one of the images
  • the same image is used as viewport background. Images have been grouped in a video, and the video is used as a camera background instead.

This way I can change my reference image and match the point of view by just changing the current frame.

However some of the images are in portrait mode, some in landscape mode, and the render size ("resolution") has to be switched accordingly, frame by frame.

enter image description here

This works manually, but I'd like to do this automatically.

Example: Selecting frame 30 to set the (animated) camera viewpoint to some actual picture which was shot in portrait mode and inserted in frame 30 of the background video:

enter image description here

The 30rd background video frame is stretched because the "resolution" is not set accordingly. Is there a bypass?

$\endgroup$
3
  • $\begingroup$ Sorry to say but there is no bypass to this. $\endgroup$ Commented Sep 10, 2018 at 9:33
  • $\begingroup$ this could be done in Python. Are you expecting to click Animation and for Blender render out each frame with its unique settings? Or are you talking about changing the frame in Blender to aid your work flow? $\endgroup$
    – rob
    Commented Sep 10, 2018 at 9:36
  • $\begingroup$ @rob: Frames are used here as a bypass for Blender not having a list of camera viewpoints that can be selected, it's an aid. There is no actual animation purpose. Python is a good solution for me. $\endgroup$
    – mins
    Commented Sep 11, 2018 at 6:46

3 Answers 3

3
$\begingroup$

This is my solution, greatly inspired from @sambler elements (please give him credits, not me).

import bpy

# Define size elements
mx, mn = 1500,1000

# There are less portrait frames, let see them as exceptions
portrait_frames = 11,12,13,14,16,19,24,27,30,31, \
                  33,34,35,36,38,39,40,42,43,44,45

# Define a callback function to call when scene current frame changes
def chg_res(scene):
    # Get frame number
    f = scene.frame_current

    # Set desired resolution for this frame
    if f in portrait_frames:
        scene.render.resolution_x = mn
        scene.render.resolution_y = mx
    else:
        scene.render.resolution_x = mx
        scene.render.resolution_y = mn

# Register callback in Blender event system (once)
bpy.app.handlers.frame_change_pre.append(chg_res)

and the result:

enter image description here

(The frame is manually changed. This leads to the camera resolution being changed by the callback function. The background image and the camera position/orientation are changed by normal animation keyframing).

$\endgroup$
2
  • $\begingroup$ Is playback in the viewport OK for you? I tried it using render animation and the handlers don't change res on frame change during rendering. If manually changing frame works for you thats great. $\endgroup$
    – sambler
    Commented Sep 11, 2018 at 10:00
  • $\begingroup$ @sambler: Yes this is what I was looking for, it's just a bypass to quickly change the camera point of view (to model objects from a series of photos). IMHO, this feature is missing in Blender. $\endgroup$
    – mins
    Commented Sep 11, 2018 at 10:02
3
$\begingroup$

Thanks to some help from Astronet and Sybren, I have code that works for rendering. Hope this helps anyone who was stuck like me.

    import bpy
    
    res_1 = [2560,941]
    res_2 = [1700,540]
    res_3 = [313,550]
    
    
    frame_res = {
        1: res_1,
        2: res_2,
        3: res_3,
        }
        
scene = bpy.context.scene
render = scene.render
f_path = render.filepath

for frame, resolution in frame_res.items():
    scene.frame_set(frame)

    render.resolution_x, render.resolution_y = resolution
    render.filepath = f'{f_path}{frame}'
    
    bpy.ops.render.render(write_still=True)
render.filepath = f_path
$\endgroup$
2
$\begingroup$

I think the only way to do that is to use a python script to adjust and render each frame.

import bpy

res_landscape = [1920,1080]
res_portrait = [1080,1920]

frame_res = {
    1: res_landscape,
    2: res_landscape,
    3: res_portrait,
    4: res_portrait,
    5: res_landscape,
    }

scn = bpy.context.scene

for f,r in frame_res.items():
    scn.frame_set(f)
    scn.render.resolution_x = r[0]
    scn.render.resolution_y = r[1]
    scn.render.filepath = '//renders/image{:03}.jpg'.format(f)
    bpy.ops.render.render('INVOKE_DEFAULT', write_still=True)
$\endgroup$
4
  • $\begingroup$ That's the idea, +1. Currently this leads to Blender freezing when the script is executed (I'll try to fix this). That set apart, I don't want to render all frames in order and stop. Instead, the script must permanently listen to the current animation frame, selected manually, and change the resolution accordingly. $\endgroup$
    – mins
    Commented Sep 11, 2018 at 7:48
  • $\begingroup$ @mins Blocking is known, there is this solution. What I was trying to remember yesterday was using 'INVOKE_DEFAULT'. The only way to automate it would be using bpy.app.handlers but they don't appear to let you change the resolution. The other option is to replace the render button and shortcut to run your operator that does these steps. $\endgroup$
    – sambler
    Commented Sep 11, 2018 at 8:23
  • $\begingroup$ @mins didn't work for me, tried most possibilities. $\endgroup$
    – sambler
    Commented Sep 11, 2018 at 9:31
  • $\begingroup$ I derived a solution from your suggestion, and posted it as an answer (obviously wouldn't fit in a comment. All credit to you indeed). $\endgroup$
    – mins
    Commented Sep 11, 2018 at 9:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .