-
-
Notifications
You must be signed in to change notification settings - Fork 35.2k
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
Performance optimization by optionally sharing matrix between child & parent #25142
Performance optimization by optionally sharing matrix between child & parent #25142
Conversation
Perf not looking great - linked list probably not a good solution as deciding when to stop traversing is too expensive.
Linked list was performing worse, not better.
Saves having to reference data on Object3D during updateMatrix()
This reverts commit 1ba542c.
…zie/three.js into Object3dMatrixData
I'm afraid this is a too specific use case... I think there are not many meshes with default position, rotation, and scale (which could benefit from this) normally, except in that use case you described. |
This also broke unit tests as it creates infinite recursion when comparing objects.
Fixes example webgl_loader_mmd
Code left over from having started with a slightly different implementation for extending updateMatrixWorld(). Can be removed now.
Caught up with latest proposed code on #25114 |
Maybe. Another use case where I find myself creating objects with default position / rotation & scale is where a 3D artist has already taken care of positioning & encoded it in the model's origin. That's quite common in my experience, as it's much easier for a 3D artist to line up multiple objects just as they want them in their 3D design environment, and just export, rather than having to separately communicate correct positioning of each object. With this approach, many/most 3D objects can end up with the transform of their root THREE.Group just being the default position/rotation/scale. |
Left over from an earlier implementation attempt.
For anyone interested, I've been experimenting with a version of this in super-three (the A-Frame fork of three) and A-Frame. Branches here: Been using some A-Frame-ified versions of the THREE.js Benchmarks. Performance gains on updateMatrixWorld() are extremely promising... 4+ times speed-up... Build here should be viable if anyone wants to try this out... |
Chrome perf profiling showing reduction in updateMatrixWorld() CPU usage in this example: (about 67% reduction) https://diarmidmackenzie.github.io/instanced-mesh/examples/coloring-blocks/index.html @takahirox This may be of interest to you. |
Thanks for your work on this but unfortunately this PR contains way to many substantial API changes that can not be applied to the library. Besides, sharing matrices between child and parent nodes is not something users should care about. Providing the opportunity to explicitly enable/disable matrix sharing with method calls is the wrong way, imo. The goal has to be speeding up the world matrix computation process without affecting user level code as much as possible. Everything else is not acceptable regarding the maturity level of |
Further explanation: We can't go for best possible performance in |
Thanks for the feedback on this. This point:
actually applies to #25114 (which this PR builds on), and turns out to be a fixable issue. I have pushed an update to that PR. On this point:
I have some sympathy with this - the code in this PR was intended to illustrate & explore breaking the alignment between the Object3D graph, and the Object3DMatrixData graph introduced by #25114. I'm not particularly attached to any particular mechanism for mediating the relationships between the two layers. I do think there are potentially very significant performance gains to be made by relaxing the assumption that every Object3D needs have its own unique transform. But I'm happy to concede that more work would be needed to deliver this in a way that minimizes the level of interface change for existing users. |
Description
This is a somewhat speculative PR. It builds on #25114, to offer a couple of new functions on Object3D that can be used to substantially boost performance of updateMatrixWorld(), permitting more objects in a scene.
#25114 added a new class Object3DMatrixData, and a new tree of Object3DMatrixData objects that mirrors the existing scene graph of Object3Ds.
The motivation for this was to allow monomorphic (hence, higher performance) iteration through the scene graph when updating matrices in updateMatrixWorld().
However, the existence of this "matrix graph" that exists parallel to the "scene graph" opens up other possibilities for further performance gains. In particular one interesting option is to prune unecessary nodes from the "matrix graph", so that it is smaller, and hence faster to iterate through.
One context where this would be particularly valuable is in A-Frame. In A-Frame, every
<a-entity>
is instantiated as a THREE.Group, with additional child Object3Ds as required to instantiate Meshes, Lights etc. This means that the THREE.js scene graph for a typical A-Frame scene consists of a THREE.Group and a THREE.Mesh for each entity.Typically the THREE.Group has a meaningful matrix, encoding position, rotation & scale, while the THREE.Mesh matrix is an identity matrix, with default position, scale & rotation.
This can create performance issues in some applications, particularly on
updateMatrixWorld()
e.g. Hubs-Foundation/hubs#5311This PR provides 2 new methods on the Object3D:
shareParentMatrix()
configures the Object3D to use it's parent's Object3DMatrixData, and trims this Object3D's Object3DMatrixData out of the "matrix graph".restorePrivateMatrix()
reverses the above operation.Either A-Frame itself, or an A-Frame application, could call
shareParentMatrix()
on every THREE.Mesh that is a child of a THREE.Group, and does not itself have any position, rotation or scale.If done across the scene, this would result in a substantial (up to 50%) reduction to the size of the "matrix tree" and thus a substantial gain (again, up to 50%) in performance of updateMatrixWorld()
When rendering the mesh, the renderer would use the matrix data from its parent, which would still result in the correct rendering position.
Applications could also make use of this in other specific situations where objects/entities are known to always take the identity/default transformation matrix.
** Current state of the PR **
updateMatrixWorld()
it will be necessary to ensure that all code that combines matrices up/down the scene graph is moved across to use the new "matrix graph". One example isupdateWorldMatrix()
and there may be others as well.