1
$\begingroup$

I have a looped animation. On the first and last frames, there is nothing but a plain backdrop, and the object appears sometime during the middle of the animation. I'm rendering to an image sequence, then compiling to .gif with the help of ScreenToGif.

The problem is that the .gif thumbnail shows the first frame, which is the blank backdrop. This is especially problematic because I have multiple works in a series, and all of their thumbnails are the same blank backdrop. The animations are all 168 frames long. My workaround is to manually import frames 60-168 into ScreenToGif, then to import frames 1-59. However, this is fairly inconvenient. I've also tried shifting the keyframes to achieve the same effect but, again, it's a substantial amount of unnecessary work.

Is there a way to render frames out-of-order and effectively renumber or remap the frames? For example, I'd like to save frames 60-168 as frame[0001-0108].png, and frames 1-59 as frame[0109-0168].png.

Is this possible?

$\endgroup$
1
  • 1
    $\begingroup$ There is no frame offset property. You would have to rename the renderings using python when finished. An automated way I can think of is copying the files into a new folder by specifing the 'split frame' and create the gif by using ffmpeg. Would this help? $\endgroup$
    – brockmann
    Mar 30, 2021 at 17:30

2 Answers 2

1
$\begingroup$

I would do this via scripting. Here I modified an existing script that would do your remapping of frame# into file index#. You would adjust firstBreak to 60 and lastFrame to 168.

import bpy

filepathFmt="//render/frame {0:04d}.png"

firstBreak=8
lastFrame=11

###
### for list of shape types, N loops, create a set of objects, render and save, and clean up:
###
fp=""
outFileIdx=1

### render from firstBreak to lastFrame:
for frameIdx in range(firstBreak, lastFrame+1, 1):
    
    bpy.context.scene.frame_set(frame=frameIdx)
    print("frame=" + str(frameIdx))
    # format filename string using different index
    fp = filepathFmt.format( outFileIdx )
    print(outFileIdx)
    print( fp )
    bpy.context.scene.render.filepath = fp
    bpy.ops.render.render( write_still=True )
    outFileIdx+=1

print("remap")

### render from frame 1 to firstBreak-1:
for frameIdx in range(1, firstBreak, 1):
    
    bpy.context.scene.frame_set(frame=frameIdx)
    print("frame=" + str(frameIdx))
        
    ### render and save:
    # format filename string using different index
    fp = filepathFmt.format( outFileIdx )
    print(outFileIdx)
    print( fp )
    bpy.context.scene.render.filepath = fp
    bpy.ops.render.render( write_still=True )
    outFileIdx+=1
```
$\endgroup$
1
$\begingroup$

I would also do it with scripting. This solution renames already rendered files. It reads most stuff from your Blender settings - but it also assumes those settings are correct and didn't change since you rendered the files. It also assumes there's no additional files other than those rendered in the render directory!

Running the script once will shift the frames by specified number (I've set it to 100) - you could also uncomment line 11 to shift by half of the animation, so it starts exactly in middle.

Running the script a second time will unshift the frames back.

I just wrote this script so it's not thoroughly tested.

import bpy, os

offset = 100  # that many frames will be moved from the end to the beginning
shifted = "shifted"  # base of filename after shifting

scene = bpy.context.scene
path, orig_base = os.path.split(scene.render.filepath)
start = scene.frame_start
end = scene.frame_end
anim_len = end - start + 1
# offset = int(anim_len/2)  # set offset to half of the animation

for i, filename in enumerate(sorted(os.listdir(path))):
    base, ext = os.path.splitext(filename)
    if base.startswith(shifted):
        # restore
        new_frame_num = start + (i-offset) % anim_len
        new_filename = f"{orig_base}{new_frame_num:04}{ext}"
    else:
        # shift
        new_frame_num = start + (i+offset) % anim_len
        new_filename = f"{shifted}{new_frame_num:04}{ext}"
    print(f"Renaming {filename} to {new_filename}")
    os.rename(os.path.join(path, filename), os.path.join(path, new_filename))
$\endgroup$
1
  • 1
    $\begingroup$ Don't worry, looks nice and should work fine. $\endgroup$
    – brockmann
    Mar 31, 2021 at 15:08

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.