-
-
Notifications
You must be signed in to change notification settings - Fork 35.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimizations to Animation Engine #13910
Comments
I'm not sure how to progress with this issue unless you (or somebody else) has specific suggestions for improvement. Did you profile to see where the bottlenecks are before suggesting this? Or would you be willing to do so now? Or are there other JS animation systems that you are comparing against that have better performance than our one? |
Well, off the top of my head, I know a bit about how the existing animation system is structured, there are a lot of objects, and a lot of object references. This could be reduced by using a less comprehensive but a more cache-friendly data structure for bones and transitions. An optimized can be added, to take existing animations and try to reduce computational complexity. One example: function updateV3_x(t){
v3.x = lerp( 0,3, inverseLerp(t,0,10) )
}
function updateV3_x(t){
v3.y = lerp( 1,4, inverseLerp(t,0,10) )
}
function updateV3_x(t){
v3.z = lerp( 2,5, inverseLerp(t,0,10) )
}
function update(t){
updateV3_x(t);
updateV3_y(t);
updateV3_z(t);
} or function update(t){
const f = inverseLerp(t,0,10);
v3.x = lerp( 0, 3, f );
v3.y = lerp( 1, 4, f );
v3.z = lerp( 2, 5, f );
} second case has fewer instructions, and fewer jumps. Another point is to put animations to sleep based on their visibility, no point animating what can't be seen. Or if there is a usecase for that - put it behind a flag, let animation system only do as much work as is necessary, instead of animating all those meshes that are not visible. answering specific questions.
No, I haven't specifically profiled the animation engine. I have profiled my entire system, and I saw that a big chunk of CPU is spent in animation system, not exactly where in the animation system.
If you would consider them to be comparable - shader-based particle engines. They are pretty much entirely aimed at animation. Other than that - I don't think that comparison is easy to draw, seeing as there aren't that many mature 3d libraries in JS. So no. As an engineer - I see some areas of improvement, some of which are listed here. |
I think we'll need to find examples of high-quality animated models to profile. Comparison to skinning and other keyframe-based animation in non-JS engines like Unity and Unreal would be fair game as well. 👍 |
vs
This is exactly the kind of thing that you need to profile before assuming that it's a bottle neck - especially since these kind of obvious optimisations may well be done automatically by the JS engine.
I suspect that is not unusual - one of the biggest CPU bound operations is going to be calculating animations. Not saying that we can't make improvements, but we should do more profiling and comparison against other systems before making the statement that our system is inefficient. |
@looeee < rant > If the "community" believes that there is not problem in the animation engine, and any perceived inefficiencies could only be addressed for marginal performance gains - I would rest my case and close the issue. I don't want to push my own agenda when no one else shares it here. |
The suggestion to sleep animations for anything offscreen sounds like it would be a useful. I can't speak for anyone else in the community, but I would support at least investigating whether that can be added in a reasonably simple manner.
Are you saying that you have already implemented this in your app?
It's probably not disinterest that you hear. People have limited time and are busy working on other things. Generally, changes will happen because somebody spearheads them. In other words, if you want to see these changes then you need to start writing code and making PRs. |
Yes, i do. Visibility queries are very important for performance across my game. |
That's great! Then I'm looking forward to exploring your PR 😉 |
+1 to the above — we are interested but have limited time, and it takes a lot of work to (1) reproduce a problem in a "realistic" scenario, (2) diagnose what is wrong, (3) compare pros/cons of alternatives, (4) implement a PR. All of 1–4 take time, so the more of these steps that others can help with, the more likely we are able to spend our time on the remaining parts. I would even say 1–3 are often even more helpful than the PR itself. 🙂 |
@looeee For my pipeline, making animation sleep outside of active camera frustums - takes either integration of my ECS engine with a few subsystems other than Animation, or at the very least having a Spatial Index and Visibility set calculation code. I have both, but these are assembled into my engine, where three.js is entirely unaware of these parts. In simple terms, it's like this:
each frame:
|
Steps 4-6 would probably be fairly simple to implement. But for the rest I see a couple of issues:
|
this is a very good question question. It's more or less a question of "how can we determine bounds of an animated mesh?". There are a few possible answers to that, one is to scrub through frames and compute maximum bounding box and use that, so working with an over-estimation. There are a lot of caveats to that. Animating bounding box is also possible, pre-process animation, compute bounding box for each key-frame and animate between them. My approach currently is to use an arbitrary multiplication factor (2.0 in my case) to enlarge static bounding box. I know this is not a generic solution.
This is where the need to maintain a visibility set comes up. From my experience doing a query on a well-built AABB BVH is negligible in terms of performance, as the cost is ~log(n). There are some tricks you can do with frustum queries also.
There is surprisingly a lot of literature on this subject. I use re-insertion, when a box (X) changes bounds - i walk up the tree, looking for a parent large enough to contain it, and then walk down from there - looking for smallest descendant (Y) that would contain the volume, then build a new intermediate node as a parent for X and Y, and re-parent it to old Y's parent. It's pretty trivial, explaining it in text is more complicated than actually coding it. The process of updating bounds of individual boxes is called "refitting", this contrasts with re-building, when you basically build a new hierarchy from scratch. Refitting typically produces sub-optimal hierarchy which has a tendency to degrade over time, so if you want to retain a good structure - you need to run some kind of incremental optimization on the tree every now and then. But this is really far beyond discussion of animation and even culling :) |
This is how I did it. Works for my case (mmorpg style game). I actually tried to get this technique merged into the library, but I believe it was considered to be too app specific, which is understandable.
And then in the render loop:
|
@Usnul could you link to some of that literature? I spent a bit of time searching but didn't come across anything. Probably looking in the wrong places Also, I tried to find examples of other engines that have already implemented this and drew a blank there too. Any ideas if a generic version of something like this has already been implemented somewhere? |
@looeee Fast, Effective BVH Updates for Animated Sceneshttp://www.cs.utah.edu/~thiago/papers/rotations.pdf From my experience, if your scene doesn't have too many moving parts - just doing refitting is enough. If you have a highly dynamic scene - I believe that using BVH might be less optimal than a structure with fixed volumes such as R-tree or a kD-tree, since you need to do minimal housekeeping and they do not degrade in quality. BVH is a lot more precise though and takes less memory potentially, as you don't need to create empty volumes. @titansoftime |
Optimizations to animation engine
Currently animation engine chokes on some 500 bones being animated simultaneously, resulting in a very high CPU usage.
Motivation
It is not uncommon to see 3-5 characters at the same time with 500+ bones each in modern games, with current CPU demand such fidelity is not achievable, instead you have to compromise to about 15 bones per character in order to achieve decent performance.
born as a result of this discussion: #13807
The text was updated successfully, but these errors were encountered: