Fullscreen frame-by-frame 2d animation

I’ve got hundreds of 1080p images that I want to animate in a 30fps sequence and show full screen.
I managed to create an animation using AnimatedSprite2D, but I can’t figure out how to make it behave properly when window is being resized.
TextureRect acts properly when resizing, but can’t be animated like that. There is an AnimatedTexture but adding hundreds of images as frames one by one is not really a good option. Same goes for AnimationPlayer.
Is there a way to do it properly? I am sorry if the question is dumb, I am completely new to Godot, coming from Unity and testing if Godot will be a suitable replacement. And I couldn’t find any solution except for the creation of custom AnimatedTextureRect bootleg class that lags and has problems with proper animation speed.

You can use GD.Load(“res://textures/1.png”); To load the Texture and then assign the result to the texture property of TextureRect, you only need to write the logical switching frame within the _PhysicsProcess method?

You can write a script to populate the AnimationPlayer or AnimatedTexture but either way you’re probably going to run into issues. If there a reason you can’t turn the image into a video and just play that? There are free converters out there. Adobe has a good one.

You’re going to run into a resource problem that Godot can’t help you with. A video compresses frames by saving the delta (changes) between frames. You are going to load a bunch of pictures into memory and your game is likely to stall, be slow, or crash at some point unless you manage that.

what’s the use case here? What are you trying to accomplish with all these 1080 pictures?

1 Like

It’s a stylized cutscene with visualized sound(a car crashes and a funky “boom” flies from it fading away in a second, a phone rings and “beep” does the same etc.)
I load those sounds by calling a function at specific frames, also some cutscenes are not just and animation or a loop, it’s a one time animation that transitions into a loop until player makes a decision, quicktime event of sorts. And when the player does - I want to have options of moving to the next part instantly, smooth fadein or seamless frame perfect.
While doing all that by timing(sounds) and some signal of ended playback is probably possible - it sounds like a bandaid to me that will be causing problems later.
Figured 2 solutions so far:

  1. AnimatedSprite2d seems to be following the screen changes if the initial size of the texture fits the initial resolution of the project. But the sounds and frame perfect transitions still an issue so I take SpriteFrame that was created and put it into AnimationPlayer, 0 frame at start, end frame in the end and in transitions between them asa a normal animation. That works. I can add all the func calls I need now. BUT I’m not sure sprite2d won’t start behaving weirdly when I decide to port it to android for example.
  2. Second solutions is filling an animation track for TextureRect. Also doable, but I encountered an itsy issue.
    var animation = animator.get_animation(‘Test’)
    var tex:Texture = load(“res://Animations/003_out.webp”)
    animation.track_insert_key(0, 0.0666, tex)
    Works. But the fact that I can’t choose a frame and have to choose a time in a 30fps animation cause a slight desync.
    If I set 0.0667 for frame 3 - the frames will go 1 → 2 → 2 → 4, but will go properly if played backwards.
    If I set 0.0666 for frame 3 - the frames will go 1 → 2 → 3 → 4, but the frame skip will happen when it’s played backwards.
    Since I don’t need to play my cutscenes in reverse - not really an issue, just a quirk.

What’s the memory problem you’re talking about? Does godot not unload unused textures? I had a similar problem in unity, I unloaded them with a separate code to prevent that.

Godot unloads an assets only when it is no longer being used anywhere. It uses Reference Counting. You can read more by checking out the RefCounted class which everything in Godot derives from. So it really depends on how you set up your scenes. If you load them all into memory, then everything is there. But if you load scenes only as needed and call queue_free() on them you should be fine.

Okay, new problem. The more animations I add the longer it takes the scene to start. Currently it’s somewhere around 20 seconds to load. I added 700 frames animation and it spiked from 2s to 30s load time.
Tried both AnimatedSprite2d and AnimationPlayer. They both preload all textures they’ve got animations for.
Are there any solutions for that? Like, maybe, not preload everything and load every frame when it’s needed? I don’t remember having that problem in unity with those same animations.

Edit. Ok, it’s not just loading times, lol. I just noticed VRAM usage. Built 2 versions - the one with Sprite Frames loaded in the scene and the one without. Without those it loads instantly and takes up around 200mb VRAM, with sprites it takes up 6.7gb of VRAM. Basically just 2d images showing. And I haven’t even added all of the animations that I planned.
My interest in godot was mainly because it seemed lightweight compared to unity. I thought it might be less taxing on player’s pc. And because of native webp support since lots of 1080p images kinda take a lot of space in unity being converted to 2mb each. Taking up nearly 7gb of vram for basically a visual novel-style animation is surprising.

Godot is lightweight. Your pictures are not. Everything you want to do can be done using videos in Godot. The problems you are seeing are the ones I was trying to warn you about.

I recommend you read this from the documentation on the differences from load() and preload(): Logic preferences — Godot Engine (4.4) documentation in English

You definitely shouldn’t be using preload(). I’d recommend you also consider loading only the animations you need in a scene, and if that scene is too big, you look at optimization.

Ideally, you should not be using animated frames that big. It’s a game engine. It can do the animation for you. Give it pieces of the picture separately that you want to animate, and do the animation in-engine.

Basically, I don’t see your current approach of working with any game engine. Hundreds of 1080p pictures is going to take up a lot of video RAM, as you are experiencing. Either videos or in-game animation stores deltas and so are much more efficient.

1 Like

I’m not using preload, not even load really. It’s just the behaviour of AnimationPlayer itself. It loads on start every texture it has animations for. I was able to minimize the problem

  1. Deleting all animations and only loading the ones currently showing/removing them from the library after helped a lot.
  2. Changed import settings to VRAM compressed with high quality, BC7, same format unity uses actually. I compared them at the same animation - pretty much the same VRAM usage and delay. Not 30s but still there, like a second, maybe a bit more.

Figured I could actually async load anims that are about to be played to get rid of that delay.
I also tried just loading textures in the _process func as was suggested in the first reply. It actually works, I had like 45-50 loaded each second when I only needed 30 for 30 fps. It works without any noticable load on vram, cpu or disk. But, unfortunately I can’t tell animplayer to not preload and load like that. At least I don’t think I can?
You’re probably right that I should just use videos. I had trouble with videos in the past - some players couldn’t see them ingame and quality dropped compared to images that the video was made from. I followed the steps described in the godot docs about making a decent video with conversion. Looks good, but I feel like sometimes frames are missed and it looks a bit stuttery if compared to the lossless variation.

1 Like

Godot has recently received many video related fixes. FFmpeg also had some bugs that would affect Godot and they have been fixed in the latest daily builds.

Godot 4.5 should be able to pull this pretty well. Just in case you want to try. I also think this could work better with video. Please, read the Playing Videos page of the docs for important information.

1 Like

Using video sounded so easy. Only one format? How bad could it be, I thought to myself. Every single converter I tried has problems with ogv. FFmpeg recommended in the docs - did ok in a 90frame video, then I tried 320frames video - it lost half of the frames, mixed others with some weird colorful artifacts, when I tried to test that video in godot - it looked suspiciously similar to the videotape from the ring! I’m sure I saw a demon’s face at some point. Then 3 next converters couldn’t output ogv at all. The next 2 - one eats the last frame when converting, the other ADDS an extra frame of stuttering for some reason! Every time! And all of those make a video slightly darker/more red/sometimes add green tint. While also giving out perfect webms and mp4s pretty much 1to1 when compared to initial images. All those problems are present only when converting to ogv.

Try using Adobe’s converter.

Can you share the command line used for FFmpeg?

You could try converting your frames to FFV1 then to OGV as a workaround but maybe we can figure out the main issue.

What do you mean? Online one? It says it converts only to mp4, Adobe Encoder also doesn’t work with ogvs.

.\ffmpeg -i convert.mov -c:v libtheora -q:v 10 -c:a libvorbis -q:a -1 output_video.ogv

At first I tried mp4 h264 into ogv, but at some point I noticed the video quality drops noticably when you’ve got 20+ frames in the video. After some testing I switched to ProRes 422 in a Quicktime container, hence .mov. This one retains quality no matter the size. Ffmpeg failed both with a bit different results.
Don’t know what FFV1 means, googling said it’s the mp4 h264 version, did I understand that correctly?

I could swear that’s what I used when I did a conversion. Apologies.

FFV1 is a lossless video format used by FFmpeg.

Which date and version is the FFmpeg you’re using?

And which Godot version?