bevy_core_pipeline/skybox/
prepass.rs1use bevy_asset::{load_embedded_asset, AssetServer, Handle};
4use bevy_ecs::{
5 component::Component,
6 entity::Entity,
7 query::{Has, With},
8 resource::Resource,
9 system::{Commands, Query, Res, ResMut},
10};
11use bevy_render::{
12 render_resource::{
13 binding_types::uniform_buffer, BindGroup, BindGroupEntries, BindGroupLayoutDescriptor,
14 BindGroupLayoutEntries, CachedRenderPipelineId, CompareFunction, DepthStencilState,
15 FragmentState, MultisampleState, PipelineCache, RenderPipelineDescriptor, ShaderStages,
16 SpecializedRenderPipeline, SpecializedRenderPipelines,
17 },
18 renderer::RenderDevice,
19 view::{Msaa, ViewUniform, ViewUniforms},
20};
21use bevy_shader::Shader;
22use bevy_utils::prelude::default;
23
24use crate::{
25 core_3d::CORE_3D_DEPTH_FORMAT,
26 prepass::{
27 prepass_target_descriptors, MotionVectorPrepass, NormalPrepass, PreviousViewData,
28 PreviousViewUniforms,
29 },
30 FullscreenShader, Skybox,
31};
32
33#[derive(Resource)]
39pub struct SkyboxPrepassPipeline {
40 bind_group_layout: BindGroupLayoutDescriptor,
41 fullscreen_shader: FullscreenShader,
42 fragment_shader: Handle<Shader>,
43}
44
45#[derive(PartialEq, Eq, Hash, Clone, Copy)]
47pub struct SkyboxPrepassPipelineKey {
48 samples: u32,
49 normal_prepass: bool,
50}
51
52#[derive(Component)]
55pub struct RenderSkyboxPrepassPipeline(pub CachedRenderPipelineId);
56
57#[derive(Component)]
60pub struct SkyboxPrepassBindGroup(pub BindGroup);
61
62pub fn init_skybox_prepass_pipeline(
63 mut commands: Commands,
64 fullscreen_shader: Res<FullscreenShader>,
65 asset_server: Res<AssetServer>,
66) {
67 commands.insert_resource(SkyboxPrepassPipeline {
68 bind_group_layout: BindGroupLayoutDescriptor::new(
69 "skybox_prepass_bind_group_layout",
70 &BindGroupLayoutEntries::sequential(
71 ShaderStages::FRAGMENT,
72 (
73 uniform_buffer::<ViewUniform>(true),
74 uniform_buffer::<PreviousViewData>(true),
75 ),
76 ),
77 ),
78 fullscreen_shader: fullscreen_shader.clone(),
79 fragment_shader: load_embedded_asset!(asset_server.as_ref(), "skybox_prepass.wgsl"),
80 });
81}
82
83impl SpecializedRenderPipeline for SkyboxPrepassPipeline {
84 type Key = SkyboxPrepassPipelineKey;
85
86 fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
87 RenderPipelineDescriptor {
88 label: Some("skybox_prepass_pipeline".into()),
89 layout: vec![self.bind_group_layout.clone()],
90 vertex: self.fullscreen_shader.to_vertex_state(),
91 depth_stencil: Some(DepthStencilState {
92 format: CORE_3D_DEPTH_FORMAT,
93 depth_write_enabled: false,
94 depth_compare: CompareFunction::GreaterEqual,
95 stencil: default(),
96 bias: default(),
97 }),
98 multisample: MultisampleState {
99 count: key.samples,
100 mask: !0,
101 alpha_to_coverage_enabled: false,
102 },
103 fragment: Some(FragmentState {
104 shader: self.fragment_shader.clone(),
105 targets: prepass_target_descriptors(key.normal_prepass, true, false),
106 ..default()
107 }),
108 ..default()
109 }
110 }
111}
112
113pub fn prepare_skybox_prepass_pipelines(
115 mut commands: Commands,
116 pipeline_cache: Res<PipelineCache>,
117 mut pipelines: ResMut<SpecializedRenderPipelines<SkyboxPrepassPipeline>>,
118 pipeline: Res<SkyboxPrepassPipeline>,
119 views: Query<(Entity, Has<NormalPrepass>, &Msaa), (With<Skybox>, With<MotionVectorPrepass>)>,
120) {
121 for (entity, normal_prepass, msaa) in &views {
122 let pipeline_key = SkyboxPrepassPipelineKey {
123 samples: msaa.samples(),
124 normal_prepass,
125 };
126
127 let render_skybox_prepass_pipeline =
128 pipelines.specialize(&pipeline_cache, &pipeline, pipeline_key);
129 commands
130 .entity(entity)
131 .insert(RenderSkyboxPrepassPipeline(render_skybox_prepass_pipeline));
132 }
133}
134
135pub fn prepare_skybox_prepass_bind_groups(
139 mut commands: Commands,
140 pipeline: Res<SkyboxPrepassPipeline>,
141 view_uniforms: Res<ViewUniforms>,
142 prev_view_uniforms: Res<PreviousViewUniforms>,
143 render_device: Res<RenderDevice>,
144 pipeline_cache: Res<PipelineCache>,
145 views: Query<Entity, (With<Skybox>, With<MotionVectorPrepass>)>,
146) {
147 for entity in &views {
148 let (Some(view_uniforms), Some(prev_view_uniforms)) = (
149 view_uniforms.uniforms.binding(),
150 prev_view_uniforms.uniforms.binding(),
151 ) else {
152 continue;
153 };
154 let bind_group = render_device.create_bind_group(
155 "skybox_prepass_bind_group",
156 &pipeline_cache.get_bind_group_layout(&pipeline.bind_group_layout),
157 &BindGroupEntries::sequential((view_uniforms, prev_view_uniforms)),
158 );
159
160 commands
161 .entity(entity)
162 .insert(SkyboxPrepassBindGroup(bind_group));
163 }
164}