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, BindGroupLayout,
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: BindGroupLayout,
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 render_device: Res<RenderDevice>,
65 fullscreen_shader: Res<FullscreenShader>,
66 asset_server: Res<AssetServer>,
67) {
68 commands.insert_resource(SkyboxPrepassPipeline {
69 bind_group_layout: render_device.create_bind_group_layout(
70 "skybox_prepass_bind_group_layout",
71 &BindGroupLayoutEntries::sequential(
72 ShaderStages::FRAGMENT,
73 (
74 uniform_buffer::<ViewUniform>(true),
75 uniform_buffer::<PreviousViewData>(true),
76 ),
77 ),
78 ),
79 fullscreen_shader: fullscreen_shader.clone(),
80 fragment_shader: load_embedded_asset!(asset_server.as_ref(), "skybox_prepass.wgsl"),
81 });
82}
83
84impl SpecializedRenderPipeline for SkyboxPrepassPipeline {
85 type Key = SkyboxPrepassPipelineKey;
86
87 fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
88 RenderPipelineDescriptor {
89 label: Some("skybox_prepass_pipeline".into()),
90 layout: vec![self.bind_group_layout.clone()],
91 vertex: self.fullscreen_shader.to_vertex_state(),
92 depth_stencil: Some(DepthStencilState {
93 format: CORE_3D_DEPTH_FORMAT,
94 depth_write_enabled: false,
95 depth_compare: CompareFunction::GreaterEqual,
96 stencil: default(),
97 bias: default(),
98 }),
99 multisample: MultisampleState {
100 count: key.samples,
101 mask: !0,
102 alpha_to_coverage_enabled: false,
103 },
104 fragment: Some(FragmentState {
105 shader: self.fragment_shader.clone(),
106 targets: prepass_target_descriptors(key.normal_prepass, true, false),
107 ..default()
108 }),
109 ..default()
110 }
111 }
112}
113
114pub fn prepare_skybox_prepass_pipelines(
116 mut commands: Commands,
117 pipeline_cache: Res<PipelineCache>,
118 mut pipelines: ResMut<SpecializedRenderPipelines<SkyboxPrepassPipeline>>,
119 pipeline: Res<SkyboxPrepassPipeline>,
120 views: Query<(Entity, Has<NormalPrepass>, &Msaa), (With<Skybox>, With<MotionVectorPrepass>)>,
121) {
122 for (entity, normal_prepass, msaa) in &views {
123 let pipeline_key = SkyboxPrepassPipelineKey {
124 samples: msaa.samples(),
125 normal_prepass,
126 };
127
128 let render_skybox_prepass_pipeline =
129 pipelines.specialize(&pipeline_cache, &pipeline, pipeline_key);
130 commands
131 .entity(entity)
132 .insert(RenderSkyboxPrepassPipeline(render_skybox_prepass_pipeline));
133 }
134}
135
136pub fn prepare_skybox_prepass_bind_groups(
140 mut commands: Commands,
141 pipeline: Res<SkyboxPrepassPipeline>,
142 view_uniforms: Res<ViewUniforms>,
143 prev_view_uniforms: Res<PreviousViewUniforms>,
144 render_device: Res<RenderDevice>,
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.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}