godot
                                
                                
                                
                                    godot copied to clipboard
                            
                            
                            
                        Performance greatly decreases if characters are animated in 4.0 and later
Godot version
4.0
System information
Windows 10, i7, nvidia 840m 8gb, forward+, mobile and compatibility
Issue description
Since I was interested to shift to 4.0 from 3.5.1 I made a test scene to test 4.0 performances and well the results were bad. My characters are made of multiple poligons with puppet-like animations, now if an enemy is not animated I can populate the test scene with more than 500 enemies, if it's animated only 31.
EDIT: in comparison in 3.5.1 a mostly complete test level with environment, functioning player, various functioning enemies with ai, attack, physics etc can handle more than 60 enemies on screen.
Steps to reproduce
-If you want to start from zero: Make a character made of multiple sprites or polygons, animate it and make a test scene that adds as many copies of characters until the fps go lower than 60fps, try one time with the character animated and another time with the character not animated and you will see a big difference in performance(or at least it's what happens to me).
-if you want to start from my minimal project: there are only 2 scenes, test and enemy_pol, enemy_pol has only the "walk" animation in the AnimationPlayer, check or uncheck the autoplay button depending if you want test enemy_pol animated or not and then run the main scene(test). In the bottom left corner of the test scene you will see how many enemies are on screen and the fps.
PS: Don't judge the blank character, i wasn't ready to share the still unfinished version lol!
Minimal reproduction project
This comes from a change that was made early in the 4.0 rendering rewrite. To make skeletons with Polygon2Ds faster we moved to internally creating meshes out of Polygon2Ds. So everytime you make a change to the polygon properties (i.e. polygon, uv, offset, the mesh is regenerated and sent to the RenderingServer. In the typical use case ( the Polygon2D is created once and then bones are used to animate it) this works very well and avoids a lot of the overhead of the old approach.
However, your use-case is not what we expected when this was rewritten. You are using an AnimationPlayer to manually make changes to the polygons instead of using bones to edit them. Accordingly all the changes are happening on the CPU-side and then the meshes need to be recreated every frame. This wastes a lot of performance.
In the MRP, just disabling the changes to uv, offset and polygon in the AnimationPlayer make it so I can render many more characters (normally at 90 characters I hit 30fps, but after unchecking, uv, offset, and polygon I get 55 FPS with 360 chracters)
I have discussed this with other users and this change has been a problem for anyone who is doing custom animation stuff on Polygon2Ds directly. So we need to improve performance. The main question is how?
One option is to add back a codepath when not using skeletons to stream polygon data every frame. In other words, instead of creating a mesh each time the polygon changes, always use polygon and pass all polygon data to the GPU each frame (this is how it worked on 3.x).
Another option (that may only be a partial fix) is to automatically batch polygons and meshes. They share a format, so it should be possible to batch them. That being said, I think the lack of batching is only part of the performance issue.
Yeah i suspected that it had to do with those proprerties. I made other tests, same scene but this time with sprites instead of polygons and I found problems with CanvasGroup:
Animated enemies made of sprites without canvasgroup: 182 Not animated enemies made of sprites without canvasgroup: 562
Animated enemies made of sprites using canvasgroup: 22 or 31(more often 31) Not animated enemies made of sprites using canvasgroup: 22 or 31(more often 22...?)
Also enemies, animated or not, made of polygons with canvasgroup: 22
I forgot to say that no matter the case the fps are never steady, i guess it has to do with the creation of new nodes.
One option is to add back a codepath when not using skeletons to stream polygon data every frame. In other words, instead of creating a mesh each time the polygon changes, always use polygon and pass all polygon data to the GPU each frame (this is how it worked on 3.x).
I'd suggest going with this approach, considering how common manually animating Polygon2Ds is. In fact, it's probably more common than using skeletons in 2D…