Path: blob/main/crates/bevy_render/src/extract_component.rs
9299 views
use crate::{1render_resource::{encase::internal::WriteInto, DynamicUniformBuffer, ShaderType},2renderer::{RenderDevice, RenderQueue},3sync_component::{SyncComponent, SyncComponentPlugin},4sync_world::RenderEntity,5Extract, ExtractSchedule, Render, RenderApp, RenderSystems,6};7use bevy_app::{App, Plugin};8use bevy_camera::visibility::ViewVisibility;9use bevy_ecs::{10component::Component,11prelude::*,12query::{QueryFilter, QueryItem, ReadOnlyQueryData},13};14use core::{marker::PhantomData, ops::Deref};1516pub use bevy_render_macros::ExtractComponent;1718/// Stores the index of a uniform inside of [`ComponentUniforms`].19#[derive(Component)]20pub struct DynamicUniformIndex<C: Component> {21index: u32,22marker: PhantomData<C>,23}2425impl<C: Component> DynamicUniformIndex<C> {26#[inline]27pub fn index(&self) -> u32 {28self.index29}30}3132/// Describes how a component gets extracted for rendering.33///34/// Therefore the component is transferred from the "app world" into the "render35/// world" in the [`ExtractSchedule`] step. This functionality is enabled by36/// adding [`ExtractComponentPlugin`] with the component type.37///38/// The Out type is defined in [`SyncComponent`].39///40/// The marker type is only used as a way to bypass the orphan rules. To41/// implement the trait for a foreign type you can use a local type as the42/// marker, e.g. the type of the plugin that calls [`ExtractComponentPlugin`].43pub trait ExtractComponent<Marker = ()>: SyncComponent {44/// ECS [`ReadOnlyQueryData`] to fetch the components to extract.45type QueryData: ReadOnlyQueryData;46/// Filters the entities with additional constraints.47type QueryFilter: QueryFilter;4849/// Defines how the component is transferred into the "render world".50fn extract_component(item: QueryItem<'_, '_, Self::QueryData>) -> Option<Self::Out>;51}5253/// This plugin prepares the components of the corresponding type for the GPU54/// by transforming them into uniforms.55///56/// They can then be accessed from the [`ComponentUniforms`] resource.57/// For referencing the newly created uniforms a [`DynamicUniformIndex`] is inserted58/// for every processed entity.59///60/// Therefore it sets up the [`RenderSystems::Prepare`] step61/// for the specified [`ExtractComponent`].62pub struct UniformComponentPlugin<C>(PhantomData<fn() -> C>);6364impl<C> Default for UniformComponentPlugin<C> {65fn default() -> Self {66Self(PhantomData)67}68}6970impl<C: Component + ShaderType + WriteInto + Clone> Plugin for UniformComponentPlugin<C> {71fn build(&self, app: &mut App) {72if let Some(render_app) = app.get_sub_app_mut(RenderApp) {73render_app74.insert_resource(ComponentUniforms::<C>::default())75.add_systems(76Render,77prepare_uniform_components::<C>.in_set(RenderSystems::PrepareResources),78);79}80}81}8283/// Stores all uniforms of the component type.84#[derive(Resource)]85pub struct ComponentUniforms<C: Component + ShaderType> {86uniforms: DynamicUniformBuffer<C>,87}8889impl<C: Component + ShaderType> Deref for ComponentUniforms<C> {90type Target = DynamicUniformBuffer<C>;9192#[inline]93fn deref(&self) -> &Self::Target {94&self.uniforms95}96}9798impl<C: Component + ShaderType> ComponentUniforms<C> {99#[inline]100pub fn uniforms(&self) -> &DynamicUniformBuffer<C> {101&self.uniforms102}103}104105impl<C: Component + ShaderType> Default for ComponentUniforms<C> {106fn default() -> Self {107Self {108uniforms: Default::default(),109}110}111}112113/// This system prepares all components of the corresponding component type.114/// They are transformed into uniforms and stored in the [`ComponentUniforms`] resource.115fn prepare_uniform_components<C>(116mut commands: Commands,117render_device: Res<RenderDevice>,118render_queue: Res<RenderQueue>,119mut component_uniforms: ResMut<ComponentUniforms<C>>,120components: Query<(Entity, &C)>,121) where122C: Component + ShaderType + WriteInto + Clone,123{124let components_iter = components.iter();125let count = components_iter.len();126let Some(mut writer) =127component_uniforms128.uniforms129.get_writer(count, &render_device, &render_queue)130else {131return;132};133let entities = components_iter134.map(|(entity, component)| {135(136entity,137DynamicUniformIndex::<C> {138index: writer.write(component),139marker: PhantomData,140},141)142})143.collect::<Vec<_>>();144commands.try_insert_batch(entities);145}146147/// This plugin extracts the components into the render world for synced148/// entities. To do so, it sets up the [`ExtractSchedule`] step for the149/// specified [`ExtractComponent`].150///151/// It also registers [`SyncComponentPlugin`] to ensure the extracted components152/// are deleted if the main world components are removed.153pub struct ExtractComponentPlugin<C, F = ()> {154only_extract_visible: bool,155marker: PhantomData<fn() -> (C, F)>,156}157158impl<C, F> Default for ExtractComponentPlugin<C, F> {159fn default() -> Self {160Self {161only_extract_visible: false,162marker: PhantomData,163}164}165}166167impl<C, F> ExtractComponentPlugin<C, F> {168pub fn extract_visible() -> Self {169Self {170only_extract_visible: true,171marker: PhantomData,172}173}174}175176impl<C: ExtractComponent<Marker>, Marker: 'static> Plugin for ExtractComponentPlugin<C, Marker> {177fn build(&self, app: &mut App) {178app.add_plugins(SyncComponentPlugin::<C>::default());179180if let Some(render_app) = app.get_sub_app_mut(RenderApp) {181if self.only_extract_visible {182render_app.add_systems(ExtractSchedule, extract_visible_components::<C, Marker>);183} else {184render_app.add_systems(ExtractSchedule, extract_components::<C, Marker>);185}186}187}188}189190/// This system extracts all components of the corresponding [`ExtractComponent`], for entities that are synced via [`crate::sync_world::SyncToRenderWorld`].191fn extract_components<C: ExtractComponent<Marker>, Marker>(192mut commands: Commands,193mut previous_len: Local<usize>,194query: Extract<Query<(RenderEntity, C::QueryData), C::QueryFilter>>,195) {196let mut values = Vec::with_capacity(*previous_len);197for (entity, query_item) in &query {198if let Some(component) = C::extract_component(query_item) {199values.push((entity, component));200} else {201commands.entity(entity).remove::<C::Out>();202}203}204*previous_len = values.len();205commands.try_insert_batch(values);206}207208/// This system extracts all components of the corresponding [`ExtractComponent`], for entities that are visible and synced via [`crate::sync_world::SyncToRenderWorld`].209fn extract_visible_components<C: ExtractComponent<Marker>, Marker>(210mut commands: Commands,211mut previous_len: Local<usize>,212query: Extract<Query<(RenderEntity, &ViewVisibility, C::QueryData), C::QueryFilter>>,213) {214let mut values = Vec::with_capacity(*previous_len);215for (entity, view_visibility, query_item) in &query {216if view_visibility.get() {217if let Some(component) = C::extract_component(query_item) {218values.push((entity, component));219} else {220commands.entity(entity).remove::<C::Out>();221}222}223}224*previous_len = values.len();225commands.try_insert_batch(values);226}227228229