Skip to content

Add options to lower precision/compressed vertex buffer#21926

Merged
alice-i-cecile merged 73 commits into
bevyengine:mainfrom
beicause:mesh-attributes-low-precision
Jun 2, 2026
Merged

Add options to lower precision/compressed vertex buffer#21926
alice-i-cecile merged 73 commits into
bevyengine:mainfrom
beicause:mesh-attributes-low-precision

Conversation

@beicause

@beicause beicause commented Nov 24, 2025

Copy link
Copy Markdown
Member

Objective

Resolves #21902.

Solution

This PR adopts a relatively transparent approach to reduce the GPU vertex buffer size. On CPU-side mesh can still use uncompressed Float32 data, and users are not required to insert compressed vertex formats. The vertex data is automatically processed into lower-precision/octahedral encoded data when uploading to the GPU.

To enable vertex attribute compression, just set the attribute_compression field of Mesh, or set mesh_attribute_compression of GltfLoaderSettings. If enabled, normal and tangent will be octahedral encoded Unorm16x2, uv0, uv1, joint weight and color will be corresponding Unorm16 or Float16. I also provide Unorm8x4 for vertex color if hdr isn't needed.

Update:

Added compressed_mesh method to Mesh to construct compressed Mesh ahead of time. GltfLoader can also opt-in mesh compressing when loading. I also add an option to convert indices to u16, though I believe blender gltf exporter already uses u16 indices when possible.

For users, the usage is:

  1. Call Mesh.compressed_mesh to compress the mesh or use options in GltfLoader.
  2. Handle compressed vertices in shaders if you use custom vertex shader. The default vertex shader already handles it. See mesh2d_vertex_input.wgsl, prepass_io.wgsl, forward_io.wgsl
    for the default Vertex definitions and decompress_vertex.

Testing

Run many_cubes, many_foxes, many_morph_targets with --vertex-compression to test 3d.
Run bevymark with sprite_mesh to test 2d, because SpriteMesh uses compressed quad mesh now.

@JMS55 JMS55 self-requested a review November 24, 2025 03:20
@JMS55

JMS55 commented Nov 24, 2025

Copy link
Copy Markdown
Contributor

This will need some thinking on how it interacts with Virtual Geometry and Solari, which rely on hardcoded vertex formats.

@greeble-dev

Copy link
Copy Markdown
Contributor

For the octahedral normals and tangents, encoding as UNORM16 or SNORM16 should give better accuracy? Unless there's some compatibility or performance reason to prefer floats.

For joint weights, I'd similarly suggest UNORM16. Unless Bevy wants to support joints weights greater than one - I don't know of any engine that does this. For bonus points it should also adjusted the encoded weights to make sure they sum to one.

@greeble-dev greeble-dev added C-Feature A new feature, making something new possible A-Rendering Drawing game state to the screen C-Performance A change motivated by improving speed, memory usage or compile times S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Nov 24, 2025
@github-actions

Copy link
Copy Markdown
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-21926

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

2 similar comments
@github-actions

Copy link
Copy Markdown
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-21926

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

@github-actions

Copy link
Copy Markdown
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-21926

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

@greeble-dev

greeble-dev commented Nov 24, 2025

Copy link
Copy Markdown
Contributor

@beicause, I noticed that you also changed the UVs from FLOAT16 to UNORM16. That might be a problem for some assets since it's legitimate for UVs to be outside the [0, 1] range.

I'm not sure what the best option is for UVs, so maybe worth seeing if someone else has an opinion. From a glance it seems like Unreal supports FLOAT16/32. Godot does use UNORM16 but scales them to fit the maximum value if they're outside of [0, 1] (ref 1, ref 2).

@greeble-dev greeble-dev added the C-Dependencies A change to the crates that Bevy depends on label Nov 24, 2025
@greeble-dev

Copy link
Copy Markdown
Contributor

Also, could the PR description say whether compression is enabled by default? The description currently sounds like it's disabled by default, but the code seems like it's enabled by default. I can't speak for anyone else, but I'm guessing most people would prefer it to be disabled by default.

@beicause

Copy link
Copy Markdown
Member Author

I think using float16 for UVs is worthwhile because the benefits of unorm16 may be limited after thought.

I would probably like to enable compression by default, as other engines seem to do this by default as well. Enabling compression generally provides a net benefit, and users can opt-out if issues arise.

@github-actions

Copy link
Copy Markdown
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-21926

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

@greeble-dev greeble-dev added the X-Contentious There are nontrivial implications that should be thought through label Nov 24, 2025
@greeble-dev

Copy link
Copy Markdown
Contributor

Added X-Contentious as I expect there'll be various opinions on enabling by default. Also added C-Dependencies as the PR adds a dependency on half to bevy_mesh - although I'm not sure if the label is appropriate since half is already used by bevy_image.

@github-actions

Copy link
Copy Markdown
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-21926

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

@JMS55

JMS55 commented Dec 1, 2025

Copy link
Copy Markdown
Contributor

Some quick drive by thoughts:

  • f16 UVs are definitely dangerous. We should probably avoid enabling that one by default.
  • f16 positions would be great to have. I'd like to use them in Solari.
  • We should take advantage of the f16 type in wgsl shaders where we can and where it's beneficial) to save registers

@greeble-dev

Copy link
Copy Markdown
Contributor

For positions, I'd suggest an AABB-relative unorm16 instead of f16. It's a faff to set up but the worst case error is much lower. I've seen both tried for moderate to high poly characters, and the f16 version had noticeable artifacts.

