bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
35.7k stars 3.53k forks source link

Simultaneous mutable/immutable access to different mesh attributes #2134

Open SorteKanin opened 3 years ago

SorteKanin commented 3 years ago

What problem does this solve or what need does it fill?

You cannot at the moment have a mutable and an immutable reference to different mesh attributes at the same time. My specific use case that caused me to file this feature requests was when I was trying to calculate normals for a generated mesh. The normals must be calculated from the geometry. Hence I need mutable access to the normals and immutable access to the positions and indices. I need to clone the positions and indices to do this at the moment and I don't think having mutable access to both positions and normals is possible at all. It would be nice if this was possible.

What solution would you like?

Not sure what is best but it would be great if there was a way to access (both mutably and immutably) mesh attributes simultaneously.

What alternative(s) have you considered?

For my specific use case I can clone but this is needlessly expensive. For the use case of simultaneous mutable access to different mesh attributes, I suspect there is no way to do it.

cart commented 3 years ago

If we stored attributes in a Vec instead of a BTreeMap (or other key/value pair collections like HashMap) we could safely do split_at_mut to get multiple attributes. The downside it that implementation complexity goes up (and lookup perf likely goes down)

cart commented 3 years ago

It would be nice if rust key/value collections exposed a get_disjoint_mut(keys: &[Key]) -> &mut [Value] style api, but I totally get why they dont. (they need to check for collisions, which is expensive).

cart commented 3 years ago

Alternatively, we could add interior mutability by wrapping values in RefCell (although Mesh needs to be Send/Sync, which means this would probably need Mutex instead)

SorteKanin commented 3 years ago

I'm just starting out using Bevy and don't know much about the internals, but I'm just shooting ideas here. Could it not be possible to split a mesh into several different components? As in, instead of an entity having a mesh (handle) component, it would have a positions (handle I guess) component and a normals component and so on. Then you could mutably query for both positions and normals components simultaneously, just like you would with other components. Just spitballing, don't know if this is a viable idea.

cart commented 3 years ago

Meshes are currently stored in an Assets collection, which is a Resource. This means that they cannot have components added to them.

Handling Assets like this as components is a novel idea, but I have a feeling that breaking it up would ultimately make it harder to work with.

SorteKanin commented 3 years ago

Just ran into this issue a second time, so investigated possible solutions a bit more.

It would be nice if rust key/value collections exposed a get_disjoint_mut(keys: &[Key]) -> &mut [Value] style api, but I totally get why they dont. (they need to check for collisions, which is expensive).

This answer on StackOverflow has some suggestions for how to do this actually. hashbrown::HashMap (which is what std uses anyway) has a method to do this, or there's the multi_mut crate. Or a bit of unsafe code could do it.