2023-02-24 18:33:55 +00:00
|
|
|
use bevy_app::{IntoSystemAppConfig, Plugin};
|
2023-01-19 22:11:13 +00:00
|
|
|
use bevy_asset::{load_internal_asset, AssetServer, Handle, HandleUntyped};
|
|
|
|
use bevy_core_pipeline::{
|
|
|
|
prelude::Camera3d,
|
|
|
|
prepass::{
|
|
|
|
AlphaMask3dPrepass, DepthPrepass, NormalPrepass, Opaque3dPrepass, ViewPrepassTextures,
|
|
|
|
DEPTH_PREPASS_FORMAT, NORMAL_PREPASS_FORMAT,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
use bevy_ecs::{
|
Migrate engine to Schedule v3 (#7267)
Huge thanks to @maniwani, @devil-ira, @hymm, @cart, @superdump and @jakobhellermann for the help with this PR.
# Objective
- Followup #6587.
- Minimal integration for the Stageless Scheduling RFC: https://github.com/bevyengine/rfcs/pull/45
## Solution
- [x] Remove old scheduling module
- [x] Migrate new methods to no longer use extension methods
- [x] Fix compiler errors
- [x] Fix benchmarks
- [x] Fix examples
- [x] Fix docs
- [x] Fix tests
## Changelog
### Added
- a large number of methods on `App` to work with schedules ergonomically
- the `CoreSchedule` enum
- `App::add_extract_system` via the `RenderingAppExtension` trait extension method
- the private `prepare_view_uniforms` system now has a public system set for scheduling purposes, called `ViewSet::PrepareUniforms`
### Removed
- stages, and all code that mentions stages
- states have been dramatically simplified, and no longer use a stack
- `RunCriteriaLabel`
- `AsSystemLabel` trait
- `on_hierarchy_reports_enabled` run criteria (now just uses an ad hoc resource checking run condition)
- systems in `RenderSet/Stage::Extract` no longer warn when they do not read data from the main world
- `RunCriteriaLabel`
- `transform_propagate_system_set`: this was a nonstandard pattern that didn't actually provide enough control. The systems are already `pub`: the docs have been updated to ensure that the third-party usage is clear.
### Changed
- `System::default_labels` is now `System::default_system_sets`.
- `App::add_default_labels` is now `App::add_default_sets`
- `CoreStage` and `StartupStage` enums are now `CoreSet` and `StartupSet`
- `App::add_system_set` was renamed to `App::add_systems`
- The `StartupSchedule` label is now defined as part of the `CoreSchedules` enum
- `.label(SystemLabel)` is now referred to as `.in_set(SystemSet)`
- `SystemLabel` trait was replaced by `SystemSet`
- `SystemTypeIdLabel<T>` was replaced by `SystemSetType<T>`
- The `ReportHierarchyIssue` resource now has a public constructor (`new`), and implements `PartialEq`
- Fixed time steps now use a schedule (`CoreSchedule::FixedTimeStep`) rather than a run criteria.
- Adding rendering extraction systems now panics rather than silently failing if no subapp with the `RenderApp` label is found.
- the `calculate_bounds` system, with the `CalculateBounds` label, is now in `CoreSet::Update`, rather than in `CoreSet::PostUpdate` before commands are applied.
- `SceneSpawnerSystem` now runs under `CoreSet::Update`, rather than `CoreStage::PreUpdate.at_end()`.
- `bevy_pbr::add_clusters` is no longer an exclusive system
- the top level `bevy_ecs::schedule` module was replaced with `bevy_ecs::scheduling`
- `tick_global_task_pools_on_main_thread` is no longer run as an exclusive system. Instead, it has been replaced by `tick_global_task_pools`, which uses a `NonSend` resource to force running on the main thread.
## Migration Guide
- Calls to `.label(MyLabel)` should be replaced with `.in_set(MySet)`
- Stages have been removed. Replace these with system sets, and then add command flushes using the `apply_system_buffers` exclusive system where needed.
- The `CoreStage`, `StartupStage, `RenderStage` and `AssetStage` enums have been replaced with `CoreSet`, `StartupSet, `RenderSet` and `AssetSet`. The same scheduling guarantees have been preserved.
- Systems are no longer added to `CoreSet::Update` by default. Add systems manually if this behavior is needed, although you should consider adding your game logic systems to `CoreSchedule::FixedTimestep` instead for more reliable framerate-independent behavior.
- Similarly, startup systems are no longer part of `StartupSet::Startup` by default. In most cases, this won't matter to you.
- For example, `add_system_to_stage(CoreStage::PostUpdate, my_system)` should be replaced with
- `add_system(my_system.in_set(CoreSet::PostUpdate)`
- When testing systems or otherwise running them in a headless fashion, simply construct and run a schedule using `Schedule::new()` and `World::run_schedule` rather than constructing stages
- Run criteria have been renamed to run conditions. These can now be combined with each other and with states.
- Looping run criteria and state stacks have been removed. Use an exclusive system that runs a schedule if you need this level of control over system control flow.
- For app-level control flow over which schedules get run when (such as for rollback networking), create your own schedule and insert it under the `CoreSchedule::Outer` label.
- Fixed timesteps are now evaluated in a schedule, rather than controlled via run criteria. The `run_fixed_timestep` system runs this schedule between `CoreSet::First` and `CoreSet::PreUpdate` by default.
- Command flush points introduced by `AssetStage` have been removed. If you were relying on these, add them back manually.
- Adding extract systems is now typically done directly on the main app. Make sure the `RenderingAppExtension` trait is in scope, then call `app.add_extract_system(my_system)`.
- the `calculate_bounds` system, with the `CalculateBounds` label, is now in `CoreSet::Update`, rather than in `CoreSet::PostUpdate` before commands are applied. You may need to order your movement systems to occur before this system in order to avoid system order ambiguities in culling behavior.
- the `RenderLabel` `AppLabel` was renamed to `RenderApp` for clarity
- `App::add_state` now takes 0 arguments: the starting state is set based on the `Default` impl.
- Instead of creating `SystemSet` containers for systems that run in stages, simply use `.on_enter::<State::Variant>()` or its `on_exit` or `on_update` siblings.
- `SystemLabel` derives should be replaced with `SystemSet`. You will also need to add the `Debug`, `PartialEq`, `Eq`, and `Hash` traits to satisfy the new trait bounds.
- `with_run_criteria` has been renamed to `run_if`. Run criteria have been renamed to run conditions for clarity, and should now simply return a bool.
- States have been dramatically simplified: there is no longer a "state stack". To queue a transition to the next state, call `NextState::set`
## TODO
- [x] remove dead methods on App and World
- [x] add `App::add_system_to_schedule` and `App::add_systems_to_schedule`
- [x] avoid adding the default system set at inappropriate times
- [x] remove any accidental cycles in the default plugins schedule
- [x] migrate benchmarks
- [x] expose explicit labels for the built-in command flush points
- [x] migrate engine code
- [x] remove all mentions of stages from the docs
- [x] verify docs for States
- [x] fix uses of exclusive systems that use .end / .at_start / .before_commands
- [x] migrate RenderStage and AssetStage
- [x] migrate examples
- [x] ensure that transform propagation is exported in a sufficiently public way (the systems are already pub)
- [x] ensure that on_enter schedules are run at least once before the main app
- [x] re-enable opt-in to execution order ambiguities
- [x] revert change to `update_bounds` to ensure it runs in `PostUpdate`
- [x] test all examples
- [x] unbreak directional lights
- [x] unbreak shadows (see 3d_scene, 3d_shape, lighting, transparaency_3d examples)
- [x] game menu example shows loading screen and menu simultaneously
- [x] display settings menu is a blank screen
- [x] `without_winit` example panics
- [x] ensure all tests pass
- [x] SubApp doc test fails
- [x] runs_spawn_local tasks fails
- [x] [Fix panic_when_hierachy_cycle test hanging](https://github.com/alice-i-cecile/bevy/pull/120)
## Points of Difficulty and Controversy
**Reviewers, please give feedback on these and look closely**
1. Default sets, from the RFC, have been removed. These added a tremendous amount of implicit complexity and result in hard to debug scheduling errors. They're going to be tackled in the form of "base sets" by @cart in a followup.
2. The outer schedule controls which schedule is run when `App::update` is called.
3. I implemented `Label for `Box<dyn Label>` for our label types. This enables us to store schedule labels in concrete form, and then later run them. I ran into the same set of problems when working with one-shot systems. We've previously investigated this pattern in depth, and it does not appear to lead to extra indirection with nested boxes.
4. `SubApp::update` simply runs the default schedule once. This sucks, but this whole API is incomplete and this was the minimal changeset.
5. `time_system` and `tick_global_task_pools_on_main_thread` no longer use exclusive systems to attempt to force scheduling order
6. Implemetnation strategy for fixed timesteps
7. `AssetStage` was migrated to `AssetSet` without reintroducing command flush points. These did not appear to be used, and it's nice to remove these bottlenecks.
8. Migration of `bevy_render/lib.rs` and pipelined rendering. The logic here is unusually tricky, as we have complex scheduling requirements.
## Future Work (ideally before 0.10)
- Rename schedule_v3 module to schedule or scheduling
- Add a derive macro to states, and likely a `EnumIter` trait of some form
- Figure out what exactly to do with the "systems added should basically work by default" problem
- Improve ergonomics for working with fixed timesteps and states
- Polish FixedTime API to match Time
- Rebase and merge #7415
- Resolve all internal ambiguities (blocked on better tools, especially #7442)
- Add "base sets" to replace the removed default sets.
2023-02-06 02:04:50 +00:00
|
|
|
prelude::*,
|
2023-01-19 22:11:13 +00:00
|
|
|
system::{
|
|
|
|
lifetimeless::{Read, SRes},
|
Migrate engine to Schedule v3 (#7267)
Huge thanks to @maniwani, @devil-ira, @hymm, @cart, @superdump and @jakobhellermann for the help with this PR.
# Objective
- Followup #6587.
- Minimal integration for the Stageless Scheduling RFC: https://github.com/bevyengine/rfcs/pull/45
## Solution
- [x] Remove old scheduling module
- [x] Migrate new methods to no longer use extension methods
- [x] Fix compiler errors
- [x] Fix benchmarks
- [x] Fix examples
- [x] Fix docs
- [x] Fix tests
## Changelog
### Added
- a large number of methods on `App` to work with schedules ergonomically
- the `CoreSchedule` enum
- `App::add_extract_system` via the `RenderingAppExtension` trait extension method
- the private `prepare_view_uniforms` system now has a public system set for scheduling purposes, called `ViewSet::PrepareUniforms`
### Removed
- stages, and all code that mentions stages
- states have been dramatically simplified, and no longer use a stack
- `RunCriteriaLabel`
- `AsSystemLabel` trait
- `on_hierarchy_reports_enabled` run criteria (now just uses an ad hoc resource checking run condition)
- systems in `RenderSet/Stage::Extract` no longer warn when they do not read data from the main world
- `RunCriteriaLabel`
- `transform_propagate_system_set`: this was a nonstandard pattern that didn't actually provide enough control. The systems are already `pub`: the docs have been updated to ensure that the third-party usage is clear.
### Changed
- `System::default_labels` is now `System::default_system_sets`.
- `App::add_default_labels` is now `App::add_default_sets`
- `CoreStage` and `StartupStage` enums are now `CoreSet` and `StartupSet`
- `App::add_system_set` was renamed to `App::add_systems`
- The `StartupSchedule` label is now defined as part of the `CoreSchedules` enum
- `.label(SystemLabel)` is now referred to as `.in_set(SystemSet)`
- `SystemLabel` trait was replaced by `SystemSet`
- `SystemTypeIdLabel<T>` was replaced by `SystemSetType<T>`
- The `ReportHierarchyIssue` resource now has a public constructor (`new`), and implements `PartialEq`
- Fixed time steps now use a schedule (`CoreSchedule::FixedTimeStep`) rather than a run criteria.
- Adding rendering extraction systems now panics rather than silently failing if no subapp with the `RenderApp` label is found.
- the `calculate_bounds` system, with the `CalculateBounds` label, is now in `CoreSet::Update`, rather than in `CoreSet::PostUpdate` before commands are applied.
- `SceneSpawnerSystem` now runs under `CoreSet::Update`, rather than `CoreStage::PreUpdate.at_end()`.
- `bevy_pbr::add_clusters` is no longer an exclusive system
- the top level `bevy_ecs::schedule` module was replaced with `bevy_ecs::scheduling`
- `tick_global_task_pools_on_main_thread` is no longer run as an exclusive system. Instead, it has been replaced by `tick_global_task_pools`, which uses a `NonSend` resource to force running on the main thread.
## Migration Guide
- Calls to `.label(MyLabel)` should be replaced with `.in_set(MySet)`
- Stages have been removed. Replace these with system sets, and then add command flushes using the `apply_system_buffers` exclusive system where needed.
- The `CoreStage`, `StartupStage, `RenderStage` and `AssetStage` enums have been replaced with `CoreSet`, `StartupSet, `RenderSet` and `AssetSet`. The same scheduling guarantees have been preserved.
- Systems are no longer added to `CoreSet::Update` by default. Add systems manually if this behavior is needed, although you should consider adding your game logic systems to `CoreSchedule::FixedTimestep` instead for more reliable framerate-independent behavior.
- Similarly, startup systems are no longer part of `StartupSet::Startup` by default. In most cases, this won't matter to you.
- For example, `add_system_to_stage(CoreStage::PostUpdate, my_system)` should be replaced with
- `add_system(my_system.in_set(CoreSet::PostUpdate)`
- When testing systems or otherwise running them in a headless fashion, simply construct and run a schedule using `Schedule::new()` and `World::run_schedule` rather than constructing stages
- Run criteria have been renamed to run conditions. These can now be combined with each other and with states.
- Looping run criteria and state stacks have been removed. Use an exclusive system that runs a schedule if you need this level of control over system control flow.
- For app-level control flow over which schedules get run when (such as for rollback networking), create your own schedule and insert it under the `CoreSchedule::Outer` label.
- Fixed timesteps are now evaluated in a schedule, rather than controlled via run criteria. The `run_fixed_timestep` system runs this schedule between `CoreSet::First` and `CoreSet::PreUpdate` by default.
- Command flush points introduced by `AssetStage` have been removed. If you were relying on these, add them back manually.
- Adding extract systems is now typically done directly on the main app. Make sure the `RenderingAppExtension` trait is in scope, then call `app.add_extract_system(my_system)`.
- the `calculate_bounds` system, with the `CalculateBounds` label, is now in `CoreSet::Update`, rather than in `CoreSet::PostUpdate` before commands are applied. You may need to order your movement systems to occur before this system in order to avoid system order ambiguities in culling behavior.
- the `RenderLabel` `AppLabel` was renamed to `RenderApp` for clarity
- `App::add_state` now takes 0 arguments: the starting state is set based on the `Default` impl.
- Instead of creating `SystemSet` containers for systems that run in stages, simply use `.on_enter::<State::Variant>()` or its `on_exit` or `on_update` siblings.
- `SystemLabel` derives should be replaced with `SystemSet`. You will also need to add the `Debug`, `PartialEq`, `Eq`, and `Hash` traits to satisfy the new trait bounds.
- `with_run_criteria` has been renamed to `run_if`. Run criteria have been renamed to run conditions for clarity, and should now simply return a bool.
- States have been dramatically simplified: there is no longer a "state stack". To queue a transition to the next state, call `NextState::set`
## TODO
- [x] remove dead methods on App and World
- [x] add `App::add_system_to_schedule` and `App::add_systems_to_schedule`
- [x] avoid adding the default system set at inappropriate times
- [x] remove any accidental cycles in the default plugins schedule
- [x] migrate benchmarks
- [x] expose explicit labels for the built-in command flush points
- [x] migrate engine code
- [x] remove all mentions of stages from the docs
- [x] verify docs for States
- [x] fix uses of exclusive systems that use .end / .at_start / .before_commands
- [x] migrate RenderStage and AssetStage
- [x] migrate examples
- [x] ensure that transform propagation is exported in a sufficiently public way (the systems are already pub)
- [x] ensure that on_enter schedules are run at least once before the main app
- [x] re-enable opt-in to execution order ambiguities
- [x] revert change to `update_bounds` to ensure it runs in `PostUpdate`
- [x] test all examples
- [x] unbreak directional lights
- [x] unbreak shadows (see 3d_scene, 3d_shape, lighting, transparaency_3d examples)
- [x] game menu example shows loading screen and menu simultaneously
- [x] display settings menu is a blank screen
- [x] `without_winit` example panics
- [x] ensure all tests pass
- [x] SubApp doc test fails
- [x] runs_spawn_local tasks fails
- [x] [Fix panic_when_hierachy_cycle test hanging](https://github.com/alice-i-cecile/bevy/pull/120)
## Points of Difficulty and Controversy
**Reviewers, please give feedback on these and look closely**
1. Default sets, from the RFC, have been removed. These added a tremendous amount of implicit complexity and result in hard to debug scheduling errors. They're going to be tackled in the form of "base sets" by @cart in a followup.
2. The outer schedule controls which schedule is run when `App::update` is called.
3. I implemented `Label for `Box<dyn Label>` for our label types. This enables us to store schedule labels in concrete form, and then later run them. I ran into the same set of problems when working with one-shot systems. We've previously investigated this pattern in depth, and it does not appear to lead to extra indirection with nested boxes.
4. `SubApp::update` simply runs the default schedule once. This sucks, but this whole API is incomplete and this was the minimal changeset.
5. `time_system` and `tick_global_task_pools_on_main_thread` no longer use exclusive systems to attempt to force scheduling order
6. Implemetnation strategy for fixed timesteps
7. `AssetStage` was migrated to `AssetSet` without reintroducing command flush points. These did not appear to be used, and it's nice to remove these bottlenecks.
8. Migration of `bevy_render/lib.rs` and pipelined rendering. The logic here is unusually tricky, as we have complex scheduling requirements.
## Future Work (ideally before 0.10)
- Rename schedule_v3 module to schedule or scheduling
- Add a derive macro to states, and likely a `EnumIter` trait of some form
- Figure out what exactly to do with the "systems added should basically work by default" problem
- Improve ergonomics for working with fixed timesteps and states
- Polish FixedTime API to match Time
- Rebase and merge #7415
- Resolve all internal ambiguities (blocked on better tools, especially #7442)
- Add "base sets" to replace the removed default sets.
2023-02-06 02:04:50 +00:00
|
|
|
SystemParamItem,
|
2023-01-19 22:11:13 +00:00
|
|
|
},
|
|
|
|
};
|
|
|
|
use bevy_reflect::TypeUuid;
|
|
|
|
use bevy_render::{
|
|
|
|
camera::ExtractedCamera,
|
|
|
|
mesh::MeshVertexBufferLayout,
|
|
|
|
prelude::{Camera, Mesh},
|
|
|
|
render_asset::RenderAssets,
|
|
|
|
render_phase::{
|
|
|
|
sort_phase_system, AddRenderCommand, DrawFunctions, PhaseItem, RenderCommand,
|
|
|
|
RenderCommandResult, RenderPhase, SetItemPipeline, TrackedRenderPass,
|
|
|
|
},
|
|
|
|
render_resource::{
|
|
|
|
BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindGroupLayoutDescriptor,
|
2023-03-02 02:23:06 +00:00
|
|
|
BindGroupLayoutEntry, BindingResource, BindingType, BlendState, BufferBindingType,
|
|
|
|
ColorTargetState, ColorWrites, CompareFunction, DepthBiasState, DepthStencilState,
|
|
|
|
Extent3d, FragmentState, FrontFace, MultisampleState, PipelineCache, PolygonMode,
|
|
|
|
PrimitiveState, RenderPipelineDescriptor, Shader, ShaderDefVal, ShaderRef, ShaderStages,
|
|
|
|
ShaderType, SpecializedMeshPipeline, SpecializedMeshPipelineError,
|
|
|
|
SpecializedMeshPipelines, StencilFaceState, StencilState, TextureDescriptor,
|
|
|
|
TextureDimension, TextureFormat, TextureSampleType, TextureUsages, TextureViewDimension,
|
|
|
|
VertexState,
|
2023-01-19 22:11:13 +00:00
|
|
|
},
|
|
|
|
renderer::RenderDevice,
|
2023-03-02 02:23:06 +00:00
|
|
|
texture::{FallbackImagesDepth, FallbackImagesMsaa, TextureCache},
|
2023-01-19 22:11:13 +00:00
|
|
|
view::{ExtractedView, Msaa, ViewUniform, ViewUniformOffset, ViewUniforms, VisibleEntities},
|
Migrate engine to Schedule v3 (#7267)
Huge thanks to @maniwani, @devil-ira, @hymm, @cart, @superdump and @jakobhellermann for the help with this PR.
# Objective
- Followup #6587.
- Minimal integration for the Stageless Scheduling RFC: https://github.com/bevyengine/rfcs/pull/45
## Solution
- [x] Remove old scheduling module
- [x] Migrate new methods to no longer use extension methods
- [x] Fix compiler errors
- [x] Fix benchmarks
- [x] Fix examples
- [x] Fix docs
- [x] Fix tests
## Changelog
### Added
- a large number of methods on `App` to work with schedules ergonomically
- the `CoreSchedule` enum
- `App::add_extract_system` via the `RenderingAppExtension` trait extension method
- the private `prepare_view_uniforms` system now has a public system set for scheduling purposes, called `ViewSet::PrepareUniforms`
### Removed
- stages, and all code that mentions stages
- states have been dramatically simplified, and no longer use a stack
- `RunCriteriaLabel`
- `AsSystemLabel` trait
- `on_hierarchy_reports_enabled` run criteria (now just uses an ad hoc resource checking run condition)
- systems in `RenderSet/Stage::Extract` no longer warn when they do not read data from the main world
- `RunCriteriaLabel`
- `transform_propagate_system_set`: this was a nonstandard pattern that didn't actually provide enough control. The systems are already `pub`: the docs have been updated to ensure that the third-party usage is clear.
### Changed
- `System::default_labels` is now `System::default_system_sets`.
- `App::add_default_labels` is now `App::add_default_sets`
- `CoreStage` and `StartupStage` enums are now `CoreSet` and `StartupSet`
- `App::add_system_set` was renamed to `App::add_systems`
- The `StartupSchedule` label is now defined as part of the `CoreSchedules` enum
- `.label(SystemLabel)` is now referred to as `.in_set(SystemSet)`
- `SystemLabel` trait was replaced by `SystemSet`
- `SystemTypeIdLabel<T>` was replaced by `SystemSetType<T>`
- The `ReportHierarchyIssue` resource now has a public constructor (`new`), and implements `PartialEq`
- Fixed time steps now use a schedule (`CoreSchedule::FixedTimeStep`) rather than a run criteria.
- Adding rendering extraction systems now panics rather than silently failing if no subapp with the `RenderApp` label is found.
- the `calculate_bounds` system, with the `CalculateBounds` label, is now in `CoreSet::Update`, rather than in `CoreSet::PostUpdate` before commands are applied.
- `SceneSpawnerSystem` now runs under `CoreSet::Update`, rather than `CoreStage::PreUpdate.at_end()`.
- `bevy_pbr::add_clusters` is no longer an exclusive system
- the top level `bevy_ecs::schedule` module was replaced with `bevy_ecs::scheduling`
- `tick_global_task_pools_on_main_thread` is no longer run as an exclusive system. Instead, it has been replaced by `tick_global_task_pools`, which uses a `NonSend` resource to force running on the main thread.
## Migration Guide
- Calls to `.label(MyLabel)` should be replaced with `.in_set(MySet)`
- Stages have been removed. Replace these with system sets, and then add command flushes using the `apply_system_buffers` exclusive system where needed.
- The `CoreStage`, `StartupStage, `RenderStage` and `AssetStage` enums have been replaced with `CoreSet`, `StartupSet, `RenderSet` and `AssetSet`. The same scheduling guarantees have been preserved.
- Systems are no longer added to `CoreSet::Update` by default. Add systems manually if this behavior is needed, although you should consider adding your game logic systems to `CoreSchedule::FixedTimestep` instead for more reliable framerate-independent behavior.
- Similarly, startup systems are no longer part of `StartupSet::Startup` by default. In most cases, this won't matter to you.
- For example, `add_system_to_stage(CoreStage::PostUpdate, my_system)` should be replaced with
- `add_system(my_system.in_set(CoreSet::PostUpdate)`
- When testing systems or otherwise running them in a headless fashion, simply construct and run a schedule using `Schedule::new()` and `World::run_schedule` rather than constructing stages
- Run criteria have been renamed to run conditions. These can now be combined with each other and with states.
- Looping run criteria and state stacks have been removed. Use an exclusive system that runs a schedule if you need this level of control over system control flow.
- For app-level control flow over which schedules get run when (such as for rollback networking), create your own schedule and insert it under the `CoreSchedule::Outer` label.
- Fixed timesteps are now evaluated in a schedule, rather than controlled via run criteria. The `run_fixed_timestep` system runs this schedule between `CoreSet::First` and `CoreSet::PreUpdate` by default.
- Command flush points introduced by `AssetStage` have been removed. If you were relying on these, add them back manually.
- Adding extract systems is now typically done directly on the main app. Make sure the `RenderingAppExtension` trait is in scope, then call `app.add_extract_system(my_system)`.
- the `calculate_bounds` system, with the `CalculateBounds` label, is now in `CoreSet::Update`, rather than in `CoreSet::PostUpdate` before commands are applied. You may need to order your movement systems to occur before this system in order to avoid system order ambiguities in culling behavior.
- the `RenderLabel` `AppLabel` was renamed to `RenderApp` for clarity
- `App::add_state` now takes 0 arguments: the starting state is set based on the `Default` impl.
- Instead of creating `SystemSet` containers for systems that run in stages, simply use `.on_enter::<State::Variant>()` or its `on_exit` or `on_update` siblings.
- `SystemLabel` derives should be replaced with `SystemSet`. You will also need to add the `Debug`, `PartialEq`, `Eq`, and `Hash` traits to satisfy the new trait bounds.
- `with_run_criteria` has been renamed to `run_if`. Run criteria have been renamed to run conditions for clarity, and should now simply return a bool.
- States have been dramatically simplified: there is no longer a "state stack". To queue a transition to the next state, call `NextState::set`
## TODO
- [x] remove dead methods on App and World
- [x] add `App::add_system_to_schedule` and `App::add_systems_to_schedule`
- [x] avoid adding the default system set at inappropriate times
- [x] remove any accidental cycles in the default plugins schedule
- [x] migrate benchmarks
- [x] expose explicit labels for the built-in command flush points
- [x] migrate engine code
- [x] remove all mentions of stages from the docs
- [x] verify docs for States
- [x] fix uses of exclusive systems that use .end / .at_start / .before_commands
- [x] migrate RenderStage and AssetStage
- [x] migrate examples
- [x] ensure that transform propagation is exported in a sufficiently public way (the systems are already pub)
- [x] ensure that on_enter schedules are run at least once before the main app
- [x] re-enable opt-in to execution order ambiguities
- [x] revert change to `update_bounds` to ensure it runs in `PostUpdate`
- [x] test all examples
- [x] unbreak directional lights
- [x] unbreak shadows (see 3d_scene, 3d_shape, lighting, transparaency_3d examples)
- [x] game menu example shows loading screen and menu simultaneously
- [x] display settings menu is a blank screen
- [x] `without_winit` example panics
- [x] ensure all tests pass
- [x] SubApp doc test fails
- [x] runs_spawn_local tasks fails
- [x] [Fix panic_when_hierachy_cycle test hanging](https://github.com/alice-i-cecile/bevy/pull/120)
## Points of Difficulty and Controversy
**Reviewers, please give feedback on these and look closely**
1. Default sets, from the RFC, have been removed. These added a tremendous amount of implicit complexity and result in hard to debug scheduling errors. They're going to be tackled in the form of "base sets" by @cart in a followup.
2. The outer schedule controls which schedule is run when `App::update` is called.
3. I implemented `Label for `Box<dyn Label>` for our label types. This enables us to store schedule labels in concrete form, and then later run them. I ran into the same set of problems when working with one-shot systems. We've previously investigated this pattern in depth, and it does not appear to lead to extra indirection with nested boxes.
4. `SubApp::update` simply runs the default schedule once. This sucks, but this whole API is incomplete and this was the minimal changeset.
5. `time_system` and `tick_global_task_pools_on_main_thread` no longer use exclusive systems to attempt to force scheduling order
6. Implemetnation strategy for fixed timesteps
7. `AssetStage` was migrated to `AssetSet` without reintroducing command flush points. These did not appear to be used, and it's nice to remove these bottlenecks.
8. Migration of `bevy_render/lib.rs` and pipelined rendering. The logic here is unusually tricky, as we have complex scheduling requirements.
## Future Work (ideally before 0.10)
- Rename schedule_v3 module to schedule or scheduling
- Add a derive macro to states, and likely a `EnumIter` trait of some form
- Figure out what exactly to do with the "systems added should basically work by default" problem
- Improve ergonomics for working with fixed timesteps and states
- Polish FixedTime API to match Time
- Rebase and merge #7415
- Resolve all internal ambiguities (blocked on better tools, especially #7442)
- Add "base sets" to replace the removed default sets.
2023-02-06 02:04:50 +00:00
|
|
|
Extract, ExtractSchedule, RenderApp, RenderSet,
|
2023-01-19 22:11:13 +00:00
|
|
|
};
|
|
|
|
use bevy_utils::{tracing::error, HashMap};
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
AlphaMode, DrawMesh, Material, MaterialPipeline, MaterialPipelineKey, MeshPipeline,
|
|
|
|
MeshPipelineKey, MeshUniform, RenderMaterials, SetMaterialBindGroup, SetMeshBindGroup,
|
2023-01-30 22:53:08 +00:00
|
|
|
MAX_CASCADES_PER_LIGHT, MAX_DIRECTIONAL_LIGHTS,
|
2023-01-19 22:11:13 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
use std::{hash::Hash, marker::PhantomData};
|
|
|
|
|
|
|
|
pub const PREPASS_SHADER_HANDLE: HandleUntyped =
|
|
|
|
HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 921124473254008983);
|
|
|
|
|
|
|
|
pub const PREPASS_BINDINGS_SHADER_HANDLE: HandleUntyped =
|
|
|
|
HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 5533152893177403494);
|
|
|
|
|
2023-01-24 20:36:40 +00:00
|
|
|
pub const PREPASS_UTILS_SHADER_HANDLE: HandleUntyped =
|
|
|
|
HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 4603948296044544);
|
|
|
|
|
2023-01-19 22:11:13 +00:00
|
|
|
pub struct PrepassPlugin<M: Material>(PhantomData<M>);
|
|
|
|
|
|
|
|
impl<M: Material> Default for PrepassPlugin<M> {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self(Default::default())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<M: Material> Plugin for PrepassPlugin<M>
|
|
|
|
where
|
|
|
|
M::Data: PartialEq + Eq + Hash + Clone,
|
|
|
|
{
|
|
|
|
fn build(&self, app: &mut bevy_app::App) {
|
|
|
|
load_internal_asset!(
|
|
|
|
app,
|
|
|
|
PREPASS_SHADER_HANDLE,
|
|
|
|
"prepass.wgsl",
|
|
|
|
Shader::from_wgsl
|
|
|
|
);
|
|
|
|
|
|
|
|
load_internal_asset!(
|
|
|
|
app,
|
|
|
|
PREPASS_BINDINGS_SHADER_HANDLE,
|
|
|
|
"prepass_bindings.wgsl",
|
|
|
|
Shader::from_wgsl
|
|
|
|
);
|
|
|
|
|
2023-01-24 20:36:40 +00:00
|
|
|
load_internal_asset!(
|
|
|
|
app,
|
|
|
|
PREPASS_UTILS_SHADER_HANDLE,
|
|
|
|
"prepass_utils.wgsl",
|
|
|
|
Shader::from_wgsl
|
|
|
|
);
|
|
|
|
|
2023-01-19 22:11:13 +00:00
|
|
|
let Ok(render_app) = app.get_sub_app_mut(RenderApp) else {
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
|
|
|
render_app
|
2023-02-24 18:33:55 +00:00
|
|
|
.add_system(extract_camera_prepass_phase.in_schedule(ExtractSchedule))
|
2023-02-20 00:16:47 +00:00
|
|
|
.add_system(
|
|
|
|
prepare_prepass_textures
|
|
|
|
.in_set(RenderSet::Prepare)
|
|
|
|
.after(bevy_render::view::prepare_windows),
|
|
|
|
)
|
Migrate engine to Schedule v3 (#7267)
Huge thanks to @maniwani, @devil-ira, @hymm, @cart, @superdump and @jakobhellermann for the help with this PR.
# Objective
- Followup #6587.
- Minimal integration for the Stageless Scheduling RFC: https://github.com/bevyengine/rfcs/pull/45
## Solution
- [x] Remove old scheduling module
- [x] Migrate new methods to no longer use extension methods
- [x] Fix compiler errors
- [x] Fix benchmarks
- [x] Fix examples
- [x] Fix docs
- [x] Fix tests
## Changelog
### Added
- a large number of methods on `App` to work with schedules ergonomically
- the `CoreSchedule` enum
- `App::add_extract_system` via the `RenderingAppExtension` trait extension method
- the private `prepare_view_uniforms` system now has a public system set for scheduling purposes, called `ViewSet::PrepareUniforms`
### Removed
- stages, and all code that mentions stages
- states have been dramatically simplified, and no longer use a stack
- `RunCriteriaLabel`
- `AsSystemLabel` trait
- `on_hierarchy_reports_enabled` run criteria (now just uses an ad hoc resource checking run condition)
- systems in `RenderSet/Stage::Extract` no longer warn when they do not read data from the main world
- `RunCriteriaLabel`
- `transform_propagate_system_set`: this was a nonstandard pattern that didn't actually provide enough control. The systems are already `pub`: the docs have been updated to ensure that the third-party usage is clear.
### Changed
- `System::default_labels` is now `System::default_system_sets`.
- `App::add_default_labels` is now `App::add_default_sets`
- `CoreStage` and `StartupStage` enums are now `CoreSet` and `StartupSet`
- `App::add_system_set` was renamed to `App::add_systems`
- The `StartupSchedule` label is now defined as part of the `CoreSchedules` enum
- `.label(SystemLabel)` is now referred to as `.in_set(SystemSet)`
- `SystemLabel` trait was replaced by `SystemSet`
- `SystemTypeIdLabel<T>` was replaced by `SystemSetType<T>`
- The `ReportHierarchyIssue` resource now has a public constructor (`new`), and implements `PartialEq`
- Fixed time steps now use a schedule (`CoreSchedule::FixedTimeStep`) rather than a run criteria.
- Adding rendering extraction systems now panics rather than silently failing if no subapp with the `RenderApp` label is found.
- the `calculate_bounds` system, with the `CalculateBounds` label, is now in `CoreSet::Update`, rather than in `CoreSet::PostUpdate` before commands are applied.
- `SceneSpawnerSystem` now runs under `CoreSet::Update`, rather than `CoreStage::PreUpdate.at_end()`.
- `bevy_pbr::add_clusters` is no longer an exclusive system
- the top level `bevy_ecs::schedule` module was replaced with `bevy_ecs::scheduling`
- `tick_global_task_pools_on_main_thread` is no longer run as an exclusive system. Instead, it has been replaced by `tick_global_task_pools`, which uses a `NonSend` resource to force running on the main thread.
## Migration Guide
- Calls to `.label(MyLabel)` should be replaced with `.in_set(MySet)`
- Stages have been removed. Replace these with system sets, and then add command flushes using the `apply_system_buffers` exclusive system where needed.
- The `CoreStage`, `StartupStage, `RenderStage` and `AssetStage` enums have been replaced with `CoreSet`, `StartupSet, `RenderSet` and `AssetSet`. The same scheduling guarantees have been preserved.
- Systems are no longer added to `CoreSet::Update` by default. Add systems manually if this behavior is needed, although you should consider adding your game logic systems to `CoreSchedule::FixedTimestep` instead for more reliable framerate-independent behavior.
- Similarly, startup systems are no longer part of `StartupSet::Startup` by default. In most cases, this won't matter to you.
- For example, `add_system_to_stage(CoreStage::PostUpdate, my_system)` should be replaced with
- `add_system(my_system.in_set(CoreSet::PostUpdate)`
- When testing systems or otherwise running them in a headless fashion, simply construct and run a schedule using `Schedule::new()` and `World::run_schedule` rather than constructing stages
- Run criteria have been renamed to run conditions. These can now be combined with each other and with states.
- Looping run criteria and state stacks have been removed. Use an exclusive system that runs a schedule if you need this level of control over system control flow.
- For app-level control flow over which schedules get run when (such as for rollback networking), create your own schedule and insert it under the `CoreSchedule::Outer` label.
- Fixed timesteps are now evaluated in a schedule, rather than controlled via run criteria. The `run_fixed_timestep` system runs this schedule between `CoreSet::First` and `CoreSet::PreUpdate` by default.
- Command flush points introduced by `AssetStage` have been removed. If you were relying on these, add them back manually.
- Adding extract systems is now typically done directly on the main app. Make sure the `RenderingAppExtension` trait is in scope, then call `app.add_extract_system(my_system)`.
- the `calculate_bounds` system, with the `CalculateBounds` label, is now in `CoreSet::Update`, rather than in `CoreSet::PostUpdate` before commands are applied. You may need to order your movement systems to occur before this system in order to avoid system order ambiguities in culling behavior.
- the `RenderLabel` `AppLabel` was renamed to `RenderApp` for clarity
- `App::add_state` now takes 0 arguments: the starting state is set based on the `Default` impl.
- Instead of creating `SystemSet` containers for systems that run in stages, simply use `.on_enter::<State::Variant>()` or its `on_exit` or `on_update` siblings.
- `SystemLabel` derives should be replaced with `SystemSet`. You will also need to add the `Debug`, `PartialEq`, `Eq`, and `Hash` traits to satisfy the new trait bounds.
- `with_run_criteria` has been renamed to `run_if`. Run criteria have been renamed to run conditions for clarity, and should now simply return a bool.
- States have been dramatically simplified: there is no longer a "state stack". To queue a transition to the next state, call `NextState::set`
## TODO
- [x] remove dead methods on App and World
- [x] add `App::add_system_to_schedule` and `App::add_systems_to_schedule`
- [x] avoid adding the default system set at inappropriate times
- [x] remove any accidental cycles in the default plugins schedule
- [x] migrate benchmarks
- [x] expose explicit labels for the built-in command flush points
- [x] migrate engine code
- [x] remove all mentions of stages from the docs
- [x] verify docs for States
- [x] fix uses of exclusive systems that use .end / .at_start / .before_commands
- [x] migrate RenderStage and AssetStage
- [x] migrate examples
- [x] ensure that transform propagation is exported in a sufficiently public way (the systems are already pub)
- [x] ensure that on_enter schedules are run at least once before the main app
- [x] re-enable opt-in to execution order ambiguities
- [x] revert change to `update_bounds` to ensure it runs in `PostUpdate`
- [x] test all examples
- [x] unbreak directional lights
- [x] unbreak shadows (see 3d_scene, 3d_shape, lighting, transparaency_3d examples)
- [x] game menu example shows loading screen and menu simultaneously
- [x] display settings menu is a blank screen
- [x] `without_winit` example panics
- [x] ensure all tests pass
- [x] SubApp doc test fails
- [x] runs_spawn_local tasks fails
- [x] [Fix panic_when_hierachy_cycle test hanging](https://github.com/alice-i-cecile/bevy/pull/120)
## Points of Difficulty and Controversy
**Reviewers, please give feedback on these and look closely**
1. Default sets, from the RFC, have been removed. These added a tremendous amount of implicit complexity and result in hard to debug scheduling errors. They're going to be tackled in the form of "base sets" by @cart in a followup.
2. The outer schedule controls which schedule is run when `App::update` is called.
3. I implemented `Label for `Box<dyn Label>` for our label types. This enables us to store schedule labels in concrete form, and then later run them. I ran into the same set of problems when working with one-shot systems. We've previously investigated this pattern in depth, and it does not appear to lead to extra indirection with nested boxes.
4. `SubApp::update` simply runs the default schedule once. This sucks, but this whole API is incomplete and this was the minimal changeset.
5. `time_system` and `tick_global_task_pools_on_main_thread` no longer use exclusive systems to attempt to force scheduling order
6. Implemetnation strategy for fixed timesteps
7. `AssetStage` was migrated to `AssetSet` without reintroducing command flush points. These did not appear to be used, and it's nice to remove these bottlenecks.
8. Migration of `bevy_render/lib.rs` and pipelined rendering. The logic here is unusually tricky, as we have complex scheduling requirements.
## Future Work (ideally before 0.10)
- Rename schedule_v3 module to schedule or scheduling
- Add a derive macro to states, and likely a `EnumIter` trait of some form
- Figure out what exactly to do with the "systems added should basically work by default" problem
- Improve ergonomics for working with fixed timesteps and states
- Polish FixedTime API to match Time
- Rebase and merge #7415
- Resolve all internal ambiguities (blocked on better tools, especially #7442)
- Add "base sets" to replace the removed default sets.
2023-02-06 02:04:50 +00:00
|
|
|
.add_system(queue_prepass_view_bind_group::<M>.in_set(RenderSet::Queue))
|
|
|
|
.add_system(queue_prepass_material_meshes::<M>.in_set(RenderSet::Queue))
|
|
|
|
.add_system(sort_phase_system::<Opaque3dPrepass>.in_set(RenderSet::PhaseSort))
|
|
|
|
.add_system(sort_phase_system::<AlphaMask3dPrepass>.in_set(RenderSet::PhaseSort))
|
2023-01-19 22:11:13 +00:00
|
|
|
.init_resource::<PrepassPipeline<M>>()
|
|
|
|
.init_resource::<DrawFunctions<Opaque3dPrepass>>()
|
|
|
|
.init_resource::<DrawFunctions<AlphaMask3dPrepass>>()
|
|
|
|
.init_resource::<PrepassViewBindGroup>()
|
|
|
|
.init_resource::<SpecializedMeshPipelines<PrepassPipeline<M>>>()
|
|
|
|
.add_render_command::<Opaque3dPrepass, DrawPrepass<M>>()
|
|
|
|
.add_render_command::<AlphaMask3dPrepass, DrawPrepass<M>>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Resource)]
|
|
|
|
pub struct PrepassPipeline<M: Material> {
|
|
|
|
pub view_layout: BindGroupLayout,
|
|
|
|
pub mesh_layout: BindGroupLayout,
|
|
|
|
pub skinned_mesh_layout: BindGroupLayout,
|
|
|
|
pub material_layout: BindGroupLayout,
|
|
|
|
pub material_vertex_shader: Option<Handle<Shader>>,
|
|
|
|
pub material_fragment_shader: Option<Handle<Shader>>,
|
|
|
|
pub material_pipeline: MaterialPipeline<M>,
|
|
|
|
_marker: PhantomData<M>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<M: Material> FromWorld for PrepassPipeline<M> {
|
|
|
|
fn from_world(world: &mut World) -> Self {
|
|
|
|
let render_device = world.resource::<RenderDevice>();
|
|
|
|
let asset_server = world.resource::<AssetServer>();
|
|
|
|
|
|
|
|
let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
|
|
|
entries: &[
|
|
|
|
// View
|
|
|
|
BindGroupLayoutEntry {
|
|
|
|
binding: 0,
|
|
|
|
visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT,
|
|
|
|
ty: BindingType::Buffer {
|
|
|
|
ty: BufferBindingType::Uniform,
|
|
|
|
has_dynamic_offset: true,
|
|
|
|
min_binding_size: Some(ViewUniform::min_size()),
|
|
|
|
},
|
|
|
|
count: None,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
label: Some("prepass_view_layout"),
|
|
|
|
});
|
|
|
|
|
|
|
|
let mesh_pipeline = world.resource::<MeshPipeline>();
|
|
|
|
|
|
|
|
PrepassPipeline {
|
|
|
|
view_layout,
|
|
|
|
mesh_layout: mesh_pipeline.mesh_layout.clone(),
|
|
|
|
skinned_mesh_layout: mesh_pipeline.skinned_mesh_layout.clone(),
|
|
|
|
material_vertex_shader: match M::prepass_vertex_shader() {
|
|
|
|
ShaderRef::Default => None,
|
|
|
|
ShaderRef::Handle(handle) => Some(handle),
|
|
|
|
ShaderRef::Path(path) => Some(asset_server.load(path)),
|
|
|
|
},
|
|
|
|
material_fragment_shader: match M::prepass_fragment_shader() {
|
|
|
|
ShaderRef::Default => None,
|
|
|
|
ShaderRef::Handle(handle) => Some(handle),
|
|
|
|
ShaderRef::Path(path) => Some(asset_server.load(path)),
|
|
|
|
},
|
|
|
|
material_layout: M::bind_group_layout(render_device),
|
|
|
|
material_pipeline: world.resource::<MaterialPipeline<M>>().clone(),
|
|
|
|
_marker: PhantomData,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<M: Material> SpecializedMeshPipeline for PrepassPipeline<M>
|
|
|
|
where
|
|
|
|
M::Data: PartialEq + Eq + Hash + Clone,
|
|
|
|
{
|
|
|
|
type Key = MaterialPipelineKey<M>;
|
|
|
|
|
|
|
|
fn specialize(
|
|
|
|
&self,
|
|
|
|
key: Self::Key,
|
|
|
|
layout: &MeshVertexBufferLayout,
|
|
|
|
) -> Result<RenderPipelineDescriptor, SpecializedMeshPipelineError> {
|
|
|
|
let mut bind_group_layout = vec![self.view_layout.clone()];
|
|
|
|
let mut shader_defs = Vec::new();
|
|
|
|
let mut vertex_attributes = Vec::new();
|
|
|
|
|
|
|
|
// NOTE: Eventually, it would be nice to only add this when the shaders are overloaded by the Material.
|
|
|
|
// The main limitation right now is that bind group order is hardcoded in shaders.
|
|
|
|
bind_group_layout.insert(1, self.material_layout.clone());
|
|
|
|
|
|
|
|
if key.mesh_key.contains(MeshPipelineKey::DEPTH_PREPASS) {
|
|
|
|
shader_defs.push("DEPTH_PREPASS".into());
|
|
|
|
}
|
|
|
|
|
|
|
|
if key.mesh_key.contains(MeshPipelineKey::ALPHA_MASK) {
|
|
|
|
shader_defs.push("ALPHA_MASK".into());
|
|
|
|
}
|
|
|
|
|
2023-03-02 08:21:21 +00:00
|
|
|
let blend_key = key
|
|
|
|
.mesh_key
|
|
|
|
.intersection(MeshPipelineKey::BLEND_RESERVED_BITS);
|
|
|
|
if blend_key == MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA {
|
|
|
|
shader_defs.push("BLEND_PREMULTIPLIED_ALPHA".into());
|
|
|
|
}
|
|
|
|
|
2023-01-19 22:11:13 +00:00
|
|
|
if layout.contains(Mesh::ATTRIBUTE_POSITION) {
|
|
|
|
shader_defs.push("VERTEX_POSITIONS".into());
|
|
|
|
vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0));
|
|
|
|
}
|
|
|
|
|
|
|
|
shader_defs.push(ShaderDefVal::Int(
|
|
|
|
"MAX_DIRECTIONAL_LIGHTS".to_string(),
|
|
|
|
MAX_DIRECTIONAL_LIGHTS as i32,
|
|
|
|
));
|
2023-01-30 22:53:08 +00:00
|
|
|
shader_defs.push(ShaderDefVal::Int(
|
|
|
|
"MAX_CASCADES_PER_LIGHT".to_string(),
|
|
|
|
MAX_CASCADES_PER_LIGHT as i32,
|
|
|
|
));
|
2023-03-02 08:21:21 +00:00
|
|
|
if key.mesh_key.contains(MeshPipelineKey::DEPTH_CLAMP_ORTHO) {
|
|
|
|
shader_defs.push("DEPTH_CLAMP_ORTHO".into());
|
|
|
|
}
|
2023-01-19 22:11:13 +00:00
|
|
|
|
|
|
|
if layout.contains(Mesh::ATTRIBUTE_UV_0) {
|
|
|
|
shader_defs.push("VERTEX_UVS".into());
|
|
|
|
vertex_attributes.push(Mesh::ATTRIBUTE_UV_0.at_shader_location(1));
|
|
|
|
}
|
|
|
|
|
|
|
|
if key.mesh_key.contains(MeshPipelineKey::NORMAL_PREPASS) {
|
|
|
|
vertex_attributes.push(Mesh::ATTRIBUTE_NORMAL.at_shader_location(2));
|
|
|
|
shader_defs.push("NORMAL_PREPASS".into());
|
|
|
|
|
|
|
|
if layout.contains(Mesh::ATTRIBUTE_TANGENT) {
|
|
|
|
shader_defs.push("VERTEX_TANGENTS".into());
|
|
|
|
vertex_attributes.push(Mesh::ATTRIBUTE_TANGENT.at_shader_location(3));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if layout.contains(Mesh::ATTRIBUTE_JOINT_INDEX)
|
|
|
|
&& layout.contains(Mesh::ATTRIBUTE_JOINT_WEIGHT)
|
|
|
|
{
|
|
|
|
shader_defs.push("SKINNED".into());
|
|
|
|
vertex_attributes.push(Mesh::ATTRIBUTE_JOINT_INDEX.at_shader_location(4));
|
|
|
|
vertex_attributes.push(Mesh::ATTRIBUTE_JOINT_WEIGHT.at_shader_location(5));
|
|
|
|
bind_group_layout.insert(2, self.skinned_mesh_layout.clone());
|
|
|
|
} else {
|
|
|
|
bind_group_layout.insert(2, self.mesh_layout.clone());
|
|
|
|
}
|
|
|
|
|
|
|
|
let vertex_buffer_layout = layout.get_layout(&vertex_attributes)?;
|
|
|
|
|
2023-03-02 08:21:21 +00:00
|
|
|
// The fragment shader is only used when the normal prepass is enabled or the material uses alpha cutoff values
|
|
|
|
let fragment = if key
|
|
|
|
.mesh_key
|
|
|
|
.intersects(MeshPipelineKey::NORMAL_PREPASS | MeshPipelineKey::ALPHA_MASK)
|
|
|
|
|| blend_key == MeshPipelineKey::BLEND_PREMULTIPLIED_ALPHA
|
2023-01-19 22:11:13 +00:00
|
|
|
{
|
|
|
|
// Use the fragment shader from the material if present
|
|
|
|
let frag_shader_handle = if let Some(handle) = &self.material_fragment_shader {
|
|
|
|
handle.clone()
|
|
|
|
} else {
|
|
|
|
PREPASS_SHADER_HANDLE.typed::<Shader>()
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut targets = vec![];
|
|
|
|
// When the normal prepass is enabled we need a target to be able to write to it.
|
|
|
|
if key.mesh_key.contains(MeshPipelineKey::NORMAL_PREPASS) {
|
|
|
|
targets.push(Some(ColorTargetState {
|
|
|
|
format: TextureFormat::Rgb10a2Unorm,
|
|
|
|
blend: Some(BlendState::REPLACE),
|
|
|
|
write_mask: ColorWrites::ALL,
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
Some(FragmentState {
|
|
|
|
shader: frag_shader_handle,
|
|
|
|
entry_point: "fragment".into(),
|
|
|
|
shader_defs: shader_defs.clone(),
|
|
|
|
targets,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
|
|
|
// Use the vertex shader from the material if present
|
|
|
|
let vert_shader_handle = if let Some(handle) = &self.material_vertex_shader {
|
|
|
|
handle.clone()
|
|
|
|
} else {
|
|
|
|
PREPASS_SHADER_HANDLE.typed::<Shader>()
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut descriptor = RenderPipelineDescriptor {
|
|
|
|
vertex: VertexState {
|
|
|
|
shader: vert_shader_handle,
|
|
|
|
entry_point: "vertex".into(),
|
|
|
|
shader_defs,
|
|
|
|
buffers: vec![vertex_buffer_layout],
|
|
|
|
},
|
|
|
|
fragment,
|
2023-02-17 06:20:16 +00:00
|
|
|
layout: bind_group_layout,
|
2023-01-19 22:11:13 +00:00
|
|
|
primitive: PrimitiveState {
|
|
|
|
topology: key.mesh_key.primitive_topology(),
|
|
|
|
strip_index_format: None,
|
|
|
|
front_face: FrontFace::Ccw,
|
|
|
|
cull_mode: None,
|
|
|
|
unclipped_depth: false,
|
|
|
|
polygon_mode: PolygonMode::Fill,
|
|
|
|
conservative: false,
|
|
|
|
},
|
|
|
|
depth_stencil: Some(DepthStencilState {
|
|
|
|
format: DEPTH_PREPASS_FORMAT,
|
|
|
|
depth_write_enabled: true,
|
|
|
|
depth_compare: CompareFunction::GreaterEqual,
|
|
|
|
stencil: StencilState {
|
|
|
|
front: StencilFaceState::IGNORE,
|
|
|
|
back: StencilFaceState::IGNORE,
|
|
|
|
read_mask: 0,
|
|
|
|
write_mask: 0,
|
|
|
|
},
|
|
|
|
bias: DepthBiasState {
|
|
|
|
constant: 0,
|
|
|
|
slope_scale: 0.0,
|
|
|
|
clamp: 0.0,
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
multisample: MultisampleState {
|
|
|
|
count: key.mesh_key.msaa_samples(),
|
|
|
|
mask: !0,
|
|
|
|
alpha_to_coverage_enabled: false,
|
|
|
|
},
|
2023-02-17 06:20:16 +00:00
|
|
|
push_constant_ranges: Vec::new(),
|
2023-01-19 22:11:13 +00:00
|
|
|
label: Some("prepass_pipeline".into()),
|
|
|
|
};
|
|
|
|
|
|
|
|
// This is a bit risky because it's possible to change something that would
|
|
|
|
// break the prepass but be fine in the main pass.
|
|
|
|
// Since this api is pretty low-level it doesn't matter that much, but it is a potential issue.
|
|
|
|
M::specialize(&self.material_pipeline, &mut descriptor, layout, key)?;
|
|
|
|
|
|
|
|
Ok(descriptor)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-02 02:23:06 +00:00
|
|
|
pub fn get_bind_group_layout_entries(
|
|
|
|
bindings: [u32; 2],
|
|
|
|
multisampled: bool,
|
|
|
|
) -> [BindGroupLayoutEntry; 2] {
|
|
|
|
[
|
|
|
|
// Depth texture
|
|
|
|
BindGroupLayoutEntry {
|
|
|
|
binding: bindings[0],
|
|
|
|
visibility: ShaderStages::FRAGMENT,
|
|
|
|
ty: BindingType::Texture {
|
|
|
|
multisampled,
|
|
|
|
sample_type: TextureSampleType::Depth,
|
|
|
|
view_dimension: TextureViewDimension::D2,
|
|
|
|
},
|
|
|
|
count: None,
|
|
|
|
},
|
|
|
|
// Normal texture
|
|
|
|
BindGroupLayoutEntry {
|
|
|
|
binding: bindings[1],
|
|
|
|
visibility: ShaderStages::FRAGMENT,
|
|
|
|
ty: BindingType::Texture {
|
|
|
|
multisampled,
|
|
|
|
sample_type: TextureSampleType::Float { filterable: true },
|
|
|
|
view_dimension: TextureViewDimension::D2,
|
|
|
|
},
|
|
|
|
count: None,
|
|
|
|
},
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_bindings<'a>(
|
|
|
|
prepass_textures: Option<&'a ViewPrepassTextures>,
|
|
|
|
fallback_images: &'a mut FallbackImagesMsaa,
|
|
|
|
fallback_depths: &'a mut FallbackImagesDepth,
|
|
|
|
msaa: &'a Msaa,
|
|
|
|
bindings: [u32; 2],
|
|
|
|
) -> [BindGroupEntry<'a>; 2] {
|
|
|
|
let depth_view = match prepass_textures.and_then(|x| x.depth.as_ref()) {
|
|
|
|
Some(texture) => &texture.default_view,
|
|
|
|
None => {
|
|
|
|
&fallback_depths
|
|
|
|
.image_for_samplecount(msaa.samples())
|
|
|
|
.texture_view
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let normal_view = match prepass_textures.and_then(|x| x.normal.as_ref()) {
|
|
|
|
Some(texture) => &texture.default_view,
|
|
|
|
None => {
|
|
|
|
&fallback_images
|
|
|
|
.image_for_samplecount(msaa.samples())
|
|
|
|
.texture_view
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
[
|
|
|
|
BindGroupEntry {
|
|
|
|
binding: bindings[0],
|
|
|
|
resource: BindingResource::TextureView(depth_view),
|
|
|
|
},
|
|
|
|
BindGroupEntry {
|
|
|
|
binding: bindings[1],
|
|
|
|
resource: BindingResource::TextureView(normal_view),
|
|
|
|
},
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
2023-01-19 22:11:13 +00:00
|
|
|
// Extract the render phases for the prepass
|
|
|
|
pub fn extract_camera_prepass_phase(
|
|
|
|
mut commands: Commands,
|
|
|
|
cameras_3d: Extract<
|
|
|
|
Query<
|
|
|
|
(
|
|
|
|
Entity,
|
|
|
|
&Camera,
|
|
|
|
Option<&DepthPrepass>,
|
|
|
|
Option<&NormalPrepass>,
|
|
|
|
),
|
|
|
|
With<Camera3d>,
|
|
|
|
>,
|
|
|
|
>,
|
|
|
|
) {
|
|
|
|
for (entity, camera, depth_prepass, normal_prepass) in cameras_3d.iter() {
|
|
|
|
if !camera.is_active {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut entity = commands.get_or_spawn(entity);
|
|
|
|
if depth_prepass.is_some() || normal_prepass.is_some() {
|
|
|
|
entity.insert((
|
|
|
|
RenderPhase::<Opaque3dPrepass>::default(),
|
|
|
|
RenderPhase::<AlphaMask3dPrepass>::default(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
if depth_prepass.is_some() {
|
|
|
|
entity.insert(DepthPrepass);
|
|
|
|
}
|
|
|
|
if normal_prepass.is_some() {
|
|
|
|
entity.insert(NormalPrepass);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prepares the textures used by the prepass
|
|
|
|
pub fn prepare_prepass_textures(
|
|
|
|
mut commands: Commands,
|
|
|
|
mut texture_cache: ResMut<TextureCache>,
|
|
|
|
msaa: Res<Msaa>,
|
|
|
|
render_device: Res<RenderDevice>,
|
|
|
|
views_3d: Query<
|
|
|
|
(
|
|
|
|
Entity,
|
|
|
|
&ExtractedCamera,
|
|
|
|
Option<&DepthPrepass>,
|
|
|
|
Option<&NormalPrepass>,
|
|
|
|
),
|
|
|
|
(
|
|
|
|
With<RenderPhase<Opaque3dPrepass>>,
|
|
|
|
With<RenderPhase<AlphaMask3dPrepass>>,
|
|
|
|
),
|
|
|
|
>,
|
|
|
|
) {
|
|
|
|
let mut depth_textures = HashMap::default();
|
|
|
|
let mut normal_textures = HashMap::default();
|
|
|
|
for (entity, camera, depth_prepass, normal_prepass) in &views_3d {
|
|
|
|
let Some(physical_target_size) = camera.physical_target_size else {
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
|
|
|
let size = Extent3d {
|
|
|
|
depth_or_array_layers: 1,
|
|
|
|
width: physical_target_size.x,
|
|
|
|
height: physical_target_size.y,
|
|
|
|
};
|
|
|
|
|
|
|
|
let cached_depth_texture = depth_prepass.is_some().then(|| {
|
|
|
|
depth_textures
|
|
|
|
.entry(camera.target.clone())
|
|
|
|
.or_insert_with(|| {
|
|
|
|
let descriptor = TextureDescriptor {
|
|
|
|
label: Some("prepass_depth_texture"),
|
|
|
|
size,
|
|
|
|
mip_level_count: 1,
|
2023-01-20 14:25:21 +00:00
|
|
|
sample_count: msaa.samples(),
|
2023-01-19 22:11:13 +00:00
|
|
|
dimension: TextureDimension::D2,
|
|
|
|
format: DEPTH_PREPASS_FORMAT,
|
|
|
|
usage: TextureUsages::COPY_DST
|
|
|
|
| TextureUsages::RENDER_ATTACHMENT
|
|
|
|
| TextureUsages::TEXTURE_BINDING,
|
Wgpu 0.15 (#7356)
# Objective
Update Bevy to wgpu 0.15.
## Changelog
- Update to wgpu 0.15, wgpu-hal 0.15.1, and naga 0.11
- Users can now use the [DirectX Shader Compiler](https://github.com/microsoft/DirectXShaderCompiler) (DXC) on Windows with DX12 for faster shader compilation and ShaderModel 6.0+ support (requires `dxcompiler.dll` and `dxil.dll`, which are included in DXC downloads from [here](https://github.com/microsoft/DirectXShaderCompiler/releases/latest))
## Migration Guide
### WGSL Top-Level `let` is now `const`
All top level constants are now declared with `const`, catching up with the wgsl spec.
`let` is no longer allowed at the global scope, only within functions.
```diff
-let SOME_CONSTANT = 12.0;
+const SOME_CONSTANT = 12.0;
```
#### `TextureDescriptor` and `SurfaceConfiguration` now requires a `view_formats` field
The new `view_formats` field in the `TextureDescriptor` is used to specify a list of formats the texture can be re-interpreted to in a texture view. Currently only changing srgb-ness is allowed (ex. `Rgba8Unorm` <=> `Rgba8UnormSrgb`). You should set `view_formats` to `&[]` (empty) unless you have a specific reason not to.
#### The DirectX Shader Compiler (DXC) is now supported on DX12
DXC is now the default shader compiler when using the DX12 backend. DXC is Microsoft's replacement for their legacy FXC compiler, and is faster, less buggy, and allows for modern shader features to be used (ShaderModel 6.0+). DXC requires `dxcompiler.dll` and `dxil.dll` to be available, otherwise it will log a warning and fall back to FXC.
You can get `dxcompiler.dll` and `dxil.dll` by downloading the latest release from [Microsoft's DirectXShaderCompiler github repo](https://github.com/microsoft/DirectXShaderCompiler/releases/latest) and copying them into your project's root directory. These must be included when you distribute your Bevy game/app/etc if you plan on supporting the DX12 backend and are using DXC.
`WgpuSettings` now has a `dx12_shader_compiler` field which can be used to choose between either FXC or DXC (if you pass None for the paths for DXC, it will check for the .dlls in the working directory).
2023-01-29 20:27:30 +00:00
|
|
|
view_formats: &[],
|
2023-01-19 22:11:13 +00:00
|
|
|
};
|
|
|
|
texture_cache.get(&render_device, descriptor)
|
|
|
|
})
|
|
|
|
.clone()
|
|
|
|
});
|
|
|
|
|
|
|
|
let cached_normals_texture = normal_prepass.is_some().then(|| {
|
|
|
|
normal_textures
|
|
|
|
.entry(camera.target.clone())
|
|
|
|
.or_insert_with(|| {
|
|
|
|
texture_cache.get(
|
|
|
|
&render_device,
|
|
|
|
TextureDescriptor {
|
|
|
|
label: Some("prepass_normal_texture"),
|
|
|
|
size,
|
|
|
|
mip_level_count: 1,
|
2023-01-20 14:25:21 +00:00
|
|
|
sample_count: msaa.samples(),
|
2023-01-19 22:11:13 +00:00
|
|
|
dimension: TextureDimension::D2,
|
|
|
|
format: NORMAL_PREPASS_FORMAT,
|
|
|
|
usage: TextureUsages::RENDER_ATTACHMENT
|
|
|
|
| TextureUsages::TEXTURE_BINDING,
|
Wgpu 0.15 (#7356)
# Objective
Update Bevy to wgpu 0.15.
## Changelog
- Update to wgpu 0.15, wgpu-hal 0.15.1, and naga 0.11
- Users can now use the [DirectX Shader Compiler](https://github.com/microsoft/DirectXShaderCompiler) (DXC) on Windows with DX12 for faster shader compilation and ShaderModel 6.0+ support (requires `dxcompiler.dll` and `dxil.dll`, which are included in DXC downloads from [here](https://github.com/microsoft/DirectXShaderCompiler/releases/latest))
## Migration Guide
### WGSL Top-Level `let` is now `const`
All top level constants are now declared with `const`, catching up with the wgsl spec.
`let` is no longer allowed at the global scope, only within functions.
```diff
-let SOME_CONSTANT = 12.0;
+const SOME_CONSTANT = 12.0;
```
#### `TextureDescriptor` and `SurfaceConfiguration` now requires a `view_formats` field
The new `view_formats` field in the `TextureDescriptor` is used to specify a list of formats the texture can be re-interpreted to in a texture view. Currently only changing srgb-ness is allowed (ex. `Rgba8Unorm` <=> `Rgba8UnormSrgb`). You should set `view_formats` to `&[]` (empty) unless you have a specific reason not to.
#### The DirectX Shader Compiler (DXC) is now supported on DX12
DXC is now the default shader compiler when using the DX12 backend. DXC is Microsoft's replacement for their legacy FXC compiler, and is faster, less buggy, and allows for modern shader features to be used (ShaderModel 6.0+). DXC requires `dxcompiler.dll` and `dxil.dll` to be available, otherwise it will log a warning and fall back to FXC.
You can get `dxcompiler.dll` and `dxil.dll` by downloading the latest release from [Microsoft's DirectXShaderCompiler github repo](https://github.com/microsoft/DirectXShaderCompiler/releases/latest) and copying them into your project's root directory. These must be included when you distribute your Bevy game/app/etc if you plan on supporting the DX12 backend and are using DXC.
`WgpuSettings` now has a `dx12_shader_compiler` field which can be used to choose between either FXC or DXC (if you pass None for the paths for DXC, it will check for the .dlls in the working directory).
2023-01-29 20:27:30 +00:00
|
|
|
view_formats: &[],
|
2023-01-19 22:11:13 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.clone()
|
|
|
|
});
|
|
|
|
|
|
|
|
commands.entity(entity).insert(ViewPrepassTextures {
|
|
|
|
depth: cached_depth_texture,
|
|
|
|
normal: cached_normals_texture,
|
|
|
|
size,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Default, Resource)]
|
|
|
|
pub struct PrepassViewBindGroup {
|
|
|
|
bind_group: Option<BindGroup>,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn queue_prepass_view_bind_group<M: Material>(
|
|
|
|
render_device: Res<RenderDevice>,
|
|
|
|
prepass_pipeline: Res<PrepassPipeline<M>>,
|
|
|
|
view_uniforms: Res<ViewUniforms>,
|
|
|
|
mut prepass_view_bind_group: ResMut<PrepassViewBindGroup>,
|
|
|
|
) {
|
|
|
|
if let Some(view_binding) = view_uniforms.uniforms.binding() {
|
|
|
|
prepass_view_bind_group.bind_group =
|
|
|
|
Some(render_device.create_bind_group(&BindGroupDescriptor {
|
|
|
|
entries: &[BindGroupEntry {
|
|
|
|
binding: 0,
|
|
|
|
resource: view_binding,
|
|
|
|
}],
|
|
|
|
label: Some("prepass_view_bind_group"),
|
|
|
|
layout: &prepass_pipeline.view_layout,
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(clippy::too_many_arguments)]
|
|
|
|
pub fn queue_prepass_material_meshes<M: Material>(
|
|
|
|
opaque_draw_functions: Res<DrawFunctions<Opaque3dPrepass>>,
|
|
|
|
alpha_mask_draw_functions: Res<DrawFunctions<AlphaMask3dPrepass>>,
|
|
|
|
prepass_pipeline: Res<PrepassPipeline<M>>,
|
|
|
|
mut pipelines: ResMut<SpecializedMeshPipelines<PrepassPipeline<M>>>,
|
|
|
|
pipeline_cache: Res<PipelineCache>,
|
|
|
|
msaa: Res<Msaa>,
|
|
|
|
render_meshes: Res<RenderAssets<Mesh>>,
|
|
|
|
render_materials: Res<RenderMaterials<M>>,
|
|
|
|
material_meshes: Query<(&Handle<M>, &Handle<Mesh>, &MeshUniform)>,
|
|
|
|
mut views: Query<(
|
|
|
|
&ExtractedView,
|
|
|
|
&VisibleEntities,
|
|
|
|
&mut RenderPhase<Opaque3dPrepass>,
|
|
|
|
&mut RenderPhase<AlphaMask3dPrepass>,
|
|
|
|
Option<&DepthPrepass>,
|
|
|
|
Option<&NormalPrepass>,
|
|
|
|
)>,
|
|
|
|
) where
|
|
|
|
M::Data: PartialEq + Eq + Hash + Clone,
|
|
|
|
{
|
|
|
|
let opaque_draw_prepass = opaque_draw_functions
|
|
|
|
.read()
|
|
|
|
.get_id::<DrawPrepass<M>>()
|
|
|
|
.unwrap();
|
|
|
|
let alpha_mask_draw_prepass = alpha_mask_draw_functions
|
|
|
|
.read()
|
|
|
|
.get_id::<DrawPrepass<M>>()
|
|
|
|
.unwrap();
|
|
|
|
for (
|
|
|
|
view,
|
|
|
|
visible_entities,
|
|
|
|
mut opaque_phase,
|
|
|
|
mut alpha_mask_phase,
|
|
|
|
depth_prepass,
|
|
|
|
normal_prepass,
|
|
|
|
) in &mut views
|
|
|
|
{
|
2023-01-20 14:25:21 +00:00
|
|
|
let mut view_key = MeshPipelineKey::from_msaa_samples(msaa.samples());
|
2023-01-19 22:11:13 +00:00
|
|
|
if depth_prepass.is_some() {
|
|
|
|
view_key |= MeshPipelineKey::DEPTH_PREPASS;
|
|
|
|
}
|
|
|
|
if normal_prepass.is_some() {
|
|
|
|
view_key |= MeshPipelineKey::NORMAL_PREPASS;
|
|
|
|
}
|
|
|
|
|
|
|
|
let rangefinder = view.rangefinder3d();
|
|
|
|
|
|
|
|
for visible_entity in &visible_entities.entities {
|
|
|
|
let Ok((material_handle, mesh_handle, mesh_uniform)) = material_meshes.get(*visible_entity) else {
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
|
|
|
let (Some(material), Some(mesh)) = (
|
|
|
|
render_materials.get(material_handle),
|
|
|
|
render_meshes.get(mesh_handle),
|
|
|
|
) else {
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut mesh_key =
|
|
|
|
MeshPipelineKey::from_primitive_topology(mesh.primitive_topology) | view_key;
|
|
|
|
let alpha_mode = material.properties.alpha_mode;
|
|
|
|
match alpha_mode {
|
|
|
|
AlphaMode::Opaque => {}
|
|
|
|
AlphaMode::Mask(_) => mesh_key |= MeshPipelineKey::ALPHA_MASK,
|
2023-01-21 21:46:53 +00:00
|
|
|
AlphaMode::Blend
|
|
|
|
| AlphaMode::Premultiplied
|
|
|
|
| AlphaMode::Add
|
|
|
|
| AlphaMode::Multiply => continue,
|
2023-01-19 22:11:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let pipeline_id = pipelines.specialize(
|
|
|
|
&pipeline_cache,
|
|
|
|
&prepass_pipeline,
|
|
|
|
MaterialPipelineKey {
|
|
|
|
mesh_key,
|
|
|
|
bind_group_data: material.key.clone(),
|
|
|
|
},
|
|
|
|
&mesh.layout,
|
|
|
|
);
|
|
|
|
let pipeline_id = match pipeline_id {
|
|
|
|
Ok(id) => id,
|
|
|
|
Err(err) => {
|
|
|
|
error!("{}", err);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let distance =
|
|
|
|
rangefinder.distance(&mesh_uniform.transform) + material.properties.depth_bias;
|
|
|
|
match alpha_mode {
|
|
|
|
AlphaMode::Opaque => {
|
|
|
|
opaque_phase.add(Opaque3dPrepass {
|
|
|
|
entity: *visible_entity,
|
|
|
|
draw_function: opaque_draw_prepass,
|
|
|
|
pipeline_id,
|
|
|
|
distance,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
AlphaMode::Mask(_) => {
|
|
|
|
alpha_mask_phase.add(AlphaMask3dPrepass {
|
|
|
|
entity: *visible_entity,
|
|
|
|
draw_function: alpha_mask_draw_prepass,
|
|
|
|
pipeline_id,
|
|
|
|
distance,
|
|
|
|
});
|
|
|
|
}
|
2023-01-21 21:46:53 +00:00
|
|
|
AlphaMode::Blend
|
|
|
|
| AlphaMode::Premultiplied
|
|
|
|
| AlphaMode::Add
|
|
|
|
| AlphaMode::Multiply => {}
|
2023-01-19 22:11:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct SetPrepassViewBindGroup<const I: usize>;
|
|
|
|
impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetPrepassViewBindGroup<I> {
|
|
|
|
type Param = SRes<PrepassViewBindGroup>;
|
|
|
|
type ViewWorldQuery = Read<ViewUniformOffset>;
|
|
|
|
type ItemWorldQuery = ();
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn render<'w>(
|
|
|
|
_item: &P,
|
|
|
|
view_uniform_offset: &'_ ViewUniformOffset,
|
|
|
|
_entity: (),
|
|
|
|
prepass_view_bind_group: SystemParamItem<'w, '_, Self::Param>,
|
|
|
|
pass: &mut TrackedRenderPass<'w>,
|
|
|
|
) -> RenderCommandResult {
|
|
|
|
let prepass_view_bind_group = prepass_view_bind_group.into_inner();
|
|
|
|
pass.set_bind_group(
|
|
|
|
I,
|
|
|
|
prepass_view_bind_group.bind_group.as_ref().unwrap(),
|
|
|
|
&[view_uniform_offset.offset],
|
|
|
|
);
|
|
|
|
RenderCommandResult::Success
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub type DrawPrepass<M> = (
|
|
|
|
SetItemPipeline,
|
|
|
|
SetPrepassViewBindGroup<0>,
|
|
|
|
SetMaterialBindGroup<M, 1>,
|
|
|
|
SetMeshBindGroup<2>,
|
|
|
|
DrawMesh,
|
|
|
|
);
|