2022-05-16 13:53:20 +00:00
|
|
|
//! Skinned mesh example with mesh and joints data defined in code.
|
|
|
|
//! Example taken from <https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_019_SimpleSkin.md>
|
|
|
|
|
2022-10-22 18:52:29 +00:00
|
|
|
use std::f32::consts::*;
|
2022-03-29 18:31:13 +00:00
|
|
|
|
|
|
|
use bevy::{
|
2024-09-16 23:28:12 +00:00
|
|
|
math::ops,
|
2022-03-29 18:31:13 +00:00
|
|
|
prelude::*,
|
2024-01-03 03:31:04 +00:00
|
|
|
render::{
|
|
|
|
mesh::{
|
|
|
|
skinning::{SkinnedMesh, SkinnedMeshInverseBindposes},
|
|
|
|
Indices, PrimitiveTopology, VertexAttributeValues,
|
|
|
|
},
|
RenderAssetPersistencePolicy → RenderAssetUsages (#11399)
# Objective
Right now, all assets in the main world get extracted and prepared in
the render world (if the asset's using the RenderAssetPlugin). This is
unfortunate for two cases:
1. **TextureAtlas** / **FontAtlas**: This one's huge. The individual
`Image` assets that make up the atlas are cloned and prepared
individually when there's no reason for them to be. The atlas textures
are built on the CPU in the main world. *There can be hundreds of images
that get prepared for rendering only not to be used.*
2. If one loads an Image and needs to transform it in a system before
rendering it, kind of like the [decompression
example](https://github.com/bevyengine/bevy/blob/main/examples/asset/asset_decompression.rs#L120),
there's a price paid for extracting & preparing the asset that's not
intended to be rendered yet.
------
* References #10520
* References #1782
## Solution
This changes the `RenderAssetPersistencePolicy` enum to bitflags. I felt
that the objective with the parameter is so similar in nature to wgpu's
[`TextureUsages`](https://docs.rs/wgpu/latest/wgpu/struct.TextureUsages.html)
and
[`BufferUsages`](https://docs.rs/wgpu/latest/wgpu/struct.BufferUsages.html),
that it may as well be just like that.
```rust
// This asset only needs to be in the main world. Don't extract and prepare it.
RenderAssetUsages::MAIN_WORLD
// Keep this asset in the main world and
RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD
// This asset is only needed in the render world. Remove it from the asset server once extracted.
RenderAssetUsages::RENDER_WORLD
```
### Alternate Solution
I considered introducing a third field to `RenderAssetPersistencePolicy`
enum:
```rust
enum RenderAssetPersistencePolicy {
/// Keep the asset in the main world after extracting to the render world.
Keep,
/// Remove the asset from the main world after extracting to the render world.
Unload,
/// This doesn't need to be in the render world at all.
NoExtract, // <-----
}
```
Functional, but this seemed like shoehorning. Another option is renaming
the enum to something like:
```rust
enum RenderAssetExtractionPolicy {
/// Extract the asset and keep it in the main world.
Extract,
/// Remove the asset from the main world after extracting to the render world.
ExtractAndUnload,
/// This doesn't need to be in the render world at all.
NoExtract,
}
```
I think this last one could be a good option if the bitflags are too
clunky.
## Migration Guide
* `RenderAssetPersistencePolicy::Keep` → `RenderAssetUsage::MAIN_WORLD |
RenderAssetUsage::RENDER_WORLD` (or `RenderAssetUsage::default()`)
* `RenderAssetPersistencePolicy::Unload` →
`RenderAssetUsage::RENDER_WORLD`
* For types implementing the `RenderAsset` trait, change `fn
persistence_policy(&self) -> RenderAssetPersistencePolicy` to `fn
asset_usage(&self) -> RenderAssetUsages`.
* Change any references to `cpu_persistent_access`
(`RenderAssetPersistencePolicy`) to `asset_usage` (`RenderAssetUsage`).
This applies to `Image`, `Mesh`, and a few other types.
2024-01-30 13:22:10 +00:00
|
|
|
render_asset::RenderAssetUsages,
|
2022-03-29 18:31:13 +00:00
|
|
|
},
|
|
|
|
};
|
2024-03-22 20:25:49 +00:00
|
|
|
use rand::{Rng, SeedableRng};
|
|
|
|
use rand_chacha::ChaCha8Rng;
|
2022-03-29 18:31:13 +00:00
|
|
|
|
|
|
|
fn main() {
|
|
|
|
App::new()
|
|
|
|
.add_plugins(DefaultPlugins)
|
|
|
|
.insert_resource(AmbientLight {
|
New Exposure and Lighting Defaults (and calibrate examples) (#11868)
# Objective
After adding configurable exposure, we set the default ev100 value to
`7` (indoor). This brought us out of sync with Blender's configuration
and defaults. This PR changes the default to `9.7` (bright indoor or
very overcast outdoors), as I calibrated in #11577. This feels like a
very reasonable default.
The other changes generally center around tweaking Bevy's lighting
defaults and examples to play nicely with this number, alongside a few
other tweaks and improvements.
Note that for artistic reasons I have reverted some examples, which
changed to directional lights in #11581, back to point lights.
Fixes #11577
---
## Changelog
- Changed `Exposure::ev100` from `7` to `9.7` to better match Blender
- Renamed `ExposureSettings` to `Exposure`
- `Camera3dBundle` now includes `Exposure` for discoverability
- Bumped `FULL_DAYLIGHT ` and `DIRECT_SUNLIGHT` to represent the
middle-to-top of those ranges instead of near the bottom
- Added new `AMBIENT_DAYLIGHT` constant and set that as the new
`DirectionalLight` default illuminance.
- `PointLight` and `SpotLight` now have a default `intensity` of
1,000,000 lumens. This makes them actually useful in the context of the
new "semi-outdoor" exposure and puts them in the "cinema lighting"
category instead of the "common household light" category. They are also
reasonably close to the Blender default.
- `AmbientLight` default has been bumped from `20` to `80`.
## Migration Guide
- The increased `Exposure::ev100` means that all existing 3D lighting
will need to be adjusted to match (DirectionalLights, PointLights,
SpotLights, EnvironmentMapLights, etc). Or alternatively, you can adjust
the `Exposure::ev100` on your cameras to work nicely with your current
lighting values. If you are currently relying on default intensity
values, you might need to change the intensity to achieve the same
effect. Note that in Bevy 0.12, point/spot lights had a different hard
coded ev100 value than directional lights. In Bevy 0.13, they use the
same ev100, so if you have both in your scene, the _scale_ between these
light types has changed and you will likely need to adjust one or both
of them.
2024-02-15 20:42:48 +00:00
|
|
|
brightness: 3000.0,
|
2022-06-07 02:16:47 +00:00
|
|
|
..default()
|
2022-03-29 18:31:13 +00:00
|
|
|
})
|
2023-03-18 01:45:34 +00:00
|
|
|
.add_systems(Startup, setup)
|
|
|
|
.add_systems(Update, joint_animation)
|
2022-03-29 18:31:13 +00:00
|
|
|
.run();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Used to mark a joint to be animated in the [`joint_animation`] system.
|
|
|
|
#[derive(Component)]
|
2024-10-08 12:37:46 +00:00
|
|
|
struct AnimatedJoint(isize);
|
2022-03-29 18:31:13 +00:00
|
|
|
|
|
|
|
/// Construct a mesh and a skeleton with 2 joints for that mesh,
|
|
|
|
/// and mark the second joint to be animated.
|
|
|
|
/// It is similar to the scene defined in `models/SimpleSkin/SimpleSkin.gltf`
|
|
|
|
fn setup(
|
|
|
|
mut commands: Commands,
|
2024-10-08 12:37:46 +00:00
|
|
|
asset_server: Res<AssetServer>,
|
2022-03-29 18:31:13 +00:00
|
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
|
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
|
|
|
mut skinned_mesh_inverse_bindposes_assets: ResMut<Assets<SkinnedMeshInverseBindposes>>,
|
|
|
|
) {
|
|
|
|
// Create a camera
|
2024-10-05 01:59:52 +00:00
|
|
|
commands.spawn((
|
|
|
|
Camera3d::default(),
|
2024-10-08 12:37:46 +00:00
|
|
|
Transform::from_xyz(2.5, 2.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
|
2024-10-05 01:59:52 +00:00
|
|
|
));
|
2022-03-29 18:31:13 +00:00
|
|
|
|
|
|
|
// Create inverse bindpose matrices for a skeleton consists of 2 joints
|
Use `impl Into<A>` for `Assets::add` (#10878)
# Motivation
When spawning entities into a scene, it is very common to create assets
like meshes and materials and to add them via asset handles. A common
setup might look like this:
```rust
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
commands.spawn(PbrBundle {
mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
material: materials.add(StandardMaterial::from(Color::RED)),
..default()
});
}
```
Let's take a closer look at the part that adds the assets using `add`.
```rust
mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
material: materials.add(StandardMaterial::from(Color::RED)),
```
Here, "mesh" and "material" are both repeated three times. It's very
explicit, but I find it to be a bit verbose. In addition to being more
code to read and write, the extra characters can sometimes also lead to
the code being formatted to span multiple lines even though the core
task, adding e.g. a primitive mesh, is extremely simple.
A way to address this is by using `.into()`:
```rust
mesh: meshes.add(shape::Cube { size: 1.0 }.into()),
material: materials.add(Color::RED.into()),
```
This is fine, but from the names and the type of `meshes`, we already
know what the type should be. It's very clear that `Cube` should be
turned into a `Mesh` because of the context it's used in. `.into()` is
just seven characters, but it's so common that it quickly adds up and
gets annoying.
It would be nice if you could skip all of the conversion and let Bevy
handle it for you:
```rust
mesh: meshes.add(shape::Cube { size: 1.0 }),
material: materials.add(Color::RED),
```
# Objective
Make adding assets more ergonomic by making `Assets::add` take an `impl
Into<A>` instead of `A`.
## Solution
`Assets::add` now takes an `impl Into<A>` instead of `A`, so e.g. this
works:
```rust
commands.spawn(PbrBundle {
mesh: meshes.add(shape::Cube { size: 1.0 }),
material: materials.add(Color::RED),
..default()
});
```
I also changed all examples to use this API, which increases consistency
as well because `Mesh::from` and `into` were being used arbitrarily even
in the same file. This also gets rid of some lines of code because
formatting is nicer.
---
## Changelog
- `Assets::add` now takes an `impl Into<A>` instead of `A`
- Examples don't use `T::from(K)` or `K.into()` when adding assets
## Migration Guide
Some `into` calls that worked previously might now be broken because of
the new trait bounds. You need to either remove `into` or perform the
conversion explicitly with `from`:
```rust
// Doesn't compile
let mesh_handle = meshes.add(shape::Cube { size: 1.0 }.into()),
// These compile
let mesh_handle = meshes.add(shape::Cube { size: 1.0 }),
let mesh_handle = meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
```
## Concerns
I believe the primary concerns might be:
1. Is this too implicit?
2. Does this increase codegen bloat?
Previously, the two APIs were using `into` or `from`, and now it's
"nothing" or `from`. You could argue that `into` is slightly more
explicit than "nothing" in cases like the earlier examples where a
`Color` gets converted to e.g. a `StandardMaterial`, but I personally
don't think `into` adds much value even in this case, and you could
still see the actual type from the asset type.
As for codegen bloat, I doubt it adds that much, but I'm not very
familiar with the details of codegen. I personally value the user-facing
code reduction and ergonomics improvements that these changes would
provide, but it might be worth checking the other effects in more
detail.
Another slight concern is migration pain; apps might have a ton of
`into` calls that would need to be removed, and it did take me a while
to do so for Bevy itself (maybe around 20-40 minutes). However, I think
the fact that there *are* so many `into` calls just highlights that the
API could be made nicer, and I'd gladly migrate my own projects for it.
2024-01-08 22:14:43 +00:00
|
|
|
let inverse_bindposes = skinned_mesh_inverse_bindposes_assets.add(vec![
|
|
|
|
Mat4::from_translation(Vec3::new(-0.5, -1.0, 0.0)),
|
|
|
|
Mat4::from_translation(Vec3::new(-0.5, -1.0, 0.0)),
|
|
|
|
]);
|
2022-03-29 18:31:13 +00:00
|
|
|
|
|
|
|
// Create a mesh
|
2024-01-03 03:31:04 +00:00
|
|
|
let mesh = Mesh::new(
|
|
|
|
PrimitiveTopology::TriangleList,
|
RenderAssetPersistencePolicy → RenderAssetUsages (#11399)
# Objective
Right now, all assets in the main world get extracted and prepared in
the render world (if the asset's using the RenderAssetPlugin). This is
unfortunate for two cases:
1. **TextureAtlas** / **FontAtlas**: This one's huge. The individual
`Image` assets that make up the atlas are cloned and prepared
individually when there's no reason for them to be. The atlas textures
are built on the CPU in the main world. *There can be hundreds of images
that get prepared for rendering only not to be used.*
2. If one loads an Image and needs to transform it in a system before
rendering it, kind of like the [decompression
example](https://github.com/bevyengine/bevy/blob/main/examples/asset/asset_decompression.rs#L120),
there's a price paid for extracting & preparing the asset that's not
intended to be rendered yet.
------
* References #10520
* References #1782
## Solution
This changes the `RenderAssetPersistencePolicy` enum to bitflags. I felt
that the objective with the parameter is so similar in nature to wgpu's
[`TextureUsages`](https://docs.rs/wgpu/latest/wgpu/struct.TextureUsages.html)
and
[`BufferUsages`](https://docs.rs/wgpu/latest/wgpu/struct.BufferUsages.html),
that it may as well be just like that.
```rust
// This asset only needs to be in the main world. Don't extract and prepare it.
RenderAssetUsages::MAIN_WORLD
// Keep this asset in the main world and
RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD
// This asset is only needed in the render world. Remove it from the asset server once extracted.
RenderAssetUsages::RENDER_WORLD
```
### Alternate Solution
I considered introducing a third field to `RenderAssetPersistencePolicy`
enum:
```rust
enum RenderAssetPersistencePolicy {
/// Keep the asset in the main world after extracting to the render world.
Keep,
/// Remove the asset from the main world after extracting to the render world.
Unload,
/// This doesn't need to be in the render world at all.
NoExtract, // <-----
}
```
Functional, but this seemed like shoehorning. Another option is renaming
the enum to something like:
```rust
enum RenderAssetExtractionPolicy {
/// Extract the asset and keep it in the main world.
Extract,
/// Remove the asset from the main world after extracting to the render world.
ExtractAndUnload,
/// This doesn't need to be in the render world at all.
NoExtract,
}
```
I think this last one could be a good option if the bitflags are too
clunky.
## Migration Guide
* `RenderAssetPersistencePolicy::Keep` → `RenderAssetUsage::MAIN_WORLD |
RenderAssetUsage::RENDER_WORLD` (or `RenderAssetUsage::default()`)
* `RenderAssetPersistencePolicy::Unload` →
`RenderAssetUsage::RENDER_WORLD`
* For types implementing the `RenderAsset` trait, change `fn
persistence_policy(&self) -> RenderAssetPersistencePolicy` to `fn
asset_usage(&self) -> RenderAssetUsages`.
* Change any references to `cpu_persistent_access`
(`RenderAssetPersistencePolicy`) to `asset_usage` (`RenderAssetUsage`).
This applies to `Image`, `Mesh`, and a few other types.
2024-01-30 13:22:10 +00:00
|
|
|
RenderAssetUsages::RENDER_WORLD,
|
2024-01-03 03:31:04 +00:00
|
|
|
)
|
|
|
|
// Set mesh vertex positions
|
|
|
|
.with_inserted_attribute(
|
|
|
|
Mesh::ATTRIBUTE_POSITION,
|
|
|
|
vec![
|
|
|
|
[0.0, 0.0, 0.0],
|
|
|
|
[1.0, 0.0, 0.0],
|
|
|
|
[0.0, 0.5, 0.0],
|
|
|
|
[1.0, 0.5, 0.0],
|
|
|
|
[0.0, 1.0, 0.0],
|
|
|
|
[1.0, 1.0, 0.0],
|
|
|
|
[0.0, 1.5, 0.0],
|
|
|
|
[1.0, 1.5, 0.0],
|
|
|
|
[0.0, 2.0, 0.0],
|
|
|
|
[1.0, 2.0, 0.0],
|
|
|
|
],
|
|
|
|
)
|
2024-10-08 12:37:46 +00:00
|
|
|
// Add UV coordinates that map the left half of the texture since its a 1 x
|
|
|
|
// 2 rectangle.
|
|
|
|
.with_inserted_attribute(
|
|
|
|
Mesh::ATTRIBUTE_UV_0,
|
|
|
|
vec![
|
|
|
|
[0.0, 0.00],
|
|
|
|
[0.5, 0.00],
|
|
|
|
[0.0, 0.25],
|
|
|
|
[0.5, 0.25],
|
|
|
|
[0.0, 0.50],
|
|
|
|
[0.5, 0.50],
|
|
|
|
[0.0, 0.75],
|
|
|
|
[0.5, 0.75],
|
|
|
|
[0.0, 1.00],
|
|
|
|
[0.5, 1.00],
|
|
|
|
],
|
|
|
|
)
|
2024-01-03 03:31:04 +00:00
|
|
|
// Set mesh vertex normals
|
|
|
|
.with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, vec![[0.0, 0.0, 1.0]; 10])
|
|
|
|
// Set mesh vertex joint indices for mesh skinning.
|
|
|
|
// Each vertex gets 4 indices used to address the `JointTransforms` array in the vertex shader
|
|
|
|
// as well as `SkinnedMeshJoint` array in the `SkinnedMesh` component.
|
|
|
|
// This means that a maximum of 4 joints can affect a single vertex.
|
|
|
|
.with_inserted_attribute(
|
|
|
|
Mesh::ATTRIBUTE_JOINT_INDEX,
|
|
|
|
// Need to be explicit here as [u16; 4] could be either Uint16x4 or Unorm16x4.
|
|
|
|
VertexAttributeValues::Uint16x4(vec![
|
|
|
|
[0, 0, 0, 0],
|
|
|
|
[0, 0, 0, 0],
|
|
|
|
[0, 1, 0, 0],
|
|
|
|
[0, 1, 0, 0],
|
|
|
|
[0, 1, 0, 0],
|
|
|
|
[0, 1, 0, 0],
|
|
|
|
[0, 1, 0, 0],
|
|
|
|
[0, 1, 0, 0],
|
|
|
|
[0, 1, 0, 0],
|
|
|
|
[0, 1, 0, 0],
|
|
|
|
]),
|
|
|
|
)
|
|
|
|
// Set mesh vertex joint weights for mesh skinning.
|
|
|
|
// Each vertex gets 4 joint weights corresponding to the 4 joint indices assigned to it.
|
|
|
|
// The sum of these weights should equal to 1.
|
|
|
|
.with_inserted_attribute(
|
|
|
|
Mesh::ATTRIBUTE_JOINT_WEIGHT,
|
|
|
|
vec![
|
|
|
|
[1.00, 0.00, 0.0, 0.0],
|
|
|
|
[1.00, 0.00, 0.0, 0.0],
|
|
|
|
[0.75, 0.25, 0.0, 0.0],
|
|
|
|
[0.75, 0.25, 0.0, 0.0],
|
|
|
|
[0.50, 0.50, 0.0, 0.0],
|
|
|
|
[0.50, 0.50, 0.0, 0.0],
|
|
|
|
[0.25, 0.75, 0.0, 0.0],
|
|
|
|
[0.25, 0.75, 0.0, 0.0],
|
|
|
|
[0.00, 1.00, 0.0, 0.0],
|
|
|
|
[0.00, 1.00, 0.0, 0.0],
|
|
|
|
],
|
|
|
|
)
|
|
|
|
// Tell bevy to construct triangles from a list of vertex indices,
|
|
|
|
// where each 3 vertex indices form an triangle.
|
2024-02-06 23:31:48 +00:00
|
|
|
.with_inserted_indices(Indices::U16(vec![
|
2024-01-03 03:31:04 +00:00
|
|
|
0, 1, 3, 0, 3, 2, 2, 3, 5, 2, 5, 4, 4, 5, 7, 4, 7, 6, 6, 7, 9, 6, 9, 8,
|
2024-02-06 23:31:48 +00:00
|
|
|
]));
|
2022-03-29 18:31:13 +00:00
|
|
|
|
|
|
|
let mesh = meshes.add(mesh);
|
2023-09-19 05:57:25 +00:00
|
|
|
|
2024-03-26 19:40:18 +00:00
|
|
|
// We're seeding the PRNG here to make this example deterministic for testing purposes.
|
|
|
|
// This isn't strictly required in practical use unless you need your app to be deterministic.
|
2024-03-22 20:25:49 +00:00
|
|
|
let mut rng = ChaCha8Rng::seed_from_u64(42);
|
2023-09-19 05:57:25 +00:00
|
|
|
|
2022-03-29 18:31:13 +00:00
|
|
|
for i in -5..5 {
|
|
|
|
// Create joint entities
|
|
|
|
let joint_0 = commands
|
2024-10-08 12:37:46 +00:00
|
|
|
.spawn(Transform::from_xyz(
|
|
|
|
i as f32 * 1.5,
|
|
|
|
0.0,
|
|
|
|
// Move quads back a small amount to avoid Z-fighting and not
|
|
|
|
// obscure the transform gizmos.
|
|
|
|
-(i as f32 * 0.01).abs(),
|
|
|
|
))
|
2022-03-29 18:31:13 +00:00
|
|
|
.id();
|
2024-10-08 12:37:46 +00:00
|
|
|
let joint_1 = commands.spawn((AnimatedJoint(i), Transform::IDENTITY)).id();
|
2022-03-29 18:31:13 +00:00
|
|
|
|
|
|
|
// Set joint_1 as a child of joint_0.
|
2024-09-16 23:16:04 +00:00
|
|
|
commands.entity(joint_0).add_children(&[joint_1]);
|
2022-03-29 18:31:13 +00:00
|
|
|
|
|
|
|
// Each joint in this vector corresponds to each inverse bindpose matrix in `SkinnedMeshInverseBindposes`.
|
|
|
|
let joint_entities = vec![joint_0, joint_1];
|
|
|
|
|
|
|
|
// Create skinned mesh renderer. Note that its transform doesn't affect the position of the mesh.
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
commands.spawn((
|
Migrate meshes and materials to required components (#15524)
# Objective
A big step in the migration to required components: meshes and
materials!
## Solution
As per the [selected
proposal](https://hackmd.io/@bevy/required_components/%2Fj9-PnF-2QKK0on1KQ29UWQ):
- Deprecate `MaterialMesh2dBundle`, `MaterialMeshBundle`, and
`PbrBundle`.
- Add `Mesh2d` and `Mesh3d` components, which wrap a `Handle<Mesh>`.
- Add `MeshMaterial2d<M: Material2d>` and `MeshMaterial3d<M: Material>`,
which wrap a `Handle<M>`.
- Meshes *without* a mesh material should be rendered with a default
material. The existence of a material is determined by
`HasMaterial2d`/`HasMaterial3d`, which is required by
`MeshMaterial2d`/`MeshMaterial3d`. This gets around problems with the
generics.
Previously:
```rust
commands.spawn(MaterialMesh2dBundle {
mesh: meshes.add(Circle::new(100.0)).into(),
material: materials.add(Color::srgb(7.5, 0.0, 7.5)),
transform: Transform::from_translation(Vec3::new(-200., 0., 0.)),
..default()
});
```
Now:
```rust
commands.spawn((
Mesh2d(meshes.add(Circle::new(100.0))),
MeshMaterial2d(materials.add(Color::srgb(7.5, 0.0, 7.5))),
Transform::from_translation(Vec3::new(-200., 0., 0.)),
));
```
If the mesh material is missing, previously nothing was rendered. Now,
it renders a white default `ColorMaterial` in 2D and a
`StandardMaterial` in 3D (this can be overridden). Below, only every
other entity has a material:
![Näyttökuva 2024-09-29
181746](https://github.com/user-attachments/assets/5c8be029-d2fe-4b8c-ae89-17a72ff82c9a)
![Näyttökuva 2024-09-29
181918](https://github.com/user-attachments/assets/58adbc55-5a1e-4c7d-a2c7-ed456227b909)
Why white? This is still open for discussion, but I think white makes
sense for a *default* material, while *invalid* asset handles pointing
to nothing should have something like a pink material to indicate that
something is broken (I don't handle that in this PR yet). This is kind
of a mix of Godot and Unity: Godot just renders a white material for
non-existent materials, while Unity renders nothing when no materials
exist, but renders pink for invalid materials. I can also change the
default material to pink if that is preferable though.
## Testing
I ran some 2D and 3D examples to test if anything changed visually. I
have not tested all examples or features yet however. If anyone wants to
test more extensively, it would be appreciated!
## Implementation Notes
- The relationship between `bevy_render` and `bevy_pbr` is weird here.
`bevy_render` needs `Mesh3d` for its own systems, but `bevy_pbr` has all
of the material logic, and `bevy_render` doesn't depend on it. I feel
like the two crates should be refactored in some way, but I think that's
out of scope for this PR.
- I didn't migrate meshlets to required components yet. That can
probably be done in a follow-up, as this is already a huge PR.
- It is becoming increasingly clear to me that we really, *really* want
to disallow raw asset handles as components. They caused me a *ton* of
headache here already, and it took me a long time to find every place
that queried for them or inserted them directly on entities, since there
were no compiler errors for it. If we don't remove the `Component`
derive, I expect raw asset handles to be a *huge* footgun for users as
we transition to wrapper components, especially as handles as components
have been the norm so far. I personally consider this to be a blocker
for 0.15: we need to migrate to wrapper components for asset handles
everywhere, and remove the `Component` derive. Also see
https://github.com/bevyengine/bevy/issues/14124.
---
## Migration Guide
Asset handles for meshes and mesh materials must now be wrapped in the
`Mesh2d` and `MeshMaterial2d` or `Mesh3d` and `MeshMaterial3d`
components for 2D and 3D respectively. Raw handles as components no
longer render meshes.
Additionally, `MaterialMesh2dBundle`, `MaterialMeshBundle`, and
`PbrBundle` have been deprecated. Instead, use the mesh and material
components directly.
Previously:
```rust
commands.spawn(MaterialMesh2dBundle {
mesh: meshes.add(Circle::new(100.0)).into(),
material: materials.add(Color::srgb(7.5, 0.0, 7.5)),
transform: Transform::from_translation(Vec3::new(-200., 0., 0.)),
..default()
});
```
Now:
```rust
commands.spawn((
Mesh2d(meshes.add(Circle::new(100.0))),
MeshMaterial2d(materials.add(Color::srgb(7.5, 0.0, 7.5))),
Transform::from_translation(Vec3::new(-200., 0., 0.)),
));
```
If the mesh material is missing, a white default material is now used.
Previously, nothing was rendered if the material was missing.
The `WithMesh2d` and `WithMesh3d` query filter type aliases have also
been removed. Simply use `With<Mesh2d>` or `With<Mesh3d>`.
---------
Co-authored-by: Tim Blackbird <justthecooldude@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2024-10-01 21:33:17 +00:00
|
|
|
Mesh3d(mesh.clone()),
|
2024-10-08 12:37:46 +00:00
|
|
|
MeshMaterial3d(materials.add(StandardMaterial {
|
|
|
|
base_color: Color::srgb(
|
|
|
|
rng.gen_range(0.0..1.0),
|
|
|
|
rng.gen_range(0.0..1.0),
|
|
|
|
rng.gen_range(0.0..1.0),
|
|
|
|
),
|
|
|
|
base_color_texture: Some(asset_server.load("textures/uv_checker_bw.png")),
|
|
|
|
..default()
|
|
|
|
})),
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
SkinnedMesh {
|
2022-03-29 18:31:13 +00:00
|
|
|
inverse_bindposes: inverse_bindposes.clone(),
|
|
|
|
joints: joint_entities,
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
},
|
|
|
|
));
|
2022-03-29 18:31:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Animate the joint marked with [`AnimatedJoint`] component.
|
2024-10-08 12:37:46 +00:00
|
|
|
fn joint_animation(
|
|
|
|
time: Res<Time>,
|
|
|
|
mut query: Query<(&mut Transform, &AnimatedJoint)>,
|
|
|
|
mut gizmos: Gizmos,
|
|
|
|
) {
|
|
|
|
for (mut transform, animated_joint) in &mut query {
|
|
|
|
match animated_joint.0 {
|
|
|
|
-5 => {
|
|
|
|
transform.rotation =
|
|
|
|
Quat::from_rotation_x(FRAC_PI_2 * ops::sin(time.elapsed_seconds()));
|
|
|
|
}
|
|
|
|
-4 => {
|
|
|
|
transform.rotation =
|
|
|
|
Quat::from_rotation_y(FRAC_PI_2 * ops::sin(time.elapsed_seconds()));
|
|
|
|
}
|
|
|
|
-3 => {
|
|
|
|
transform.rotation =
|
|
|
|
Quat::from_rotation_z(FRAC_PI_2 * ops::sin(time.elapsed_seconds()));
|
|
|
|
}
|
|
|
|
-2 => {
|
|
|
|
transform.scale.x = ops::sin(time.elapsed_seconds()) + 1.0;
|
|
|
|
}
|
|
|
|
-1 => {
|
|
|
|
transform.scale.y = ops::sin(time.elapsed_seconds()) + 1.0;
|
|
|
|
}
|
|
|
|
0 => {
|
|
|
|
transform.translation.x = 0.5 * ops::sin(time.elapsed_seconds());
|
|
|
|
transform.translation.y = ops::cos(time.elapsed_seconds());
|
|
|
|
}
|
|
|
|
1 => {
|
|
|
|
transform.translation.y = ops::sin(time.elapsed_seconds());
|
|
|
|
transform.translation.z = ops::cos(time.elapsed_seconds());
|
|
|
|
}
|
|
|
|
2 => {
|
|
|
|
transform.translation.x = ops::sin(time.elapsed_seconds());
|
|
|
|
}
|
|
|
|
3 => {
|
|
|
|
transform.translation.y = ops::sin(time.elapsed_seconds());
|
|
|
|
transform.scale.x = ops::sin(time.elapsed_seconds()) + 1.0;
|
|
|
|
}
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
// Show transform
|
|
|
|
let mut axis = *transform;
|
|
|
|
axis.translation.x += animated_joint.0 as f32 * 1.5;
|
|
|
|
gizmos.axes(axis, 1.0);
|
2022-03-29 18:31:13 +00:00
|
|
|
}
|
|
|
|
}
|