bevy_pbr/transmission/
texture.rs1use bevy_core_pipeline::core_3d::{AlphaMask3d, Opaque3d, Transparent3d};
2use bevy_ecs::{
3 component::Component,
4 entity::Entity,
5 system::{Commands, Query, Res, ResMut},
6};
7use bevy_image::ToExtents;
8use bevy_platform::collections::HashMap;
9use bevy_render::{
10 camera::ExtractedCamera,
11 render_phase::{ViewBinnedRenderPhases, ViewSortedRenderPhases},
12 render_resource::{
13 FilterMode, Sampler, SamplerDescriptor, Texture, TextureDescriptor, TextureDimension,
14 TextureUsages, TextureView,
15 },
16 renderer::RenderDevice,
17 texture::TextureCache,
18 view::ExtractedView,
19};
20
21use crate::{ScreenSpaceTransmission, Transmissive3d};
22
23#[derive(Component)]
24pub struct ViewTransmissionTexture {
25 pub texture: Texture,
26 pub view: TextureView,
27 pub sampler: Sampler,
28}
29
30pub fn prepare_core_3d_transmission_textures(
31 mut commands: Commands,
32 mut texture_cache: ResMut<TextureCache>,
33 render_device: Res<RenderDevice>,
34 opaque_3d_phases: Res<ViewBinnedRenderPhases<Opaque3d>>,
35 alpha_mask_3d_phases: Res<ViewBinnedRenderPhases<AlphaMask3d>>,
36 transmissive_3d_phases: Res<ViewSortedRenderPhases<Transmissive3d>>,
37 transparent_3d_phases: Res<ViewSortedRenderPhases<Transparent3d>>,
38 views_3d: Query<(
39 Entity,
40 &ExtractedCamera,
41 &ScreenSpaceTransmission,
42 &ExtractedView,
43 )>,
44) {
45 let mut textures = <HashMap<_, _>>::default();
46 for (entity, camera, transmission, view) in &views_3d {
47 if !opaque_3d_phases.contains_key(&view.retained_view_entity)
48 || !alpha_mask_3d_phases.contains_key(&view.retained_view_entity)
49 || !transparent_3d_phases.contains_key(&view.retained_view_entity)
50 {
51 continue;
52 };
53
54 let Some(transmissive_3d_phase) = transmissive_3d_phases.get(&view.retained_view_entity)
55 else {
56 continue;
57 };
58
59 let Some(physical_target_size) = camera.physical_target_size else {
60 continue;
61 };
62
63 if transmission.steps == 0 {
65 continue;
66 }
67
68 if transmissive_3d_phase.items.is_empty() {
70 continue;
71 }
72
73 let cached_texture = textures
74 .entry(camera.target.clone())
75 .or_insert_with(|| {
76 let usage = TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST;
77
78 let descriptor = TextureDescriptor {
79 label: Some("view_transmission_texture"),
80 size: physical_target_size.to_extents(),
82 mip_level_count: 1,
83 sample_count: 1, dimension: TextureDimension::D2,
85 format: view.target_format,
86 usage,
87 view_formats: &[],
88 };
89
90 texture_cache.get(&render_device, descriptor)
91 })
92 .clone();
93
94 let sampler = render_device.create_sampler(&SamplerDescriptor {
95 label: Some("view_transmission_sampler"),
96 mag_filter: FilterMode::Linear,
97 min_filter: FilterMode::Linear,
98 ..Default::default()
99 });
100
101 commands.entity(entity).insert(ViewTransmissionTexture {
102 texture: cached_texture.texture,
103 view: cached_texture.default_view,
104 sampler,
105 });
106 }
107}