playcanvas / engine

JavaScript game engine built on WebGL, WebGPU, WebXR and glTF
https://playcanvas.com
MIT License
9.53k stars 1.33k forks source link

Optimize bone skinning - hierarchy #2203

Open mvaligursky opened 4 years ago

mvaligursky commented 4 years ago

Related to #2202.

Currently to render the animated character, we sync the hierarchy to generate world matrices for bones. Then we multiply those matrices by inverse character root bone matrix to have them in local space - which is pretty expensive.

We should explore a possibility to create an optimized hierarchy structure for characters to speed this up:

mvaligursky commented 4 years ago

I wrote a quick prototype for this, and the results are reasonably positive. I created a scene with 100 of characters, each 70 bones, single mesh/skin each. The syncHierarchy for this takes 3ms per frame on MacBook Pro.

Disabling hierarchy update, and moving it to SkinInstance.updateMatrices saved those 3ms, while not changing cost of updateMatrices, as the need to multiply matrix with inverse of root is removed, and replaced by a matrix multiply to 'update hierarchy' - multiply local matrix with parent matrix. The result are still 2 matrix multiplies per bone.

Positive - by removing multiply with inverse root, we improve precision of skinning, as hierarchy update of character takes place in character's space, instead of evaluating it at world space and then bringing it to character space for rendering, when precision of floats in Mat4 has already been lost.

Overall - this is a nice optimization, but only saves about 3ms in the frame from about 80. Priority should be given to following issues which have the potential to move the needle a lot more:

2351

2352

Maksims commented 4 years ago

In future, hoping for SIMD to get available in JS, it will dramatically improve CPU based Math of the engine.