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

Box3: optimized matrix transform - ApplyMatrix4 #28348

Closed
wants to merge 2 commits into from

Conversation

sciecode
Copy link
Contributor

Little known optimization for AABB matrix transformation.

Instead of performing a Vec3/Matrix multiplication 8 times (one for each corner), we instead perform only 2.
Once for the center of the box, and a direction transformation (normal-like) for the extent (half-size).
Then we reconstruct the box bounds back in the correct coordinate space.

AABB/Matrix Optimization Blog by Arseny Kapoulkine (Zeux)

Tests, on different devices, show a 3-5x performance gain.

10k 100k 500k 1M
original 1.33 ms 8.34 ms 39.58 ms 79.08 ms
new 0.37 ms 2.13 ms 9.15 ms 17.33 ms
ratio 3.59 3.91 4.32 4.56

Copy link

github-actions bot commented May 12, 2024

📦 Bundle size

Full ESM build, minified and gzipped.

Filesize dev Filesize PR Diff
678.6 kB (168.1 kB) 678.4 kB (168.1 kB) -215 B

🌳 Bundle size after tree-shaking

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

Filesize dev Filesize PR Diff
457.8 kB (110.4 kB) 457.5 kB (110.4 kB) -215 B

@sciecode
Copy link
Contributor Author

sciecode commented May 12, 2024

Unfortunately this won't work. It only supports affine-transformations in its current form.

A similar attempt to change the Box3.ApplyMatrix4 was already made & reverted, due to #14655.
So I imagine the same thing would happen here.

Perhaps we could introduce an affine only transformation for this?

I don't see many reasons to transform a Box3 to NDC. Since it's very easy to end up with NaNs and Infinity due to perspective divide. Even for the cases where users want a simpler frustum culling, clip-space is usually used (currently impossible), not NDC.

Eitherway, using an affine-transform is likely much more common, and having a specialized function that doesn't incur a 4x performance penalty is probably desirable.

@WestLangley @Mugen87 thoughts?

@WestLangley
Copy link
Collaborator

Perhaps we could introduce an affine only transformation for this?

I think it would be better to test if the matrix is affine, and use the proposed algorithm if it is, and the existing algorithm if it is not.

But I would only do that if there is a compelling use case to justify doing so.

@sciecode
Copy link
Contributor Author

sciecode commented May 13, 2024

I can provide a few recurring uses for my projects.

I often rewrite a custom frustum culling system, which transforms object's AABB to world-space, independant of the default system. I do this for one of two reasons:

Either because the default sphere bounding volume isn't well suited for tiled/grids/octree based entities, and a bounding-box provides tighter culling for potentially expensive render entities. Or because the DAG-based scene traversal is extremelly slow for a large number of nested entities, and it can be more efficiently computed by flattening the traversal and/or use Object AABB's that don't recurse all the way down.

Another common usage has been when building alternative raycasting systems that also don't suffer from the default system traversal / excess of unnecessary information.

I did a quick search and every single instance of Box3.applyMatrix4 internal to three.js (although there aren't many), do use it with affine-transformation.
Edit: Actually, there are quite a few, specifically in the editor, which uses Box3.setFromObject and internally calls applyMatrix4. Always with affine-transforms.


Also worth mentioning, I already use the proposed method for my own uses. In fact the only reason I noticed that ApplyMatrix4 wasn't implemented this way, was because I mistakenly used it in my own project and noticed a 5x performance degradation of a very hot loop. So I decided to share this with others that might also be running into this.

@Mugen87
Copy link
Collaborator

Mugen87 commented May 21, 2024

I would favor a single code path and not multiple ones depending on the input matrix. I have the feeling this would overcomplicate things.

@sciecode
Copy link
Contributor Author

sciecode commented May 21, 2024

I agree. I would prefer to introduce a separate function applyAffine which makes use of the proposed optimization. And we update methods that are guaranteed to only call this method with affine-transforms, so that they may make use of the fast path (like setFromObject).

If that's acceptable, I'll patch the PR. Otherwise, let me know so I can close it.

@sciecode sciecode closed this May 22, 2024
@sciecode sciecode deleted the aabb-transform branch May 22, 2024 22:29
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.

None yet

3 participants