Skip to content
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

Object3D: Respect matrixWorldAutoUpdate in matrix update methods #28533

Merged
merged 5 commits into from
Jun 4, 2024

Conversation

CodyJasonBennett
Copy link
Contributor

@CodyJasonBennett CodyJasonBennett commented Jun 1, 2024

Related issue: #21387

Description

Since #24028, whenever a parent object had its world matrices updated by three, it would update child matrices unconditionally by the local override of force (#27245, #27261). Additionally, if three reaches a child with matrixWorldAutoUpdate = false, its descendant children aren't processed despite their configuration (#27261 (comment)).

I've since fixed both issues by moving the check for matrixWorldAutoUpdate when managing the parent world matrix and preserving the original functionality prior to #24028. Unit tests aren't properly isolated, which hid this bug prior, so I also reset hidden states in-between cases, which now catch these regressions.

cc @DolphinIQ, @krispya

Copy link

github-actions bot commented Jun 1, 2024

📦 Bundle size

Full ESM build, minified and gzipped.

Filesize dev Filesize PR Diff
678.5 kB (168.2 kB) 678.5 kB (168.2 kB) -48 B

🌳 Bundle size after tree-shaking

Minimal build including a renderer, camera, empty scene, and dependencies.

Filesize dev Filesize PR Diff
456.7 kB (110.3 kB) 456.6 kB (110.3 kB) -48 B

@Mugen87
Copy link
Collaborator

Mugen87 commented Jun 3, 2024

Do you mind rebasing the PR and #28534? Unfortunately, they are based on a state with broken CI. If you grab the latest commits from dev, we should easier see if something breaks.

@Mugen87
Copy link
Collaborator

Mugen87 commented Jun 4, 2024

@CodyJasonBennett Thanks for filing this PR! updateMatrixWorld() now works as intended when using matrixWorldAutoUpdate=false! Now let's fix updateWorldMatrix() as well.

@Mugen87 Mugen87 added this to the r166 milestone Jun 4, 2024
@CodyJasonBennett CodyJasonBennett changed the title Object3D: Respect matrixWorldAutoUpdate in updateMatrixWorld Object3D: Respect matrixWorldAutoUpdate in matrix update methods Jun 4, 2024
@Mugen87 Mugen87 merged commit af9ffd1 into mrdoob:dev Jun 4, 2024
12 checks passed
@CodyJasonBennett CodyJasonBennett deleted the object3d-force-manual-matrices branch June 4, 2024 22:55
@mistic100
Copy link
Contributor

mistic100 commented Jul 3, 2024

Sorry to interfer in a closed PR but I have a hard time understanding the new behaviour.
Previously I set matrixWorldAutoUpdate = false on my camera and call updateMatrixWorld() at specific times.

Now with the new condition on line 592 the matrixWorld is never updated whereas I use force = true or not, and my camera does not move anymore. Basically manual calls to updateMatrixWorld() now seem useless, the force flag being ignored.

This is done because I need the camera matrix to be updated before rendering, I cannot wait for the WebGLRenderer to kick in. And I wanted to avoid updating the matrix twice on each frame.

Alternative I considered : do it entirely manually

this.camera.updateMatrix();
this.camera.matrixWorld.copy(this.camera.matrix);

Thanks

@Mugen87
Copy link
Collaborator

Mugen87 commented Jul 3, 2024

matrixWorldAutoUpdate does what it is stated in the documentation.

If set, then the renderer checks every frame if the object and its children need matrix updates. When it isn't, then you have to maintain all matrices in the object and its children yourself.

Yes, there is a difference between matrixWorldAutoUpdate and matrixAutoUpdate. If matrixAutoUpdate is set to false, you can still update the model matrix by calling Object3D.updateMatrix(). This is not possible with the world matrix though and is indeed an inconsistency.

TBH, I'm not super happy with how matrixWorldAutoUpdate works. Sometimes I think it would be best to completely remove it since it made the code only more contradictory. On the other hand, there are devs which use it for performance improvements and without matrixWorldAutoUpdate there is no way to optimize the world matrix computations.

So until there is a new world matrix update routine, you indeed have to manage the world matrix manually if you set matrixWorldAutoUpdate to false.

@mistic100
Copy link
Contributor

Thanks for those informations.

Still I think the "force" flag should be removed entirely has it does nothing but clear the "needsMatrixWorldUpdate" property without actually upadting the matrix.

@soadzoor
Copy link
Contributor

soadzoor commented Nov 1, 2024

Sorry to interfer in a closed PR but I have a hard time understanding the new behaviour. Previously I set matrixWorldAutoUpdate = false on my camera and call updateMatrixWorld() at specific times.

Now with the new condition on line 592 the matrixWorld is never updated whereas I use force = true or not, and my camera does not move anymore. Basically manual calls to updateMatrixWorld() now seem useless, the force flag being ignored.

This is done because I need the camera matrix to be updated before rendering, I cannot wait for the WebGLRenderer to kick in. And I wanted to avoid updating the matrix twice on each frame.

Alternative I considered : do it entirely manually

this.camera.updateMatrix();
this.camera.matrixWorld.copy(this.camera.matrix);

Thanks

I also had a hard time figuring out why all my objects are messed up after a three.js upgrade. I narrowed it down to this PR, which came with r166.

I also figured out that the world matrix cannot be updated manually anymore if the "matrixWorldAutoUpdate" is set to false. However, for performance reasons, that's how I did it in the past 2 years, I updated the local-, and worldmatrices manually whenever it was necessary.

Now, with r166, I'm using this hack as a workaround:

const prevMatrixWorldAutoUpdate = element.matrixWorldAutoUpdate;
element.matrixWorldAutoUpdate = true;
element.updateMatrix();
element.updateMatrixWorld();
element.matrixWorldAutoUpdate = prevMatrixWorldAutoUpdate;

@soadzoor
Copy link
Contributor

soadzoor commented Nov 4, 2024

Just to give another update: The above workaround doesn't work all the time, for example if the element has some children.

It would be nice to have a way to manually update the worldmatrix of an object3d (respecting the ancestors', and descendants' matrices as well). Currently it seems there's basically no easy way of doing it

@CodyJasonBennett
Copy link
Contributor Author

Still I think the "force" flag should be removed entirely has it does nothing but clear the "needsMatrixWorldUpdate" property without actually upadting the matrix.

Maybe the solution is to have force update the subtree despite configured flags but not use it in three.js where possible (nor override it internally like before). This was my intuition for how the API should behave, but I'm a little out of the loop now. The primary use case is changing the rate at which a subtree updates and not caring about specific nodes within—that would be fully manual anyway with a bespoke system for tracking updates. The most simple is skipping a fully static subtree.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants