Support array / cubemap / cubemap array textures in KTX2 (#5325)
# Objective
- Fix / support KTX2 array / cubemap / cubemap array textures
- Fixes #4495 . Supersedes #4514 .
## Solution
- Add `Option<TextureViewDescriptor>` to `Image` to enable configuration of the `TextureViewDimension` of a texture.
- This allows users to set `D2Array`, `D3`, `Cube`, `CubeArray` or whatever they need
- Automatically configure this when loading KTX2
- Transcode all layers and faces instead of just one
- Use the UASTC block size of 128 bits, and the number of blocks in x/y for a given mip level in order to determine the offset of the layer and face within the KTX2 mip level data
- `wgpu` wants data ordered as layer 0 mip 0..n, layer 1 mip 0..n, etc. See https://docs.rs/wgpu/latest/wgpu/util/trait.DeviceExt.html#tymethod.create_texture_with_data
- Reorder the data KTX2 mip X layer Y face Z to `wgpu` layer Y face Z mip X order
- Add a `skybox` example to demonstrate / test loading cubemaps from PNG and KTX2, including ASTC 4x4, BC7, and ETC2 compression for support everywhere. Note that you need to enable the `ktx2,zstd` features to be able to load the compressed textures.
---
## Changelog
- Fixed: KTX2 array / cubemap / cubemap array textures
- Fixes: Validation failure for compressed textures stored in KTX2 where the width/height are not a multiple of the block dimensions.
- Added: `Image` now has an `Option<TextureViewDescriptor>` field to enable configuration of the texture view. This is useful for configuring the `TextureViewDimension` when it is not just a plain 2D texture and the loader could/did not identify what it should be.
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-07-30 07:02:58 +00:00
|
|
|
//! Load a cubemap texture onto a cube like a skybox and cycle through different compressed texture formats
|
|
|
|
|
2022-08-30 19:52:11 +00:00
|
|
|
use std::f32::consts::PI;
|
|
|
|
|
Support array / cubemap / cubemap array textures in KTX2 (#5325)
# Objective
- Fix / support KTX2 array / cubemap / cubemap array textures
- Fixes #4495 . Supersedes #4514 .
## Solution
- Add `Option<TextureViewDescriptor>` to `Image` to enable configuration of the `TextureViewDimension` of a texture.
- This allows users to set `D2Array`, `D3`, `Cube`, `CubeArray` or whatever they need
- Automatically configure this when loading KTX2
- Transcode all layers and faces instead of just one
- Use the UASTC block size of 128 bits, and the number of blocks in x/y for a given mip level in order to determine the offset of the layer and face within the KTX2 mip level data
- `wgpu` wants data ordered as layer 0 mip 0..n, layer 1 mip 0..n, etc. See https://docs.rs/wgpu/latest/wgpu/util/trait.DeviceExt.html#tymethod.create_texture_with_data
- Reorder the data KTX2 mip X layer Y face Z to `wgpu` layer Y face Z mip X order
- Add a `skybox` example to demonstrate / test loading cubemaps from PNG and KTX2, including ASTC 4x4, BC7, and ETC2 compression for support everywhere. Note that you need to enable the `ktx2,zstd` features to be able to load the compressed textures.
---
## Changelog
- Fixed: KTX2 array / cubemap / cubemap array textures
- Fixes: Validation failure for compressed textures stored in KTX2 where the width/height are not a multiple of the block dimensions.
- Added: `Image` now has an `Option<TextureViewDescriptor>` field to enable configuration of the texture view. This is useful for configuring the `TextureViewDimension` when it is not just a plain 2D texture and the loader could/did not identify what it should be.
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-07-30 07:02:58 +00:00
|
|
|
use bevy::{
|
|
|
|
asset::LoadState,
|
|
|
|
input::mouse::MouseMotion,
|
|
|
|
pbr::{MaterialPipeline, MaterialPipelineKey},
|
|
|
|
prelude::*,
|
|
|
|
reflect::TypeUuid,
|
|
|
|
render::{
|
|
|
|
mesh::MeshVertexBufferLayout,
|
|
|
|
render_asset::RenderAssets,
|
|
|
|
render_resource::{
|
|
|
|
AsBindGroup, AsBindGroupError, BindGroupDescriptor, BindGroupEntry, BindGroupLayout,
|
|
|
|
BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType,
|
|
|
|
OwnedBindingResource, PreparedBindGroup, RenderPipelineDescriptor, SamplerBindingType,
|
|
|
|
ShaderRef, ShaderStages, SpecializedMeshPipelineError, TextureSampleType,
|
|
|
|
TextureViewDescriptor, TextureViewDimension,
|
|
|
|
},
|
|
|
|
renderer::RenderDevice,
|
|
|
|
texture::{CompressedImageFormats, FallbackImage},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const CUBEMAPS: &[(&str, CompressedImageFormats)] = &[
|
|
|
|
(
|
|
|
|
"textures/Ryfjallet_cubemap.png",
|
|
|
|
CompressedImageFormats::NONE,
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"textures/Ryfjallet_cubemap_astc4x4.ktx2",
|
|
|
|
CompressedImageFormats::ASTC_LDR,
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"textures/Ryfjallet_cubemap_bc7.ktx2",
|
|
|
|
CompressedImageFormats::BC,
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"textures/Ryfjallet_cubemap_etc2.ktx2",
|
|
|
|
CompressedImageFormats::ETC2,
|
|
|
|
),
|
|
|
|
];
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
App::new()
|
|
|
|
.add_plugins(DefaultPlugins)
|
|
|
|
.add_plugin(MaterialPlugin::<CubemapMaterial>::default())
|
|
|
|
.add_startup_system(setup)
|
|
|
|
.add_system(cycle_cubemap_asset)
|
|
|
|
.add_system(asset_loaded.after(cycle_cubemap_asset))
|
|
|
|
.add_system(camera_controller)
|
|
|
|
.add_system(animate_light_direction)
|
|
|
|
.run();
|
|
|
|
}
|
|
|
|
|
Make `Resource` trait opt-in, requiring `#[derive(Resource)]` V2 (#5577)
*This PR description is an edited copy of #5007, written by @alice-i-cecile.*
# Objective
Follow-up to https://github.com/bevyengine/bevy/pull/2254. The `Resource` trait currently has a blanket implementation for all types that meet its bounds.
While ergonomic, this results in several drawbacks:
* it is possible to make confusing, silent mistakes such as inserting a function pointer (Foo) rather than a value (Foo::Bar) as a resource
* it is challenging to discover if a type is intended to be used as a resource
* we cannot later add customization options (see the [RFC](https://github.com/bevyengine/rfcs/blob/main/rfcs/27-derive-component.md) for the equivalent choice for Component).
* dependencies can use the same Rust type as a resource in invisibly conflicting ways
* raw Rust types used as resources cannot preserve privacy appropriately, as anyone able to access that type can read and write to internal values
* we cannot capture a definitive list of possible resources to display to users in an editor
## Notes to reviewers
* Review this commit-by-commit; there's effectively no back-tracking and there's a lot of churn in some of these commits.
*ira: My commits are not as well organized :')*
* I've relaxed the bound on Local to Send + Sync + 'static: I don't think these concerns apply there, so this can keep things simple. Storing e.g. a u32 in a Local is fine, because there's a variable name attached explaining what it does.
* I think this is a bad place for the Resource trait to live, but I've left it in place to make reviewing easier. IMO that's best tackled with https://github.com/bevyengine/bevy/issues/4981.
## Changelog
`Resource` is no longer automatically implemented for all matching types. Instead, use the new `#[derive(Resource)]` macro.
## Migration Guide
Add `#[derive(Resource)]` to all types you are using as a resource.
If you are using a third party type as a resource, wrap it in a tuple struct to bypass orphan rules. Consider deriving `Deref` and `DerefMut` to improve ergonomics.
`ClearColor` no longer implements `Component`. Using `ClearColor` as a component in 0.8 did nothing.
Use the `ClearColorConfig` in the `Camera3d` and `Camera2d` components instead.
Co-authored-by: Alice <alice.i.cecile@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: devil-ira <justthecooldude@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-08-08 21:36:35 +00:00
|
|
|
#[derive(Resource)]
|
Support array / cubemap / cubemap array textures in KTX2 (#5325)
# Objective
- Fix / support KTX2 array / cubemap / cubemap array textures
- Fixes #4495 . Supersedes #4514 .
## Solution
- Add `Option<TextureViewDescriptor>` to `Image` to enable configuration of the `TextureViewDimension` of a texture.
- This allows users to set `D2Array`, `D3`, `Cube`, `CubeArray` or whatever they need
- Automatically configure this when loading KTX2
- Transcode all layers and faces instead of just one
- Use the UASTC block size of 128 bits, and the number of blocks in x/y for a given mip level in order to determine the offset of the layer and face within the KTX2 mip level data
- `wgpu` wants data ordered as layer 0 mip 0..n, layer 1 mip 0..n, etc. See https://docs.rs/wgpu/latest/wgpu/util/trait.DeviceExt.html#tymethod.create_texture_with_data
- Reorder the data KTX2 mip X layer Y face Z to `wgpu` layer Y face Z mip X order
- Add a `skybox` example to demonstrate / test loading cubemaps from PNG and KTX2, including ASTC 4x4, BC7, and ETC2 compression for support everywhere. Note that you need to enable the `ktx2,zstd` features to be able to load the compressed textures.
---
## Changelog
- Fixed: KTX2 array / cubemap / cubemap array textures
- Fixes: Validation failure for compressed textures stored in KTX2 where the width/height are not a multiple of the block dimensions.
- Added: `Image` now has an `Option<TextureViewDescriptor>` field to enable configuration of the texture view. This is useful for configuring the `TextureViewDimension` when it is not just a plain 2D texture and the loader could/did not identify what it should be.
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-07-30 07:02:58 +00:00
|
|
|
struct Cubemap {
|
|
|
|
is_loaded: bool,
|
|
|
|
index: usize,
|
|
|
|
image_handle: Handle<Image>,
|
|
|
|
}
|
|
|
|
|
|
|
|
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|
|
|
// directional 'sun' light
|
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(DirectionalLightBundle {
|
Support array / cubemap / cubemap array textures in KTX2 (#5325)
# Objective
- Fix / support KTX2 array / cubemap / cubemap array textures
- Fixes #4495 . Supersedes #4514 .
## Solution
- Add `Option<TextureViewDescriptor>` to `Image` to enable configuration of the `TextureViewDimension` of a texture.
- This allows users to set `D2Array`, `D3`, `Cube`, `CubeArray` or whatever they need
- Automatically configure this when loading KTX2
- Transcode all layers and faces instead of just one
- Use the UASTC block size of 128 bits, and the number of blocks in x/y for a given mip level in order to determine the offset of the layer and face within the KTX2 mip level data
- `wgpu` wants data ordered as layer 0 mip 0..n, layer 1 mip 0..n, etc. See https://docs.rs/wgpu/latest/wgpu/util/trait.DeviceExt.html#tymethod.create_texture_with_data
- Reorder the data KTX2 mip X layer Y face Z to `wgpu` layer Y face Z mip X order
- Add a `skybox` example to demonstrate / test loading cubemaps from PNG and KTX2, including ASTC 4x4, BC7, and ETC2 compression for support everywhere. Note that you need to enable the `ktx2,zstd` features to be able to load the compressed textures.
---
## Changelog
- Fixed: KTX2 array / cubemap / cubemap array textures
- Fixes: Validation failure for compressed textures stored in KTX2 where the width/height are not a multiple of the block dimensions.
- Added: `Image` now has an `Option<TextureViewDescriptor>` field to enable configuration of the texture view. This is useful for configuring the `TextureViewDimension` when it is not just a plain 2D texture and the loader could/did not identify what it should be.
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-07-30 07:02:58 +00:00
|
|
|
directional_light: DirectionalLight {
|
|
|
|
illuminance: 32000.0,
|
|
|
|
..default()
|
|
|
|
},
|
2022-08-30 19:52:11 +00:00
|
|
|
transform: Transform::from_xyz(0.0, 2.0, 0.0)
|
|
|
|
.with_rotation(Quat::from_rotation_x(-PI / 4.)),
|
Support array / cubemap / cubemap array textures in KTX2 (#5325)
# Objective
- Fix / support KTX2 array / cubemap / cubemap array textures
- Fixes #4495 . Supersedes #4514 .
## Solution
- Add `Option<TextureViewDescriptor>` to `Image` to enable configuration of the `TextureViewDimension` of a texture.
- This allows users to set `D2Array`, `D3`, `Cube`, `CubeArray` or whatever they need
- Automatically configure this when loading KTX2
- Transcode all layers and faces instead of just one
- Use the UASTC block size of 128 bits, and the number of blocks in x/y for a given mip level in order to determine the offset of the layer and face within the KTX2 mip level data
- `wgpu` wants data ordered as layer 0 mip 0..n, layer 1 mip 0..n, etc. See https://docs.rs/wgpu/latest/wgpu/util/trait.DeviceExt.html#tymethod.create_texture_with_data
- Reorder the data KTX2 mip X layer Y face Z to `wgpu` layer Y face Z mip X order
- Add a `skybox` example to demonstrate / test loading cubemaps from PNG and KTX2, including ASTC 4x4, BC7, and ETC2 compression for support everywhere. Note that you need to enable the `ktx2,zstd` features to be able to load the compressed textures.
---
## Changelog
- Fixed: KTX2 array / cubemap / cubemap array textures
- Fixes: Validation failure for compressed textures stored in KTX2 where the width/height are not a multiple of the block dimensions.
- Added: `Image` now has an `Option<TextureViewDescriptor>` field to enable configuration of the texture view. This is useful for configuring the `TextureViewDimension` when it is not just a plain 2D texture and the loader could/did not identify what it should be.
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-07-30 07:02:58 +00:00
|
|
|
..default()
|
|
|
|
});
|
|
|
|
|
|
|
|
let skybox_handle = asset_server.load(CUBEMAPS[0].0);
|
|
|
|
// camera
|
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((
|
|
|
|
Camera3dBundle {
|
2022-08-30 19:52:11 +00:00
|
|
|
transform: Transform::from_xyz(0.0, 0.0, 8.0).looking_at(Vec3::ZERO, Vec3::Y),
|
Support array / cubemap / cubemap array textures in KTX2 (#5325)
# Objective
- Fix / support KTX2 array / cubemap / cubemap array textures
- Fixes #4495 . Supersedes #4514 .
## Solution
- Add `Option<TextureViewDescriptor>` to `Image` to enable configuration of the `TextureViewDimension` of a texture.
- This allows users to set `D2Array`, `D3`, `Cube`, `CubeArray` or whatever they need
- Automatically configure this when loading KTX2
- Transcode all layers and faces instead of just one
- Use the UASTC block size of 128 bits, and the number of blocks in x/y for a given mip level in order to determine the offset of the layer and face within the KTX2 mip level data
- `wgpu` wants data ordered as layer 0 mip 0..n, layer 1 mip 0..n, etc. See https://docs.rs/wgpu/latest/wgpu/util/trait.DeviceExt.html#tymethod.create_texture_with_data
- Reorder the data KTX2 mip X layer Y face Z to `wgpu` layer Y face Z mip X order
- Add a `skybox` example to demonstrate / test loading cubemaps from PNG and KTX2, including ASTC 4x4, BC7, and ETC2 compression for support everywhere. Note that you need to enable the `ktx2,zstd` features to be able to load the compressed textures.
---
## Changelog
- Fixed: KTX2 array / cubemap / cubemap array textures
- Fixes: Validation failure for compressed textures stored in KTX2 where the width/height are not a multiple of the block dimensions.
- Added: `Image` now has an `Option<TextureViewDescriptor>` field to enable configuration of the texture view. This is useful for configuring the `TextureViewDimension` when it is not just a plain 2D texture and the loader could/did not identify what it should be.
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-07-30 07:02:58 +00:00
|
|
|
..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
|
|
|
},
|
|
|
|
CameraController::default(),
|
|
|
|
));
|
Support array / cubemap / cubemap array textures in KTX2 (#5325)
# Objective
- Fix / support KTX2 array / cubemap / cubemap array textures
- Fixes #4495 . Supersedes #4514 .
## Solution
- Add `Option<TextureViewDescriptor>` to `Image` to enable configuration of the `TextureViewDimension` of a texture.
- This allows users to set `D2Array`, `D3`, `Cube`, `CubeArray` or whatever they need
- Automatically configure this when loading KTX2
- Transcode all layers and faces instead of just one
- Use the UASTC block size of 128 bits, and the number of blocks in x/y for a given mip level in order to determine the offset of the layer and face within the KTX2 mip level data
- `wgpu` wants data ordered as layer 0 mip 0..n, layer 1 mip 0..n, etc. See https://docs.rs/wgpu/latest/wgpu/util/trait.DeviceExt.html#tymethod.create_texture_with_data
- Reorder the data KTX2 mip X layer Y face Z to `wgpu` layer Y face Z mip X order
- Add a `skybox` example to demonstrate / test loading cubemaps from PNG and KTX2, including ASTC 4x4, BC7, and ETC2 compression for support everywhere. Note that you need to enable the `ktx2,zstd` features to be able to load the compressed textures.
---
## Changelog
- Fixed: KTX2 array / cubemap / cubemap array textures
- Fixes: Validation failure for compressed textures stored in KTX2 where the width/height are not a multiple of the block dimensions.
- Added: `Image` now has an `Option<TextureViewDescriptor>` field to enable configuration of the texture view. This is useful for configuring the `TextureViewDimension` when it is not just a plain 2D texture and the loader could/did not identify what it should be.
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-07-30 07:02:58 +00:00
|
|
|
|
|
|
|
// ambient light
|
|
|
|
// NOTE: The ambient light is used to scale how bright the environment map is so with a bright
|
|
|
|
// environment map, use an appropriate colour and brightness to match
|
|
|
|
commands.insert_resource(AmbientLight {
|
|
|
|
color: Color::rgb_u8(210, 220, 240),
|
|
|
|
brightness: 1.0,
|
|
|
|
});
|
|
|
|
|
|
|
|
commands.insert_resource(Cubemap {
|
|
|
|
is_loaded: false,
|
|
|
|
index: 0,
|
|
|
|
image_handle: skybox_handle,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-10-22 18:52:29 +00:00
|
|
|
const CUBEMAP_SWAP_DELAY: f32 = 3.0;
|
Support array / cubemap / cubemap array textures in KTX2 (#5325)
# Objective
- Fix / support KTX2 array / cubemap / cubemap array textures
- Fixes #4495 . Supersedes #4514 .
## Solution
- Add `Option<TextureViewDescriptor>` to `Image` to enable configuration of the `TextureViewDimension` of a texture.
- This allows users to set `D2Array`, `D3`, `Cube`, `CubeArray` or whatever they need
- Automatically configure this when loading KTX2
- Transcode all layers and faces instead of just one
- Use the UASTC block size of 128 bits, and the number of blocks in x/y for a given mip level in order to determine the offset of the layer and face within the KTX2 mip level data
- `wgpu` wants data ordered as layer 0 mip 0..n, layer 1 mip 0..n, etc. See https://docs.rs/wgpu/latest/wgpu/util/trait.DeviceExt.html#tymethod.create_texture_with_data
- Reorder the data KTX2 mip X layer Y face Z to `wgpu` layer Y face Z mip X order
- Add a `skybox` example to demonstrate / test loading cubemaps from PNG and KTX2, including ASTC 4x4, BC7, and ETC2 compression for support everywhere. Note that you need to enable the `ktx2,zstd` features to be able to load the compressed textures.
---
## Changelog
- Fixed: KTX2 array / cubemap / cubemap array textures
- Fixes: Validation failure for compressed textures stored in KTX2 where the width/height are not a multiple of the block dimensions.
- Added: `Image` now has an `Option<TextureViewDescriptor>` field to enable configuration of the texture view. This is useful for configuring the `TextureViewDimension` when it is not just a plain 2D texture and the loader could/did not identify what it should be.
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-07-30 07:02:58 +00:00
|
|
|
|
|
|
|
fn cycle_cubemap_asset(
|
|
|
|
time: Res<Time>,
|
2022-10-22 18:52:29 +00:00
|
|
|
mut next_swap: Local<f32>,
|
Support array / cubemap / cubemap array textures in KTX2 (#5325)
# Objective
- Fix / support KTX2 array / cubemap / cubemap array textures
- Fixes #4495 . Supersedes #4514 .
## Solution
- Add `Option<TextureViewDescriptor>` to `Image` to enable configuration of the `TextureViewDimension` of a texture.
- This allows users to set `D2Array`, `D3`, `Cube`, `CubeArray` or whatever they need
- Automatically configure this when loading KTX2
- Transcode all layers and faces instead of just one
- Use the UASTC block size of 128 bits, and the number of blocks in x/y for a given mip level in order to determine the offset of the layer and face within the KTX2 mip level data
- `wgpu` wants data ordered as layer 0 mip 0..n, layer 1 mip 0..n, etc. See https://docs.rs/wgpu/latest/wgpu/util/trait.DeviceExt.html#tymethod.create_texture_with_data
- Reorder the data KTX2 mip X layer Y face Z to `wgpu` layer Y face Z mip X order
- Add a `skybox` example to demonstrate / test loading cubemaps from PNG and KTX2, including ASTC 4x4, BC7, and ETC2 compression for support everywhere. Note that you need to enable the `ktx2,zstd` features to be able to load the compressed textures.
---
## Changelog
- Fixed: KTX2 array / cubemap / cubemap array textures
- Fixes: Validation failure for compressed textures stored in KTX2 where the width/height are not a multiple of the block dimensions.
- Added: `Image` now has an `Option<TextureViewDescriptor>` field to enable configuration of the texture view. This is useful for configuring the `TextureViewDimension` when it is not just a plain 2D texture and the loader could/did not identify what it should be.
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-07-30 07:02:58 +00:00
|
|
|
mut cubemap: ResMut<Cubemap>,
|
|
|
|
asset_server: Res<AssetServer>,
|
|
|
|
render_device: Res<RenderDevice>,
|
|
|
|
) {
|
2022-10-22 18:52:29 +00:00
|
|
|
let now = time.elapsed_seconds();
|
Support array / cubemap / cubemap array textures in KTX2 (#5325)
# Objective
- Fix / support KTX2 array / cubemap / cubemap array textures
- Fixes #4495 . Supersedes #4514 .
## Solution
- Add `Option<TextureViewDescriptor>` to `Image` to enable configuration of the `TextureViewDimension` of a texture.
- This allows users to set `D2Array`, `D3`, `Cube`, `CubeArray` or whatever they need
- Automatically configure this when loading KTX2
- Transcode all layers and faces instead of just one
- Use the UASTC block size of 128 bits, and the number of blocks in x/y for a given mip level in order to determine the offset of the layer and face within the KTX2 mip level data
- `wgpu` wants data ordered as layer 0 mip 0..n, layer 1 mip 0..n, etc. See https://docs.rs/wgpu/latest/wgpu/util/trait.DeviceExt.html#tymethod.create_texture_with_data
- Reorder the data KTX2 mip X layer Y face Z to `wgpu` layer Y face Z mip X order
- Add a `skybox` example to demonstrate / test loading cubemaps from PNG and KTX2, including ASTC 4x4, BC7, and ETC2 compression for support everywhere. Note that you need to enable the `ktx2,zstd` features to be able to load the compressed textures.
---
## Changelog
- Fixed: KTX2 array / cubemap / cubemap array textures
- Fixes: Validation failure for compressed textures stored in KTX2 where the width/height are not a multiple of the block dimensions.
- Added: `Image` now has an `Option<TextureViewDescriptor>` field to enable configuration of the texture view. This is useful for configuring the `TextureViewDimension` when it is not just a plain 2D texture and the loader could/did not identify what it should be.
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-07-30 07:02:58 +00:00
|
|
|
if *next_swap == 0.0 {
|
|
|
|
*next_swap = now + CUBEMAP_SWAP_DELAY;
|
|
|
|
return;
|
|
|
|
} else if now < *next_swap {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
*next_swap += CUBEMAP_SWAP_DELAY;
|
|
|
|
|
|
|
|
let supported_compressed_formats =
|
|
|
|
CompressedImageFormats::from_features(render_device.features());
|
|
|
|
|
|
|
|
let mut new_index = cubemap.index;
|
|
|
|
for _ in 0..CUBEMAPS.len() {
|
|
|
|
new_index = (new_index + 1) % CUBEMAPS.len();
|
|
|
|
if supported_compressed_formats.contains(CUBEMAPS[new_index].1) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
info!("Skipping unsupported format: {:?}", CUBEMAPS[new_index]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip swapping to the same texture. Useful for when ktx2, zstd, or compressed texture support
|
|
|
|
// is missing
|
|
|
|
if new_index == cubemap.index {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cubemap.index = new_index;
|
|
|
|
cubemap.image_handle = asset_server.load(CUBEMAPS[cubemap.index].0);
|
|
|
|
cubemap.is_loaded = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn asset_loaded(
|
|
|
|
mut commands: Commands,
|
|
|
|
asset_server: Res<AssetServer>,
|
|
|
|
mut images: ResMut<Assets<Image>>,
|
|
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
|
|
mut cubemap_materials: ResMut<Assets<CubemapMaterial>>,
|
|
|
|
mut cubemap: ResMut<Cubemap>,
|
|
|
|
cubes: Query<&Handle<CubemapMaterial>>,
|
|
|
|
) {
|
|
|
|
if !cubemap.is_loaded
|
|
|
|
&& asset_server.get_load_state(cubemap.image_handle.clone_weak()) == LoadState::Loaded
|
|
|
|
{
|
|
|
|
info!("Swapping to {}...", CUBEMAPS[cubemap.index].0);
|
|
|
|
let mut image = images.get_mut(&cubemap.image_handle).unwrap();
|
|
|
|
// NOTE: PNGs do not have any metadata that could indicate they contain a cubemap texture,
|
|
|
|
// so they appear as one texture. The following code reconfigures the texture as necessary.
|
|
|
|
if image.texture_descriptor.array_layer_count() == 1 {
|
|
|
|
image.reinterpret_stacked_2d_as_array(
|
|
|
|
image.texture_descriptor.size.height / image.texture_descriptor.size.width,
|
|
|
|
);
|
|
|
|
image.texture_view_descriptor = Some(TextureViewDescriptor {
|
|
|
|
dimension: Some(TextureViewDimension::Cube),
|
|
|
|
..default()
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// spawn cube
|
|
|
|
let mut updated = false;
|
|
|
|
for handle in cubes.iter() {
|
|
|
|
if let Some(material) = cubemap_materials.get_mut(handle) {
|
|
|
|
updated = true;
|
|
|
|
material.base_color_texture = Some(cubemap.image_handle.clone_weak());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !updated {
|
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(MaterialMeshBundle::<CubemapMaterial> {
|
Support array / cubemap / cubemap array textures in KTX2 (#5325)
# Objective
- Fix / support KTX2 array / cubemap / cubemap array textures
- Fixes #4495 . Supersedes #4514 .
## Solution
- Add `Option<TextureViewDescriptor>` to `Image` to enable configuration of the `TextureViewDimension` of a texture.
- This allows users to set `D2Array`, `D3`, `Cube`, `CubeArray` or whatever they need
- Automatically configure this when loading KTX2
- Transcode all layers and faces instead of just one
- Use the UASTC block size of 128 bits, and the number of blocks in x/y for a given mip level in order to determine the offset of the layer and face within the KTX2 mip level data
- `wgpu` wants data ordered as layer 0 mip 0..n, layer 1 mip 0..n, etc. See https://docs.rs/wgpu/latest/wgpu/util/trait.DeviceExt.html#tymethod.create_texture_with_data
- Reorder the data KTX2 mip X layer Y face Z to `wgpu` layer Y face Z mip X order
- Add a `skybox` example to demonstrate / test loading cubemaps from PNG and KTX2, including ASTC 4x4, BC7, and ETC2 compression for support everywhere. Note that you need to enable the `ktx2,zstd` features to be able to load the compressed textures.
---
## Changelog
- Fixed: KTX2 array / cubemap / cubemap array textures
- Fixes: Validation failure for compressed textures stored in KTX2 where the width/height are not a multiple of the block dimensions.
- Added: `Image` now has an `Option<TextureViewDescriptor>` field to enable configuration of the texture view. This is useful for configuring the `TextureViewDimension` when it is not just a plain 2D texture and the loader could/did not identify what it should be.
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-07-30 07:02:58 +00:00
|
|
|
mesh: meshes.add(Mesh::from(shape::Cube { size: 10000.0 })),
|
|
|
|
material: cubemap_materials.add(CubemapMaterial {
|
|
|
|
base_color_texture: Some(cubemap.image_handle.clone_weak()),
|
|
|
|
}),
|
|
|
|
..default()
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
cubemap.is_loaded = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn animate_light_direction(
|
|
|
|
time: Res<Time>,
|
|
|
|
mut query: Query<&mut Transform, With<DirectionalLight>>,
|
|
|
|
) {
|
|
|
|
for mut transform in &mut query {
|
|
|
|
transform.rotate_y(time.delta_seconds() * 0.5);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, TypeUuid)]
|
|
|
|
#[uuid = "9509a0f8-3c05-48ee-a13e-a93226c7f488"]
|
|
|
|
struct CubemapMaterial {
|
|
|
|
base_color_texture: Option<Handle<Image>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Material for CubemapMaterial {
|
|
|
|
fn fragment_shader() -> ShaderRef {
|
|
|
|
"shaders/cubemap_unlit.wgsl".into()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn specialize(
|
|
|
|
_pipeline: &MaterialPipeline<Self>,
|
|
|
|
descriptor: &mut RenderPipelineDescriptor,
|
|
|
|
_layout: &MeshVertexBufferLayout,
|
|
|
|
_key: MaterialPipelineKey<Self>,
|
|
|
|
) -> Result<(), SpecializedMeshPipelineError> {
|
|
|
|
descriptor.primitive.cull_mode = None;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AsBindGroup for CubemapMaterial {
|
|
|
|
type Data = ();
|
|
|
|
|
|
|
|
fn as_bind_group(
|
|
|
|
&self,
|
|
|
|
layout: &BindGroupLayout,
|
|
|
|
render_device: &RenderDevice,
|
|
|
|
images: &RenderAssets<Image>,
|
|
|
|
_fallback_image: &FallbackImage,
|
|
|
|
) -> Result<PreparedBindGroup<Self>, AsBindGroupError> {
|
|
|
|
let base_color_texture = self
|
|
|
|
.base_color_texture
|
|
|
|
.as_ref()
|
|
|
|
.ok_or(AsBindGroupError::RetryNextUpdate)?;
|
|
|
|
let image = images
|
|
|
|
.get(base_color_texture)
|
|
|
|
.ok_or(AsBindGroupError::RetryNextUpdate)?;
|
|
|
|
let bind_group = render_device.create_bind_group(&BindGroupDescriptor {
|
|
|
|
entries: &[
|
|
|
|
BindGroupEntry {
|
|
|
|
binding: 0,
|
|
|
|
resource: BindingResource::TextureView(&image.texture_view),
|
|
|
|
},
|
|
|
|
BindGroupEntry {
|
|
|
|
binding: 1,
|
|
|
|
resource: BindingResource::Sampler(&image.sampler),
|
|
|
|
},
|
|
|
|
],
|
|
|
|
label: Some("cubemap_texture_material_bind_group"),
|
|
|
|
layout,
|
|
|
|
});
|
|
|
|
|
|
|
|
Ok(PreparedBindGroup {
|
|
|
|
bind_group,
|
|
|
|
bindings: vec![
|
|
|
|
OwnedBindingResource::TextureView(image.texture_view.clone()),
|
|
|
|
OwnedBindingResource::Sampler(image.sampler.clone()),
|
|
|
|
],
|
|
|
|
data: (),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn bind_group_layout(render_device: &RenderDevice) -> BindGroupLayout {
|
|
|
|
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
|
|
|
entries: &[
|
|
|
|
// Cubemap Base Color Texture
|
|
|
|
BindGroupLayoutEntry {
|
|
|
|
binding: 0,
|
|
|
|
visibility: ShaderStages::FRAGMENT,
|
|
|
|
ty: BindingType::Texture {
|
|
|
|
multisampled: false,
|
|
|
|
sample_type: TextureSampleType::Float { filterable: true },
|
|
|
|
view_dimension: TextureViewDimension::Cube,
|
|
|
|
},
|
|
|
|
count: None,
|
|
|
|
},
|
|
|
|
// Cubemap Base Color Texture Sampler
|
|
|
|
BindGroupLayoutEntry {
|
|
|
|
binding: 1,
|
|
|
|
visibility: ShaderStages::FRAGMENT,
|
|
|
|
ty: BindingType::Sampler(SamplerBindingType::Filtering),
|
|
|
|
count: None,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
label: None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Component)]
|
|
|
|
pub struct CameraController {
|
|
|
|
pub enabled: bool,
|
|
|
|
pub initialized: bool,
|
|
|
|
pub sensitivity: f32,
|
|
|
|
pub key_forward: KeyCode,
|
|
|
|
pub key_back: KeyCode,
|
|
|
|
pub key_left: KeyCode,
|
|
|
|
pub key_right: KeyCode,
|
|
|
|
pub key_up: KeyCode,
|
|
|
|
pub key_down: KeyCode,
|
|
|
|
pub key_run: KeyCode,
|
|
|
|
pub mouse_key_enable_mouse: MouseButton,
|
|
|
|
pub keyboard_key_enable_mouse: KeyCode,
|
|
|
|
pub walk_speed: f32,
|
|
|
|
pub run_speed: f32,
|
|
|
|
pub friction: f32,
|
|
|
|
pub pitch: f32,
|
|
|
|
pub yaw: f32,
|
|
|
|
pub velocity: Vec3,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for CameraController {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
enabled: true,
|
|
|
|
initialized: false,
|
|
|
|
sensitivity: 0.5,
|
|
|
|
key_forward: KeyCode::W,
|
|
|
|
key_back: KeyCode::S,
|
|
|
|
key_left: KeyCode::A,
|
|
|
|
key_right: KeyCode::D,
|
|
|
|
key_up: KeyCode::E,
|
|
|
|
key_down: KeyCode::Q,
|
|
|
|
key_run: KeyCode::LShift,
|
|
|
|
mouse_key_enable_mouse: MouseButton::Left,
|
|
|
|
keyboard_key_enable_mouse: KeyCode::M,
|
|
|
|
walk_speed: 2.0,
|
|
|
|
run_speed: 6.0,
|
|
|
|
friction: 0.5,
|
|
|
|
pitch: 0.0,
|
|
|
|
yaw: 0.0,
|
|
|
|
velocity: Vec3::ZERO,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn camera_controller(
|
|
|
|
time: Res<Time>,
|
|
|
|
mut mouse_events: EventReader<MouseMotion>,
|
|
|
|
mouse_button_input: Res<Input<MouseButton>>,
|
|
|
|
key_input: Res<Input<KeyCode>>,
|
|
|
|
mut move_toggled: Local<bool>,
|
|
|
|
mut query: Query<(&mut Transform, &mut CameraController), With<Camera>>,
|
|
|
|
) {
|
|
|
|
let dt = time.delta_seconds();
|
|
|
|
|
|
|
|
if let Ok((mut transform, mut options)) = query.get_single_mut() {
|
|
|
|
if !options.initialized {
|
|
|
|
let (yaw, pitch, _roll) = transform.rotation.to_euler(EulerRot::YXZ);
|
|
|
|
options.yaw = yaw;
|
|
|
|
options.pitch = pitch;
|
|
|
|
options.initialized = true;
|
|
|
|
}
|
|
|
|
if !options.enabled {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle key input
|
|
|
|
let mut axis_input = Vec3::ZERO;
|
|
|
|
if key_input.pressed(options.key_forward) {
|
|
|
|
axis_input.z += 1.0;
|
|
|
|
}
|
|
|
|
if key_input.pressed(options.key_back) {
|
|
|
|
axis_input.z -= 1.0;
|
|
|
|
}
|
|
|
|
if key_input.pressed(options.key_right) {
|
|
|
|
axis_input.x += 1.0;
|
|
|
|
}
|
|
|
|
if key_input.pressed(options.key_left) {
|
|
|
|
axis_input.x -= 1.0;
|
|
|
|
}
|
|
|
|
if key_input.pressed(options.key_up) {
|
|
|
|
axis_input.y += 1.0;
|
|
|
|
}
|
|
|
|
if key_input.pressed(options.key_down) {
|
|
|
|
axis_input.y -= 1.0;
|
|
|
|
}
|
|
|
|
if key_input.just_pressed(options.keyboard_key_enable_mouse) {
|
|
|
|
*move_toggled = !*move_toggled;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Apply movement update
|
|
|
|
if axis_input != Vec3::ZERO {
|
|
|
|
let max_speed = if key_input.pressed(options.key_run) {
|
|
|
|
options.run_speed
|
|
|
|
} else {
|
|
|
|
options.walk_speed
|
|
|
|
};
|
|
|
|
options.velocity = axis_input.normalize() * max_speed;
|
|
|
|
} else {
|
|
|
|
let friction = options.friction.clamp(0.0, 1.0);
|
|
|
|
options.velocity *= 1.0 - friction;
|
|
|
|
if options.velocity.length_squared() < 1e-6 {
|
|
|
|
options.velocity = Vec3::ZERO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let forward = transform.forward();
|
|
|
|
let right = transform.right();
|
|
|
|
transform.translation += options.velocity.x * dt * right
|
|
|
|
+ options.velocity.y * dt * Vec3::Y
|
|
|
|
+ options.velocity.z * dt * forward;
|
|
|
|
|
|
|
|
// Handle mouse input
|
|
|
|
let mut mouse_delta = Vec2::ZERO;
|
|
|
|
if mouse_button_input.pressed(options.mouse_key_enable_mouse) || *move_toggled {
|
|
|
|
for mouse_event in mouse_events.iter() {
|
|
|
|
mouse_delta += mouse_event.delta;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if mouse_delta != Vec2::ZERO {
|
|
|
|
// Apply look update
|
2022-08-30 19:52:11 +00:00
|
|
|
options.pitch = (options.pitch - mouse_delta.y * 0.5 * options.sensitivity * dt)
|
|
|
|
.clamp(-PI / 2., PI / 2.);
|
|
|
|
options.yaw -= mouse_delta.x * options.sensitivity * dt;
|
|
|
|
transform.rotation = Quat::from_euler(EulerRot::ZYX, 0.0, options.yaw, options.pitch);
|
Support array / cubemap / cubemap array textures in KTX2 (#5325)
# Objective
- Fix / support KTX2 array / cubemap / cubemap array textures
- Fixes #4495 . Supersedes #4514 .
## Solution
- Add `Option<TextureViewDescriptor>` to `Image` to enable configuration of the `TextureViewDimension` of a texture.
- This allows users to set `D2Array`, `D3`, `Cube`, `CubeArray` or whatever they need
- Automatically configure this when loading KTX2
- Transcode all layers and faces instead of just one
- Use the UASTC block size of 128 bits, and the number of blocks in x/y for a given mip level in order to determine the offset of the layer and face within the KTX2 mip level data
- `wgpu` wants data ordered as layer 0 mip 0..n, layer 1 mip 0..n, etc. See https://docs.rs/wgpu/latest/wgpu/util/trait.DeviceExt.html#tymethod.create_texture_with_data
- Reorder the data KTX2 mip X layer Y face Z to `wgpu` layer Y face Z mip X order
- Add a `skybox` example to demonstrate / test loading cubemaps from PNG and KTX2, including ASTC 4x4, BC7, and ETC2 compression for support everywhere. Note that you need to enable the `ktx2,zstd` features to be able to load the compressed textures.
---
## Changelog
- Fixed: KTX2 array / cubemap / cubemap array textures
- Fixes: Validation failure for compressed textures stored in KTX2 where the width/height are not a multiple of the block dimensions.
- Added: `Image` now has an `Option<TextureViewDescriptor>` field to enable configuration of the texture view. This is useful for configuring the `TextureViewDimension` when it is not just a plain 2D texture and the loader could/did not identify what it should be.
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-07-30 07:02:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|