2023-10-13 17:06:53 +00:00
|
|
|
//! Convenience logic for turning components from the main world into extracted
|
2023-10-08 10:34:44 +00:00
|
|
|
//! instances in the render world.
|
|
|
|
//!
|
|
|
|
//! This is essentially the same as the `extract_component` module, but
|
|
|
|
//! higher-performance because it avoids the ECS overhead.
|
|
|
|
|
|
|
|
use std::marker::PhantomData;
|
|
|
|
|
|
|
|
use bevy_app::{App, Plugin};
|
|
|
|
use bevy_asset::{Asset, AssetId, Handle};
|
|
|
|
use bevy_derive::{Deref, DerefMut};
|
|
|
|
use bevy_ecs::{
|
|
|
|
prelude::Entity,
|
Rename `WorldQueryData` & `WorldQueryFilter` to `QueryData` & `QueryFilter` (#10779)
# Rename `WorldQueryData` & `WorldQueryFilter` to `QueryData` &
`QueryFilter`
Fixes #10776
## Solution
Traits `WorldQueryData` & `WorldQueryFilter` were renamed to `QueryData`
and `QueryFilter`, respectively. Related Trait types were also renamed.
---
## Changelog
- Trait `WorldQueryData` has been renamed to `QueryData`. Derive macro's
`QueryData` attribute `world_query_data` has been renamed to
`query_data`.
- Trait `WorldQueryFilter` has been renamed to `QueryFilter`. Derive
macro's `QueryFilter` attribute `world_query_filter` has been renamed to
`query_filter`.
- Trait's `ExtractComponent` type `Query` has been renamed to `Data`.
- Trait's `GetBatchData` types `Query` & `QueryFilter` has been renamed
to `Data` & `Filter`, respectively.
- Trait's `ExtractInstance` type `Query` has been renamed to `Data`.
- Trait's `ViewNode` type `ViewQuery` has been renamed to `ViewData`.
- Trait's `RenderCommand` types `ViewWorldQuery` & `ItemWorldQuery` has
been renamed to `ViewData` & `ItemData`, respectively.
## Migration Guide
Note: if merged before 0.13 is released, this should instead modify the
migration guide of #10776 with the updated names.
- Rename `WorldQueryData` & `WorldQueryFilter` trait usages to
`QueryData` & `QueryFilter` and their respective derive macro attributes
`world_query_data` & `world_query_filter` to `query_data` &
`query_filter`.
- Rename the following trait type usages:
- Trait's `ExtractComponent` type `Query` to `Data`.
- Trait's `GetBatchData` type `Query` to `Data`.
- Trait's `ExtractInstance` type `Query` to `Data`.
- Trait's `ViewNode` type `ViewQuery` to `ViewData`'
- Trait's `RenderCommand` types `ViewWolrdQuery` & `ItemWorldQuery` to
`ViewData` & `ItemData`, respectively.
```rust
// Before
#[derive(WorldQueryData)]
#[world_query_data(derive(Debug))]
struct EmptyQuery {
empty: (),
}
// After
#[derive(QueryData)]
#[query_data(derive(Debug))]
struct EmptyQuery {
empty: (),
}
// Before
#[derive(WorldQueryFilter)]
struct CustomQueryFilter<T: Component, P: Component> {
_c: With<ComponentC>,
_d: With<ComponentD>,
_or: Or<(Added<ComponentC>, Changed<ComponentD>, Without<ComponentZ>)>,
_generic_tuple: (With<T>, With<P>),
}
// After
#[derive(QueryFilter)]
struct CustomQueryFilter<T: Component, P: Component> {
_c: With<ComponentC>,
_d: With<ComponentD>,
_or: Or<(Added<ComponentC>, Changed<ComponentD>, Without<ComponentZ>)>,
_generic_tuple: (With<T>, With<P>),
}
// Before
impl ExtractComponent for ContrastAdaptiveSharpeningSettings {
type Query = &'static Self;
type Filter = With<Camera>;
type Out = (DenoiseCAS, CASUniform);
fn extract_component(item: QueryItem<Self::Query>) -> Option<Self::Out> {
//...
}
}
// After
impl ExtractComponent for ContrastAdaptiveSharpeningSettings {
type Data = &'static Self;
type Filter = With<Camera>;
type Out = (DenoiseCAS, CASUniform);
fn extract_component(item: QueryItem<Self::Data>) -> Option<Self::Out> {
//...
}
}
// Before
impl GetBatchData for MeshPipeline {
type Param = SRes<RenderMeshInstances>;
type Query = Entity;
type QueryFilter = With<Mesh3d>;
type CompareData = (MaterialBindGroupId, AssetId<Mesh>);
type BufferData = MeshUniform;
fn get_batch_data(
mesh_instances: &SystemParamItem<Self::Param>,
entity: &QueryItem<Self::Query>,
) -> (Self::BufferData, Option<Self::CompareData>) {
// ....
}
}
// After
impl GetBatchData for MeshPipeline {
type Param = SRes<RenderMeshInstances>;
type Data = Entity;
type Filter = With<Mesh3d>;
type CompareData = (MaterialBindGroupId, AssetId<Mesh>);
type BufferData = MeshUniform;
fn get_batch_data(
mesh_instances: &SystemParamItem<Self::Param>,
entity: &QueryItem<Self::Data>,
) -> (Self::BufferData, Option<Self::CompareData>) {
// ....
}
}
// Before
impl<A> ExtractInstance for AssetId<A>
where
A: Asset,
{
type Query = Read<Handle<A>>;
type Filter = ();
fn extract(item: QueryItem<'_, Self::Query>) -> Option<Self> {
Some(item.id())
}
}
// After
impl<A> ExtractInstance for AssetId<A>
where
A: Asset,
{
type Data = Read<Handle<A>>;
type Filter = ();
fn extract(item: QueryItem<'_, Self::Data>) -> Option<Self> {
Some(item.id())
}
}
// Before
impl ViewNode for PostProcessNode {
type ViewQuery = (
&'static ViewTarget,
&'static PostProcessSettings,
);
fn run(
&self,
_graph: &mut RenderGraphContext,
render_context: &mut RenderContext,
(view_target, _post_process_settings): QueryItem<Self::ViewQuery>,
world: &World,
) -> Result<(), NodeRunError> {
// ...
}
}
// After
impl ViewNode for PostProcessNode {
type ViewData = (
&'static ViewTarget,
&'static PostProcessSettings,
);
fn run(
&self,
_graph: &mut RenderGraphContext,
render_context: &mut RenderContext,
(view_target, _post_process_settings): QueryItem<Self::ViewData>,
world: &World,
) -> Result<(), NodeRunError> {
// ...
}
}
// Before
impl<P: CachedRenderPipelinePhaseItem> RenderCommand<P> for SetItemPipeline {
type Param = SRes<PipelineCache>;
type ViewWorldQuery = ();
type ItemWorldQuery = ();
#[inline]
fn render<'w>(
item: &P,
_view: (),
_entity: (),
pipeline_cache: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult {
// ...
}
}
// After
impl<P: CachedRenderPipelinePhaseItem> RenderCommand<P> for SetItemPipeline {
type Param = SRes<PipelineCache>;
type ViewData = ();
type ItemData = ();
#[inline]
fn render<'w>(
item: &P,
_view: (),
_entity: (),
pipeline_cache: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult {
// ...
}
}
```
2023-12-12 19:45:50 +00:00
|
|
|
query::{QueryFilter, QueryItem, ReadOnlyQueryData},
|
2023-10-08 10:34:44 +00:00
|
|
|
system::{lifetimeless::Read, Query, ResMut, Resource},
|
|
|
|
};
|
|
|
|
use bevy_utils::EntityHashMap;
|
|
|
|
|
|
|
|
use crate::{prelude::ViewVisibility, Extract, ExtractSchedule, RenderApp};
|
|
|
|
|
|
|
|
/// Describes how to extract data needed for rendering from a component or
|
|
|
|
/// components.
|
|
|
|
///
|
|
|
|
/// Before rendering, any applicable components will be transferred from the
|
|
|
|
/// main world to the render world in the [`ExtractSchedule`] step.
|
|
|
|
///
|
|
|
|
/// This is essentially the same as
|
|
|
|
/// [`ExtractComponent`](crate::extract_component::ExtractComponent), but
|
|
|
|
/// higher-performance because it avoids the ECS overhead.
|
2023-10-13 17:06:53 +00:00
|
|
|
pub trait ExtractInstance: Send + Sync + Sized + 'static {
|
Rename `WorldQueryData` & `WorldQueryFilter` to `QueryData` & `QueryFilter` (#10779)
# Rename `WorldQueryData` & `WorldQueryFilter` to `QueryData` &
`QueryFilter`
Fixes #10776
## Solution
Traits `WorldQueryData` & `WorldQueryFilter` were renamed to `QueryData`
and `QueryFilter`, respectively. Related Trait types were also renamed.
---
## Changelog
- Trait `WorldQueryData` has been renamed to `QueryData`. Derive macro's
`QueryData` attribute `world_query_data` has been renamed to
`query_data`.
- Trait `WorldQueryFilter` has been renamed to `QueryFilter`. Derive
macro's `QueryFilter` attribute `world_query_filter` has been renamed to
`query_filter`.
- Trait's `ExtractComponent` type `Query` has been renamed to `Data`.
- Trait's `GetBatchData` types `Query` & `QueryFilter` has been renamed
to `Data` & `Filter`, respectively.
- Trait's `ExtractInstance` type `Query` has been renamed to `Data`.
- Trait's `ViewNode` type `ViewQuery` has been renamed to `ViewData`.
- Trait's `RenderCommand` types `ViewWorldQuery` & `ItemWorldQuery` has
been renamed to `ViewData` & `ItemData`, respectively.
## Migration Guide
Note: if merged before 0.13 is released, this should instead modify the
migration guide of #10776 with the updated names.
- Rename `WorldQueryData` & `WorldQueryFilter` trait usages to
`QueryData` & `QueryFilter` and their respective derive macro attributes
`world_query_data` & `world_query_filter` to `query_data` &
`query_filter`.
- Rename the following trait type usages:
- Trait's `ExtractComponent` type `Query` to `Data`.
- Trait's `GetBatchData` type `Query` to `Data`.
- Trait's `ExtractInstance` type `Query` to `Data`.
- Trait's `ViewNode` type `ViewQuery` to `ViewData`'
- Trait's `RenderCommand` types `ViewWolrdQuery` & `ItemWorldQuery` to
`ViewData` & `ItemData`, respectively.
```rust
// Before
#[derive(WorldQueryData)]
#[world_query_data(derive(Debug))]
struct EmptyQuery {
empty: (),
}
// After
#[derive(QueryData)]
#[query_data(derive(Debug))]
struct EmptyQuery {
empty: (),
}
// Before
#[derive(WorldQueryFilter)]
struct CustomQueryFilter<T: Component, P: Component> {
_c: With<ComponentC>,
_d: With<ComponentD>,
_or: Or<(Added<ComponentC>, Changed<ComponentD>, Without<ComponentZ>)>,
_generic_tuple: (With<T>, With<P>),
}
// After
#[derive(QueryFilter)]
struct CustomQueryFilter<T: Component, P: Component> {
_c: With<ComponentC>,
_d: With<ComponentD>,
_or: Or<(Added<ComponentC>, Changed<ComponentD>, Without<ComponentZ>)>,
_generic_tuple: (With<T>, With<P>),
}
// Before
impl ExtractComponent for ContrastAdaptiveSharpeningSettings {
type Query = &'static Self;
type Filter = With<Camera>;
type Out = (DenoiseCAS, CASUniform);
fn extract_component(item: QueryItem<Self::Query>) -> Option<Self::Out> {
//...
}
}
// After
impl ExtractComponent for ContrastAdaptiveSharpeningSettings {
type Data = &'static Self;
type Filter = With<Camera>;
type Out = (DenoiseCAS, CASUniform);
fn extract_component(item: QueryItem<Self::Data>) -> Option<Self::Out> {
//...
}
}
// Before
impl GetBatchData for MeshPipeline {
type Param = SRes<RenderMeshInstances>;
type Query = Entity;
type QueryFilter = With<Mesh3d>;
type CompareData = (MaterialBindGroupId, AssetId<Mesh>);
type BufferData = MeshUniform;
fn get_batch_data(
mesh_instances: &SystemParamItem<Self::Param>,
entity: &QueryItem<Self::Query>,
) -> (Self::BufferData, Option<Self::CompareData>) {
// ....
}
}
// After
impl GetBatchData for MeshPipeline {
type Param = SRes<RenderMeshInstances>;
type Data = Entity;
type Filter = With<Mesh3d>;
type CompareData = (MaterialBindGroupId, AssetId<Mesh>);
type BufferData = MeshUniform;
fn get_batch_data(
mesh_instances: &SystemParamItem<Self::Param>,
entity: &QueryItem<Self::Data>,
) -> (Self::BufferData, Option<Self::CompareData>) {
// ....
}
}
// Before
impl<A> ExtractInstance for AssetId<A>
where
A: Asset,
{
type Query = Read<Handle<A>>;
type Filter = ();
fn extract(item: QueryItem<'_, Self::Query>) -> Option<Self> {
Some(item.id())
}
}
// After
impl<A> ExtractInstance for AssetId<A>
where
A: Asset,
{
type Data = Read<Handle<A>>;
type Filter = ();
fn extract(item: QueryItem<'_, Self::Data>) -> Option<Self> {
Some(item.id())
}
}
// Before
impl ViewNode for PostProcessNode {
type ViewQuery = (
&'static ViewTarget,
&'static PostProcessSettings,
);
fn run(
&self,
_graph: &mut RenderGraphContext,
render_context: &mut RenderContext,
(view_target, _post_process_settings): QueryItem<Self::ViewQuery>,
world: &World,
) -> Result<(), NodeRunError> {
// ...
}
}
// After
impl ViewNode for PostProcessNode {
type ViewData = (
&'static ViewTarget,
&'static PostProcessSettings,
);
fn run(
&self,
_graph: &mut RenderGraphContext,
render_context: &mut RenderContext,
(view_target, _post_process_settings): QueryItem<Self::ViewData>,
world: &World,
) -> Result<(), NodeRunError> {
// ...
}
}
// Before
impl<P: CachedRenderPipelinePhaseItem> RenderCommand<P> for SetItemPipeline {
type Param = SRes<PipelineCache>;
type ViewWorldQuery = ();
type ItemWorldQuery = ();
#[inline]
fn render<'w>(
item: &P,
_view: (),
_entity: (),
pipeline_cache: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult {
// ...
}
}
// After
impl<P: CachedRenderPipelinePhaseItem> RenderCommand<P> for SetItemPipeline {
type Param = SRes<PipelineCache>;
type ViewData = ();
type ItemData = ();
#[inline]
fn render<'w>(
item: &P,
_view: (),
_entity: (),
pipeline_cache: SystemParamItem<'w, '_, Self::Param>,
pass: &mut TrackedRenderPass<'w>,
) -> RenderCommandResult {
// ...
}
}
```
2023-12-12 19:45:50 +00:00
|
|
|
/// ECS [`ReadOnlyQueryData`] to fetch the components to extract.
|
2024-01-22 15:01:55 +00:00
|
|
|
type QueryData: ReadOnlyQueryData;
|
2023-10-08 10:34:44 +00:00
|
|
|
/// Filters the entities with additional constraints.
|
2024-01-22 15:01:55 +00:00
|
|
|
type QueryFilter: QueryFilter;
|
2023-10-08 10:34:44 +00:00
|
|
|
|
|
|
|
/// Defines how the component is transferred into the "render world".
|
2024-01-22 15:01:55 +00:00
|
|
|
fn extract(item: QueryItem<'_, Self::QueryData>) -> Option<Self>;
|
2023-10-08 10:34:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// This plugin extracts one or more components into the "render world" as
|
2023-10-13 17:06:53 +00:00
|
|
|
/// extracted instances.
|
2023-10-08 10:34:44 +00:00
|
|
|
///
|
|
|
|
/// Therefore it sets up the [`ExtractSchedule`] step for the specified
|
2023-10-13 17:06:53 +00:00
|
|
|
/// [`ExtractedInstances`].
|
2023-10-08 10:34:44 +00:00
|
|
|
#[derive(Default)]
|
2023-10-13 17:06:53 +00:00
|
|
|
pub struct ExtractInstancesPlugin<EI>
|
2023-10-08 10:34:44 +00:00
|
|
|
where
|
2023-10-13 17:06:53 +00:00
|
|
|
EI: ExtractInstance,
|
2023-10-08 10:34:44 +00:00
|
|
|
{
|
|
|
|
only_extract_visible: bool,
|
2023-10-13 17:06:53 +00:00
|
|
|
marker: PhantomData<fn() -> EI>,
|
2023-10-08 10:34:44 +00:00
|
|
|
}
|
|
|
|
|
2023-10-13 17:06:53 +00:00
|
|
|
/// Stores all extract instances of a type in the render world.
|
2023-10-08 10:34:44 +00:00
|
|
|
#[derive(Resource, Deref, DerefMut)]
|
2023-10-13 17:06:53 +00:00
|
|
|
pub struct ExtractedInstances<EI>(EntityHashMap<Entity, EI>)
|
2023-10-08 10:34:44 +00:00
|
|
|
where
|
2023-10-13 17:06:53 +00:00
|
|
|
EI: ExtractInstance;
|
2023-10-08 10:34:44 +00:00
|
|
|
|
2023-10-13 17:06:53 +00:00
|
|
|
impl<EI> Default for ExtractedInstances<EI>
|
2023-10-08 10:34:44 +00:00
|
|
|
where
|
2023-10-13 17:06:53 +00:00
|
|
|
EI: ExtractInstance,
|
2023-10-08 10:34:44 +00:00
|
|
|
{
|
|
|
|
fn default() -> Self {
|
|
|
|
Self(Default::default())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-13 17:06:53 +00:00
|
|
|
impl<EI> ExtractInstancesPlugin<EI>
|
2023-10-08 10:34:44 +00:00
|
|
|
where
|
2023-10-13 17:06:53 +00:00
|
|
|
EI: ExtractInstance,
|
2023-10-08 10:34:44 +00:00
|
|
|
{
|
2023-10-13 17:06:53 +00:00
|
|
|
/// Creates a new [`ExtractInstancesPlugin`] that unconditionally extracts to
|
2023-10-08 10:34:44 +00:00
|
|
|
/// the render world, whether the entity is visible or not.
|
|
|
|
pub fn new() -> Self {
|
|
|
|
Self {
|
|
|
|
only_extract_visible: false,
|
|
|
|
marker: PhantomData,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-13 17:06:53 +00:00
|
|
|
/// Creates a new [`ExtractInstancesPlugin`] that extracts to the render world
|
2023-10-08 10:34:44 +00:00
|
|
|
/// if and only if the entity it's attached to is visible.
|
|
|
|
pub fn extract_visible() -> Self {
|
|
|
|
Self {
|
|
|
|
only_extract_visible: true,
|
|
|
|
marker: PhantomData,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-13 17:06:53 +00:00
|
|
|
impl<EI> Plugin for ExtractInstancesPlugin<EI>
|
2023-10-08 10:34:44 +00:00
|
|
|
where
|
2023-10-13 17:06:53 +00:00
|
|
|
EI: ExtractInstance,
|
2023-10-08 10:34:44 +00:00
|
|
|
{
|
|
|
|
fn build(&self, app: &mut App) {
|
|
|
|
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
2023-10-13 17:06:53 +00:00
|
|
|
render_app.init_resource::<ExtractedInstances<EI>>();
|
2023-10-08 10:34:44 +00:00
|
|
|
if self.only_extract_visible {
|
2023-10-13 17:06:53 +00:00
|
|
|
render_app.add_systems(ExtractSchedule, extract_visible::<EI>);
|
2023-10-08 10:34:44 +00:00
|
|
|
} else {
|
2023-10-13 17:06:53 +00:00
|
|
|
render_app.add_systems(ExtractSchedule, extract_all::<EI>);
|
2023-10-08 10:34:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-13 17:06:53 +00:00
|
|
|
fn extract_all<EI>(
|
|
|
|
mut extracted_instances: ResMut<ExtractedInstances<EI>>,
|
2024-01-22 15:01:55 +00:00
|
|
|
query: Extract<Query<(Entity, EI::QueryData), EI::QueryFilter>>,
|
2023-10-08 10:34:44 +00:00
|
|
|
) where
|
2023-10-13 17:06:53 +00:00
|
|
|
EI: ExtractInstance,
|
2023-10-08 10:34:44 +00:00
|
|
|
{
|
2023-10-13 17:06:53 +00:00
|
|
|
extracted_instances.clear();
|
2023-10-08 10:34:44 +00:00
|
|
|
for (entity, other) in &query {
|
2023-10-13 17:06:53 +00:00
|
|
|
if let Some(extract_instance) = EI::extract(other) {
|
|
|
|
extracted_instances.insert(entity, extract_instance);
|
2023-10-08 10:34:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-13 17:06:53 +00:00
|
|
|
fn extract_visible<EI>(
|
|
|
|
mut extracted_instances: ResMut<ExtractedInstances<EI>>,
|
2024-01-22 15:01:55 +00:00
|
|
|
query: Extract<Query<(Entity, &ViewVisibility, EI::QueryData), EI::QueryFilter>>,
|
2023-10-08 10:34:44 +00:00
|
|
|
) where
|
2023-10-13 17:06:53 +00:00
|
|
|
EI: ExtractInstance,
|
2023-10-08 10:34:44 +00:00
|
|
|
{
|
2023-10-13 17:06:53 +00:00
|
|
|
extracted_instances.clear();
|
2023-10-08 10:34:44 +00:00
|
|
|
for (entity, view_visibility, other) in &query {
|
|
|
|
if view_visibility.get() {
|
2023-10-13 17:06:53 +00:00
|
|
|
if let Some(extract_instance) = EI::extract(other) {
|
|
|
|
extracted_instances.insert(entity, extract_instance);
|
2023-10-08 10:34:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-13 17:06:53 +00:00
|
|
|
impl<A> ExtractInstance for AssetId<A>
|
2023-10-08 10:34:44 +00:00
|
|
|
where
|
|
|
|
A: Asset,
|
|
|
|
{
|
2024-01-22 15:01:55 +00:00
|
|
|
type QueryData = Read<Handle<A>>;
|
|
|
|
type QueryFilter = ();
|
2023-10-08 10:34:44 +00:00
|
|
|
|
2024-01-22 15:01:55 +00:00
|
|
|
fn extract(item: QueryItem<'_, Self::QueryData>) -> Option<Self> {
|
2023-10-08 10:34:44 +00:00
|
|
|
Some(item.id())
|
|
|
|
}
|
|
|
|
}
|