Page 1 of 1

rendering.set_animation_speed() skips frames

Posted: Wed Jan 01, 2020 8:23 am
by ownlyme
I needed an animated graphic with render layer that i can dynamically change the animation speed of ( https://mods.factorio.com/mod/windturbines )
so i stumbled over your new LuaRendering API and was really happy about it's seemingly endless possibilities.

But i soon ran into an issue when i changed the animation speeds of the turbine blades and shadow to simulate wind speeds.
For the orientation i replaced the animations by simply using rendering.set_animation() which didn't cause frame skips but i thought i should maybe mention it.

It would be really nice if the animation wouldn't skip frames when you changed it's speed.

I thought it was possible to calculate the frame offset, but it doesn't seem to be deterministic at all... (but i'm sure my formula is correct .. at least now) (it also glitches when i dont replace the animation)

Code: Select all

game.print("total ticks "..(game.tick-turbine.creation_tick))
local current_wind_speed = wind_speeds[turbine.base.surface.name]*WIND_SPEED_MULT
turbine.last_frame_count = turbine.last_frame_count+(game.tick-turbine.last_change)*turbine.last_speed
game.print("actual frames until now: "..turbine.last_frame_count)
game.print("changing speed to "..current_wind_speed)
local new_frame_number = (game.tick-turbine.creation_tick) * current_wind_speed
game.print("expected frame at new speed: "..new_frame_number)
local new_offset = (new_frame_number-turbine.last_frame_count)*-1
game.print("calculated offset: "..new_offset)

rendering.set_animation_speed(turbine.turbine,current_wind_speed )
rendering.set_animation_speed(turbine.shadow,current_wind_speed)
rendering.set_animation_offset(turbine.shadow,new_offset)
rendering.set_animation_offset(turbine.turbine,new_offset)

turbine.last_change = game.tick
turbine.last_speed = current_wind_speed 
https://www.dropbox.com/s/auc73v9ag8kj2 ... .zip?raw=1

Happy new year!

Re: rendering.set_animation_speed() skips frames

Posted: Wed Jan 01, 2020 11:46 am
by Klonan
The rendering animation speed is done in the same way as the most of the rest of the game, essentially like this

Code: Select all

local frame = ((game.tick * animation_speed) + animation offset) % #frames)
It doesn't store any state about what frame it was on, or progressing frames, that is bad for memory performance

Re: rendering.set_animation_speed() skips frames

Posted: Thu Jan 02, 2020 5:30 am
by ownlyme
if that formula is correct i should be able to calculate an offset, but it doesn't work (but i'll try something new based on your formula, give me 1 hour...)
if you're not able to calculate the offset, the set_animation_speed function is useless.
i'm pretty sure there's something you can do to fix this, without hurting memory performance, for example only when a mod utilizes this.
Normal entities that scale their animation speed by activity also work without skipping frames, so why not this too?
but i feel like you're again declaring something as not-a-bug too quickly

Re: rendering.set_animation_speed() skips frames

Posted: Thu Jan 02, 2020 6:04 am
by TruePikachu
Your math likely does have an error, since substituting it into the equation Klonan provided states that the animation would transition to the same frame only if `turbine.creation_tick * (turbine.last_speed - current_wind_speed) ≡ (turbine.last_change - game.tick) * turbine.last_speed (mod frame_count)`.

EDIT: I'd suspect that normal entities (read: C++ code) have built-in computation of the new offset via setter member function. It might be an API request to expose this automatic calculation, but the omission of it, strictly speaking, isn't a bug.

EDIT 2: The corrected formula should be along the lines of `offset' = (tick * (speed - speed') + offset) % #frames` (where offset' and speed' are the new values for offset and speed)

Re: rendering.set_animation_speed() skips frames

Posted: Thu Jan 02, 2020 6:12 am
by ownlyme
i tried a new algorithm based on your formula but it still glitches

Code: Select all

local expected_frame = (((game.tick * turbine.last_speed) + turbine.last_offset) % 24)
game.print("currently at frame: "..expected_frame)
local current_wind_speed = wind_speeds[turbine.base.surface.name]*WIND_SPEED_MULT
local new_frame = (((game.tick * current_wind_speed)) % 24)
game.print("new speed: "..current_wind_speed)
game.print("new frame w/o offset: "..new_frame)

new_offset = (expected_frame - new_frame)%24
game.print("new offset: "..new_offset)
game.print(string.rep("-",game.tick%80))
rendering.set_animation_speed(turbine.turbine,current_wind_speed )
rendering.set_animation_speed(turbine.shadow,current_wind_speed)
rendering.set_animation_offset(turbine.shadow,new_offset)
rendering.set_animation_offset(turbine.turbine,new_offset)

turbine.last_offset = new_offset			
turbine.last_speed = current_wind_speed 

Re: rendering.set_animation_speed() skips frames

Posted: Thu Jan 02, 2020 6:28 am
by TruePikachu
I have just verified the math in the new algorithm; assuming the formula provided by Klonan is correct, and the animation is exactly 24 frames long, there shouldn't be any frame skipping.

Re: rendering.set_animation_speed() skips frames

Posted: Thu Jan 02, 2020 6:33 am
by ownlyme
but there is... (a lot) .. if it only skipped 1 or 2 frames i'd know that i was on the right way but it often skips half of the animation
https://www.dropbox.com/s/079sm3hc4tpfm ... .zip?raw=1

Re: rendering.set_animation_speed() skips frames

Posted: Thu Jan 02, 2020 7:34 am
by TruePikachu
Set the animation speed in your prototypes to 1.0, or account for the effects that setting a not-1.0 speed in the prototypes has on the actual speeds. The actual animation speed is the speed set on the render object multiplied by the animation's speed in prototypes.

I just verified the equation provided by Klonan via disassembly of the relevant function, but came across that additional factor of the prototype speed.

Re: rendering.set_animation_speed() skips frames

Posted: Thu Jan 02, 2020 7:42 am
by ownlyme
OMG THANK YOU SO MUCH!!!!!
IT WORKS! :D :) ;) :shock: :lol: :P :mrgreen: