Skip to content

Conversation

@ChristopherBiscardi
Copy link
Contributor

@ChristopherBiscardi ChristopherBiscardi commented Dec 29, 2025

Objective

People have been asking how to get a compute shader-built mesh into bevy's "stuff".

Some people want to control the lifetime of the mesh via Handle, and others don't don't how to set data in bind groups.

Solution

a new example that shows how to initialize a mesh handle with a render_world usage mesh, and then put the output of the compute shader into the mesh_allocator slab for the mesh.

The demo creates a scene with a camera, light, a circular base mesh, and an empty "cube to be" mesh that is shared by cloning the handle across two entities. The compute shader then fills in the data directly into the mesh_allocator slabs for the vertex/index buffers.

If the compute shader failed, there would be no cube meshes showing as the data would be empty.

Testing

cargo run --example compute_mesh

Showcase

screenshot-2025-12-29-at-16 06 48@2x
@github-actions
Copy link
Contributor

The generated examples/README.md is out of sync with the example metadata in Cargo.toml or the example readme template. Please run cargo run -p build-templated-pages -- update examples to update it, and commit the file change.

@ChristopherBiscardi ChristopherBiscardi marked this pull request as ready for review December 29, 2025 19:01
@ChristopherBiscardi ChristopherBiscardi added A-Rendering Drawing game state to the screen S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Dec 29, 2025
@ChristopherBiscardi ChristopherBiscardi added the C-Examples An addition or correction to our examples label Dec 29, 2025
@alice-i-cecile alice-i-cecile added X-Uncontroversial This work is generally agreed upon D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes labels Dec 29, 2025
// Add the compute node as a top-level node to the render graph. This means it will only execute
// once per frame. Normally, adding a node would use the `RenderGraphApp::add_render_graph_node`
// method, but it does not allow adding as a top-level node.
render_graph.add_node(ComputeNodeLabel, ComputeNode::default());
Copy link
Contributor

Choose a reason for hiding this comment

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

I can't remember if this is right or not. I think you may need to order it vs the camera driver node?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added the edge here, but I'm really not sure it has any impact here (but it definitely doesn't hurt). Figuring out what the render graph actually looks like could use some debug visualization. Maybe a function that returns a dotviz 🤔

Copy link
Member

@tychedelia tychedelia left a comment

Choose a reason for hiding this comment

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

thanks!! i've wanted this for a while but only hesitated because i've felt like it should be easier. i have some ideas though and so think this will be a good target to improve things incrementally here

render_app
.world_mut()
.resource_mut::<MeshAllocator>()
.extra_buffer_usages = BufferUsages::STORAGE;
Copy link
Contributor

@IceSentry IceSentry Dec 29, 2025

Choose a reason for hiding this comment

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

This feels a bit off. It seems weird that this needs to modify a global resource. But I'm not sure if there's a better alternative

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It feels like something that should be configurable by inserting a Resource or similar rather than modifying this one, yeah. but the MeshAllocator fields are private and initializing it using its FromWorld implementation is probably more awkward (it also has ordering requirements with other resources).

I also wanted to pass the BufferSlice to the shader instead of the full buffer, but I don't think the offsets match the storage buffer offset requirements (it was 256 on my machine and the offsets I saw were numbers like 4, 12, etc)

@IceSentry
Copy link
Contributor

Could you make it so the cubes aren't clipping the circle mesh? I don't generally comment about the look of examples but it looks a bit strange in it's current state.

Also, if I'm reading this correctly this ends up modifying the mesh every frame right? I'd suggest maybe changing the scale every frame to show this is happening.

@ChristopherBiscardi
Copy link
Contributor Author

Could you make it so the cubes aren't clipping the circle mesh?

Updated.

Also, if I'm reading this correctly this ends up modifying the mesh every frame right? I'd suggest maybe changing the scale every frame to show this is happening.

I instead updated this so that it will only generate once per unique GenerateMesh. I envision this particular example to be more of a "generate the N chunks around a player" as they move through a world, so continuing to generate every frame doesn't make sense.

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-Examples An addition or correction to our examples D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes S-Needs-Review Needs reviewer attention (from anyone!) to move forward X-Uncontroversial This work is generally agreed upon

5 participants