bevy/crates
Matty 900f50d77d
Uniform mesh sampling (#14071)
# Objective

Allow random sampling from the surfaces of triangle meshes.

## Solution

This has two parts.

Firstly, rendering meshes can now yield their collections of triangles
through a method `Mesh::triangles`. This has signature
```rust
pub fn triangles(&self) -> Result<Vec<Triangle3d>, MeshTrianglesError> { //... }
```

and fails in a variety of cases — the most obvious of these is that the
mesh must have either the `TriangleList` or `TriangleStrip` topology,
and the others correspond to malformed vertex or triangle-index data.

With that in hand, we have the second piece, which is
`UniformMeshSampler`, which is a `Vec3`-valued
[distribution](https://docs.rs/rand/latest/rand/distributions/trait.Distribution.html)
that samples uniformly from collections of triangles. It caches the
triangles' distribution of areas so that after its initial setup,
sampling is allocation-free. It is constructed via
`UniformMeshSampler::try_new`, which looks like this:
```rust
pub fn try_new<T: Into<Vec<Triangle3d>>>(triangles: T) -> Result<Self, ZeroAreaMeshError> { //... }
```

It fails if the collection of triangles has zero area. 

The sum of these parts means that you can sample random points from a
mesh as follows:
```rust
let triangles = my_mesh.triangles().unwrap();
let mut rng = StdRng::seed_from_u64(8765309);
let distribution = UniformMeshSampler::try_new(triangles).unwrap();
// 10000 random points from the surface of my_mesh:
let sample_points: Vec<Vec3> = distribution.sample_iter(&mut rng).take(10000).collect();
```

## Testing

Tested by instantiating meshes and sampling as demonstrated above.

---

## Changelog

- Added `Mesh::triangles` method to get a collection of triangles from a
mesh.
- Added `UniformMeshSampler` to `bevy_math::sampling`. This is a
distribution which allows random sampling over collections of triangles
(such as those provided through meshes).

---

## Discussion

### Design decisions

The main thing here was making sure to have a good separation between
the parts of this in `bevy_render` and in `bevy_math`. Getting the
triangles from a mesh seems like a reasonable step after adding
`Triangle3d` to `bevy_math`, so I decided to make all of the random
sampling operate at that level, with the fallible conversion to
triangles doing most of the work.

Notably, the sampler could be called something else that reflects that
its input is a collection of triangles, but if/when we add other kinds
of meshes to `bevy_math` (e.g. half-edge meshes), the fact that
`try_new` takes an `impl Into<Vec<Triangle3d>>` means that those meshes
just need to satisfy that trait bound in order to work immediately with
this sampling functionality. In that case, the result would just be
something like this:
```rust
let dist = UniformMeshSampler::try_new(mesh).unwrap();
```
I think this highlights that most of the friction is really just from
extracting data from `Mesh`.

It's maybe worth mentioning also that "collection of triangles"
(`Vec<Triangle3d>`) sits downstream of any other kind of triangle mesh,
since the topology connecting the triangles has been effectively erased,
which makes an `Into<Vec<Triangle3d>>` trait bound seem all the more
natural to me.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-07-08 00:57:08 +00:00
..
bevy_a11y Bump accesskit to 0.16 (#14091) 2024-07-01 14:42:40 +00:00
bevy_animation Added get_main_animation for AnimationTransitions (#14104) 2024-07-02 13:28:42 +00:00
bevy_app Apply Clippy lints regarding lazy evaluation and closures (#14015) 2024-07-01 15:54:40 +00:00
bevy_asset EmptyPathStream is only used in android/wasm32 (#14200) 2024-07-07 19:54:53 +00:00
bevy_audio Optimize common usages of AssetReader (#14082) 2024-07-01 19:59:42 +00:00
bevy_color Allow bevy_color use without bevy_reflect support (#13870) 2024-06-16 15:47:30 +00:00
bevy_core Don't show .to_bits in Display impl for Entity (#14011) 2024-06-25 17:08:24 +00:00
bevy_core_pipeline Apply Clippy lints regarding lazy evaluation and closures (#14015) 2024-07-01 15:54:40 +00:00
bevy_derive Deprecate dynamic plugins (#13080) 2024-05-20 20:01:28 +00:00
bevy_dev_tools Merge BuildWorldChildren and BuildChildren traits. (#14052) 2024-07-01 14:29:39 +00:00
bevy_diagnostic Poll system information in separate tasks (#13693) 2024-06-10 19:06:22 +00:00
bevy_dylib Add README.md to all crates (#13184) 2024-05-02 18:56:00 +00:00
bevy_dynamic_plugin Deprecate dynamic plugins (#13080) 2024-05-20 20:01:28 +00:00
bevy_ecs Component Hook functions as attributes for Component derive macro (#14005) 2024-07-08 00:46:00 +00:00
bevy_encase_derive Add README.md to all crates (#13184) 2024-05-02 18:56:00 +00:00
bevy_gilrs Add README.md to all crates (#13184) 2024-05-02 18:56:00 +00:00
bevy_gizmos Use u32 for all resolution/subdivision fields in bevy_gizmos (#13927) 2024-06-19 17:28:10 +00:00
bevy_gltf EmptyPathStream is only used in android/wasm32 (#14200) 2024-07-07 19:54:53 +00:00
bevy_hierarchy Fix push_children inserting a Children component even when no children are supplied (#14109) 2024-07-02 13:27:02 +00:00
bevy_input Mouse input accumulation (#14044) 2024-07-01 14:27:21 +00:00
bevy_internal Cosmic text (#10193) 2024-07-04 20:41:08 +00:00
bevy_log Document use of NO_COLOR in LogPlugin (#13984) 2024-06-24 21:04:55 +00:00
bevy_macro_utils Add README.md to all crates (#13184) 2024-05-02 18:56:00 +00:00
bevy_math Uniform mesh sampling (#14071) 2024-07-08 00:57:08 +00:00
bevy_mikktspace Fixed a link to Blender's mikktspace docs (#13924) 2024-06-19 12:37:10 +00:00
bevy_pbr impl Debug for ExtendedMaterial (#14140) 2024-07-04 23:59:48 +00:00
bevy_picking Upstream CorePlugin from bevy_mod_picking (#13677) 2024-06-15 11:59:57 +00:00
bevy_ptr add Debug for ptr types (#13498) 2024-05-24 21:25:11 +00:00
bevy_reflect bevy_reflect: Re-enable reflection compile fail tests (#14165) 2024-07-05 20:49:03 +00:00
bevy_render Uniform mesh sampling (#14071) 2024-07-08 00:57:08 +00:00
bevy_scene Send SceneInstanceReady when spawning any kind of scene (#11741) 2024-07-06 14:00:39 +00:00
bevy_sprite Cosmic text (#10193) 2024-07-04 20:41:08 +00:00
bevy_state Move StateTransitionSteps registration to states plugin (#13939) 2024-06-20 00:57:40 +00:00
bevy_tasks Apply Clippy lints regarding lazy evaluation and closures (#14015) 2024-07-01 15:54:40 +00:00
bevy_text Cosmic text (#10193) 2024-07-04 20:41:08 +00:00
bevy_time Make time_system public (#13879) 2024-06-16 18:07:41 +00:00
bevy_transform Merge BuildWorldChildren and BuildChildren traits. (#14052) 2024-07-01 14:29:39 +00:00
bevy_ui Optimize ui_layout_system (#14064) 2024-07-08 00:48:35 +00:00
bevy_utils Remove unused type parameter in Parallel::drain() (#14178) 2024-07-06 13:29:29 +00:00
bevy_window apply window scale to window size when creating it (#13967) 2024-06-21 18:04:57 +00:00
bevy_winit Bump accesskit to 0.16 (#14091) 2024-07-01 14:42:40 +00:00