@JMS55

JMS55 commented Dec 1, 2025

Copy link
Copy Markdown
Contributor

The reason I suggest f16 is that it's one of the few supported BLAS formats for raytracing https://github.com/Vecvec/wgpu/blob/3e9ede6c38012d6c134e1ced689ded2f58dec49f/wgpu-types/src/features.rs#L1497-L1501, and it has pretty significant improvements over f32 https://zeux.io/2025/03/31/measuring-acceleration-structures/

@beicause beicause force-pushed the mesh-attributes-low-precision branch from 5999291 to 8b85876 Compare December 2, 2025 01:30
@github-actions

github-actions Bot commented Dec 2, 2025

Copy link
Copy Markdown
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-21926

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

@beicause

beicause commented Dec 2, 2025

Copy link
Copy Markdown
Member Author

I've added snorm16 positions relative to AABB. Its precision should be as good as unorm16. And it seems that the BLAS supports it?

@github-actions

github-actions Bot commented Dec 2, 2025

Copy link
Copy Markdown
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-21926

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

1 similar comment
@github-actions

github-actions Bot commented Dec 2, 2025

Copy link
Copy Markdown
Contributor

Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-21926

If it's expected, please add the M-Deliberate-Rendering-Change label.

If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it.

@JMS55

JMS55 commented Dec 2, 2025

Copy link
Copy Markdown
Contributor

This deserves a thorough review by me, but I unfortunately won't have time for the next while due to work. Apologies - it's something I'm definitely excited to land though!

@tychedelia

Copy link
Copy Markdown
Member

I have moved the metadata to mesh slab using a ssbo if supported, otherwise each mesh allocates dedicated uniform slab.

Thanks! That's a great solution. Will review soon. Am going to put this in 0.20 for now.

@cart cart closed this May 5, 2026
@github-project-automation github-project-automation Bot moved this from Needs SME Triage to Done in Rendering May 5, 2026
@cart cart reopened this May 5, 2026
@github-project-automation github-project-automation Bot moved this from Done to Needs SME Triage in Rendering May 5, 2026
@greeble-dev

Copy link
Copy Markdown
Contributor

@tychedelia, do you still plan to review this PR? Asking because it has enough approvals to be S-Ready-For-Final-Review, but I'm not sure whether to do that if you still want to review.

@alice-i-cecile alice-i-cecile self-requested a review May 27, 2026 14:02
@alice-i-cecile alice-i-cecile added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels May 27, 2026

@alice-i-cecile alice-i-cecile left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe my criticism has been resolved now, we have rendering approval and the core idea is worth doing. Merging; we can revert or revise as needed.

@alice-i-cecile alice-i-cecile added this pull request to the merge queue Jun 1, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jun 1, 2026
@alice-i-cecile alice-i-cecile enabled auto-merge June 2, 2026 03:22
@alice-i-cecile alice-i-cecile added this pull request to the merge queue Jun 2, 2026
Merged via the queue into bevyengine:main with commit 7517c61 Jun 2, 2026
42 checks passed
@github-project-automation github-project-automation Bot moved this from Needs SME Triage to Done in Rendering Jun 2, 2026
@beicause beicause deleted the mesh-attributes-low-precision branch June 2, 2026 05:17
@Affinator

Copy link
Copy Markdown

The release content is for another CR (and therefore a clear description what really changed, since the description of this PR is not really detailed) and I think an example is missing to show how to use this.

Should this be fixed in a follow-up PR?

@beicause

beicause commented Jun 2, 2026

Copy link
Copy Markdown
Member Author

The release content is for another CR (and therefore a clear description what really changed, since the description of this PR is not really detailed) and I think an example is missing to show how to use this.

Should this be fixed in a follow-up PR?

Usage:

  1. Call Mesh.compressed_mesh to compress the mesh or use options in GltfLoader.
  2. Handle compressed vertices in shaders if you use custom vertex shader. The default vertex shader already handles it. See mesh2d_vertex_input.wgsl, prepass_io.wgsl, forward_io.wgsl
    for the default Vertex definitions and decompress_vertex.

I think a separate example isn't necessary. It's like handling morph and skin but not all examples handled them for simplicity.

That said, a release note may be worth it. Should we add one for this?

pull Bot pushed a commit to octoape/bevy that referenced this pull request Jun 3, 2026
…24520)

# Objective

Fixes regression from bevyengine#21926

## Solution

Fixes shader import errors

## Testing

Tested deferred_rendering, atmosphere and meshlet examples.
slyedoc added a commit to slyedoc/bevy that referenced this pull request Jun 6, 2026
Upstream bevyengine#21926 relocated the octahedral helpers from bevy_pbr::utils to bevy_render::utils. Update the two cluster scene-binding shader imports so they resolve at pipeline-compile time after the rebase onto current main. (Shaders validate at runtime, so the Rust build didn't catch this.)
greeble-dev added a commit to greeble-dev/bevy that referenced this pull request Jun 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Rendering Drawing game state to the screen C-Dependencies A change to the crates that Bevy depends on C-Feature A new feature, making something new possible C-Performance A change motivated by improving speed, memory usage or compile times M-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it X-Contentious There are nontrivial implications that should be thought through

Projects

Status: Done
Status: No status

Development

Successfully merging this pull request may close these issues.

Use low precision format for vertex attributes

8 participants