mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 04:33:37 +00:00
Add Skybox Motion Vectors (#13617)
# Objective - Add motion vector support to the skybox - This fixes the last remaining "gap" to complete the motion blur feature ## Solution - Add a pipeline for the skybox to write motion vectors to the prepass ## Testing - Used examples to test motion vectors using motion blur https://github.com/bevyengine/bevy/assets/2632925/74c0778a-7e77-4e68-8111-05791e4bfdd2 --------- Co-authored-by: Patrick Walton <pcwalton@mimiga.net>
This commit is contained in:
parent
7d3fcd5067
commit
b45786df41
9 changed files with 317 additions and 65 deletions
|
@ -31,6 +31,7 @@ use std::ops::Range;
|
|||
|
||||
use bevy_asset::AssetId;
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_math::Mat4;
|
||||
use bevy_reflect::Reflect;
|
||||
use bevy_render::{
|
||||
mesh::Mesh,
|
||||
|
@ -38,10 +39,15 @@ use bevy_render::{
|
|||
BinnedPhaseItem, CachedRenderPipelinePhaseItem, DrawFunctionId, PhaseItem,
|
||||
PhaseItemExtraIndex,
|
||||
},
|
||||
render_resource::{BindGroupId, CachedRenderPipelineId, Extent3d, TextureFormat, TextureView},
|
||||
render_resource::{
|
||||
BindGroupId, CachedRenderPipelineId, ColorTargetState, ColorWrites, DynamicUniformBuffer,
|
||||
Extent3d, ShaderType, TextureFormat, TextureView,
|
||||
},
|
||||
texture::ColorAttachment,
|
||||
};
|
||||
|
||||
use crate::deferred::{DEFERRED_LIGHTING_PASS_ID_FORMAT, DEFERRED_PREPASS_FORMAT};
|
||||
|
||||
pub const NORMAL_PREPASS_FORMAT: TextureFormat = TextureFormat::Rgb10a2Unorm;
|
||||
pub const MOTION_VECTOR_PREPASS_FORMAT: TextureFormat = TextureFormat::Rg16Float;
|
||||
|
||||
|
@ -63,6 +69,22 @@ pub struct MotionVectorPrepass;
|
|||
#[derive(Component, Default, Reflect)]
|
||||
pub struct DeferredPrepass;
|
||||
|
||||
#[derive(Component, ShaderType, Clone)]
|
||||
pub struct PreviousViewData {
|
||||
pub inverse_view: Mat4,
|
||||
pub view_proj: Mat4,
|
||||
}
|
||||
|
||||
#[derive(Resource, Default)]
|
||||
pub struct PreviousViewUniforms {
|
||||
pub uniforms: DynamicUniformBuffer<PreviousViewData>,
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct PreviousViewUniformOffset {
|
||||
pub offset: u32,
|
||||
}
|
||||
|
||||
/// Textures that are written to by the prepass.
|
||||
///
|
||||
/// This component will only be present if any of the relevant prepass components are also present.
|
||||
|
@ -270,3 +292,32 @@ impl CachedRenderPipelinePhaseItem for AlphaMask3dPrepass {
|
|||
self.key.pipeline
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prepass_target_descriptors(
|
||||
normal_prepass: bool,
|
||||
motion_vector_prepass: bool,
|
||||
deferred_prepass: bool,
|
||||
) -> Vec<Option<ColorTargetState>> {
|
||||
vec![
|
||||
normal_prepass.then_some(ColorTargetState {
|
||||
format: NORMAL_PREPASS_FORMAT,
|
||||
blend: None,
|
||||
write_mask: ColorWrites::ALL,
|
||||
}),
|
||||
motion_vector_prepass.then_some(ColorTargetState {
|
||||
format: MOTION_VECTOR_PREPASS_FORMAT,
|
||||
blend: None,
|
||||
write_mask: ColorWrites::ALL,
|
||||
}),
|
||||
deferred_prepass.then_some(ColorTargetState {
|
||||
format: DEFERRED_PREPASS_FORMAT,
|
||||
blend: None,
|
||||
write_mask: ColorWrites::ALL,
|
||||
}),
|
||||
deferred_prepass.then_some(ColorTargetState {
|
||||
format: DEFERRED_LIGHTING_PASS_ID_FORMAT,
|
||||
blend: None,
|
||||
write_mask: ColorWrites::ALL,
|
||||
}),
|
||||
]
|
||||
}
|
||||
|
|
|
@ -5,14 +5,19 @@ use bevy_render::{
|
|||
diagnostic::RecordDiagnostics,
|
||||
render_graph::{NodeRunError, RenderGraphContext, ViewNode},
|
||||
render_phase::{TrackedRenderPass, ViewBinnedRenderPhases},
|
||||
render_resource::{CommandEncoderDescriptor, RenderPassDescriptor, StoreOp},
|
||||
render_resource::{CommandEncoderDescriptor, PipelineCache, RenderPassDescriptor, StoreOp},
|
||||
renderer::RenderContext,
|
||||
view::ViewDepthTexture,
|
||||
view::{ViewDepthTexture, ViewUniformOffset},
|
||||
};
|
||||
#[cfg(feature = "trace")]
|
||||
use bevy_utils::tracing::info_span;
|
||||
|
||||
use super::{AlphaMask3dPrepass, DeferredPrepass, Opaque3dPrepass, ViewPrepassTextures};
|
||||
use crate::skybox::prepass::{RenderSkyboxPrepassPipeline, SkyboxPrepassBindGroup};
|
||||
|
||||
use super::{
|
||||
AlphaMask3dPrepass, DeferredPrepass, Opaque3dPrepass, PreviousViewUniformOffset,
|
||||
ViewPrepassTextures,
|
||||
};
|
||||
|
||||
/// Render node used by the prepass.
|
||||
///
|
||||
|
@ -26,17 +31,28 @@ impl ViewNode for PrepassNode {
|
|||
&'static ExtractedCamera,
|
||||
&'static ViewDepthTexture,
|
||||
&'static ViewPrepassTextures,
|
||||
&'static ViewUniformOffset,
|
||||
Option<&'static DeferredPrepass>,
|
||||
Option<&'static RenderSkyboxPrepassPipeline>,
|
||||
Option<&'static SkyboxPrepassBindGroup>,
|
||||
Option<&'static PreviousViewUniformOffset>,
|
||||
);
|
||||
|
||||
fn run<'w>(
|
||||
&self,
|
||||
graph: &mut RenderGraphContext,
|
||||
render_context: &mut RenderContext<'w>,
|
||||
(view, camera, view_depth_texture, view_prepass_textures, deferred_prepass): QueryItem<
|
||||
'w,
|
||||
Self::ViewQuery,
|
||||
>,
|
||||
(
|
||||
view,
|
||||
camera,
|
||||
view_depth_texture,
|
||||
view_prepass_textures,
|
||||
view_uniform_offset,
|
||||
deferred_prepass,
|
||||
skybox_prepass_pipeline,
|
||||
skybox_prepass_bind_group,
|
||||
view_prev_uniform_offset,
|
||||
): QueryItem<'w, Self::ViewQuery>,
|
||||
world: &'w World,
|
||||
) -> Result<(), NodeRunError> {
|
||||
let (Some(opaque_prepass_phases), Some(alpha_mask_prepass_phases)) = (
|
||||
|
@ -119,6 +135,30 @@ impl ViewNode for PrepassNode {
|
|||
alpha_mask_prepass_phase.render(&mut render_pass, world, view_entity);
|
||||
}
|
||||
|
||||
// Skybox draw using a fullscreen triangle
|
||||
if let (
|
||||
Some(skybox_prepass_pipeline),
|
||||
Some(skybox_prepass_bind_group),
|
||||
Some(view_prev_uniform_offset),
|
||||
) = (
|
||||
skybox_prepass_pipeline,
|
||||
skybox_prepass_bind_group,
|
||||
view_prev_uniform_offset,
|
||||
) {
|
||||
let pipeline_cache = world.resource::<PipelineCache>();
|
||||
if let Some(pipeline) =
|
||||
pipeline_cache.get_render_pipeline(skybox_prepass_pipeline.0)
|
||||
{
|
||||
render_pass.set_render_pipeline(pipeline);
|
||||
render_pass.set_bind_group(
|
||||
0,
|
||||
&skybox_prepass_bind_group.0,
|
||||
&[view_uniform_offset.offset, view_prev_uniform_offset.offset],
|
||||
);
|
||||
render_pass.draw(0..3, 0..1);
|
||||
}
|
||||
}
|
||||
|
||||
pass_span.end(&mut render_pass);
|
||||
drop(render_pass);
|
||||
|
||||
|
|
|
@ -22,16 +22,25 @@ use bevy_render::{
|
|||
view::{ExtractedView, Msaa, ViewTarget, ViewUniform, ViewUniforms},
|
||||
Render, RenderApp, RenderSet,
|
||||
};
|
||||
use prepass::{SkyboxPrepassPipeline, SKYBOX_PREPASS_SHADER_HANDLE};
|
||||
|
||||
use crate::core_3d::CORE_3D_DEPTH_FORMAT;
|
||||
|
||||
const SKYBOX_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(55594763423201);
|
||||
|
||||
pub mod prepass;
|
||||
|
||||
pub struct SkyboxPlugin;
|
||||
|
||||
impl Plugin for SkyboxPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
load_internal_asset!(app, SKYBOX_SHADER_HANDLE, "skybox.wgsl", Shader::from_wgsl);
|
||||
load_internal_asset!(
|
||||
app,
|
||||
SKYBOX_PREPASS_SHADER_HANDLE,
|
||||
"skybox_prepass.wgsl",
|
||||
Shader::from_wgsl
|
||||
);
|
||||
|
||||
app.add_plugins((
|
||||
ExtractComponentPlugin::<Skybox>::default(),
|
||||
|
@ -43,11 +52,15 @@ impl Plugin for SkyboxPlugin {
|
|||
};
|
||||
render_app
|
||||
.init_resource::<SpecializedRenderPipelines<SkyboxPipeline>>()
|
||||
.init_resource::<SpecializedRenderPipelines<SkyboxPrepassPipeline>>()
|
||||
.add_systems(
|
||||
Render,
|
||||
(
|
||||
prepare_skybox_pipelines.in_set(RenderSet::Prepare),
|
||||
prepass::prepare_skybox_prepass_pipelines.in_set(RenderSet::Prepare),
|
||||
prepare_skybox_bind_groups.in_set(RenderSet::PrepareBindGroups),
|
||||
prepass::prepare_skybox_prepass_bind_groups
|
||||
.in_set(RenderSet::PrepareBindGroups),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -57,7 +70,9 @@ impl Plugin for SkyboxPlugin {
|
|||
return;
|
||||
};
|
||||
let render_device = render_app.world().resource::<RenderDevice>().clone();
|
||||
render_app.insert_resource(SkyboxPipeline::new(&render_device));
|
||||
render_app
|
||||
.insert_resource(SkyboxPipeline::new(&render_device))
|
||||
.init_resource::<SkyboxPrepassPipeline>();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
165
crates/bevy_core_pipeline/src/skybox/prepass.rs
Normal file
165
crates/bevy_core_pipeline/src/skybox/prepass.rs
Normal file
|
@ -0,0 +1,165 @@
|
|||
#![warn(missing_docs)]
|
||||
|
||||
//! Adds motion vector support to skyboxes. See [`SkyboxPrepassPipeline`] for details.
|
||||
|
||||
use bevy_asset::Handle;
|
||||
use bevy_ecs::{
|
||||
component::Component,
|
||||
entity::Entity,
|
||||
query::{Has, With},
|
||||
system::{Commands, Query, Res, ResMut, Resource},
|
||||
world::{FromWorld, World},
|
||||
};
|
||||
use bevy_render::{
|
||||
render_resource::{
|
||||
binding_types::uniform_buffer, BindGroup, BindGroupEntries, BindGroupLayout,
|
||||
BindGroupLayoutEntries, CachedRenderPipelineId, CompareFunction, DepthStencilState,
|
||||
FragmentState, MultisampleState, PipelineCache, RenderPipelineDescriptor, Shader,
|
||||
ShaderStages, SpecializedRenderPipeline, SpecializedRenderPipelines,
|
||||
},
|
||||
renderer::RenderDevice,
|
||||
view::{Msaa, ViewUniform, ViewUniforms},
|
||||
};
|
||||
use bevy_utils::prelude::default;
|
||||
|
||||
use crate::{
|
||||
core_3d::CORE_3D_DEPTH_FORMAT,
|
||||
prepass::{
|
||||
prepass_target_descriptors, MotionVectorPrepass, NormalPrepass, PreviousViewData,
|
||||
PreviousViewUniforms,
|
||||
},
|
||||
Skybox,
|
||||
};
|
||||
|
||||
pub const SKYBOX_PREPASS_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(376510055324461154);
|
||||
|
||||
/// This pipeline writes motion vectors to the prepass for all [`Skybox`]es.
|
||||
///
|
||||
/// This allows features like motion blur and TAA to work correctly on the skybox. Without this, for
|
||||
/// example, motion blur would not be applied to the skybox when the camera is rotated and motion
|
||||
/// blur is enabled.
|
||||
#[derive(Resource)]
|
||||
pub struct SkyboxPrepassPipeline {
|
||||
bind_group_layout: BindGroupLayout,
|
||||
}
|
||||
|
||||
/// Used to specialize the [`SkyboxPrepassPipeline`].
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub struct SkyboxPrepassPipelineKey {
|
||||
samples: u32,
|
||||
normal_prepass: bool,
|
||||
}
|
||||
|
||||
/// Stores the ID for a camera's specialized pipeline, so it can be retrieved from the
|
||||
/// [`PipelineCache`].
|
||||
#[derive(Component)]
|
||||
pub struct RenderSkyboxPrepassPipeline(pub CachedRenderPipelineId);
|
||||
|
||||
/// Stores the [`SkyboxPrepassPipeline`] bind group for a camera. This is later used by the prepass
|
||||
/// render graph node to add this binding to the prepass's render pass.
|
||||
#[derive(Component)]
|
||||
pub struct SkyboxPrepassBindGroup(pub BindGroup);
|
||||
|
||||
impl FromWorld for SkyboxPrepassPipeline {
|
||||
fn from_world(world: &mut World) -> Self {
|
||||
let render_device = world.resource::<RenderDevice>();
|
||||
|
||||
Self {
|
||||
bind_group_layout: render_device.create_bind_group_layout(
|
||||
"skybox_prepass_bind_group_layout",
|
||||
&BindGroupLayoutEntries::sequential(
|
||||
ShaderStages::FRAGMENT,
|
||||
(
|
||||
uniform_buffer::<ViewUniform>(true),
|
||||
uniform_buffer::<PreviousViewData>(true),
|
||||
),
|
||||
),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SpecializedRenderPipeline for SkyboxPrepassPipeline {
|
||||
type Key = SkyboxPrepassPipelineKey;
|
||||
|
||||
fn specialize(&self, key: Self::Key) -> RenderPipelineDescriptor {
|
||||
RenderPipelineDescriptor {
|
||||
label: Some("skybox_prepass_pipeline".into()),
|
||||
layout: vec![self.bind_group_layout.clone()],
|
||||
push_constant_ranges: vec![],
|
||||
vertex: crate::fullscreen_vertex_shader::fullscreen_shader_vertex_state(),
|
||||
primitive: default(),
|
||||
depth_stencil: Some(DepthStencilState {
|
||||
format: CORE_3D_DEPTH_FORMAT,
|
||||
depth_write_enabled: false,
|
||||
depth_compare: CompareFunction::GreaterEqual,
|
||||
stencil: default(),
|
||||
bias: default(),
|
||||
}),
|
||||
multisample: MultisampleState {
|
||||
count: key.samples,
|
||||
mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
fragment: Some(FragmentState {
|
||||
shader: SKYBOX_PREPASS_SHADER_HANDLE,
|
||||
shader_defs: vec![],
|
||||
entry_point: "fragment".into(),
|
||||
targets: prepass_target_descriptors(key.normal_prepass, true, false),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Specialize and cache the [`SkyboxPrepassPipeline`] for each camera with a [`Skybox`].
|
||||
pub fn prepare_skybox_prepass_pipelines(
|
||||
mut commands: Commands,
|
||||
pipeline_cache: Res<PipelineCache>,
|
||||
mut pipelines: ResMut<SpecializedRenderPipelines<SkyboxPrepassPipeline>>,
|
||||
msaa: Res<Msaa>,
|
||||
pipeline: Res<SkyboxPrepassPipeline>,
|
||||
views: Query<(Entity, Has<NormalPrepass>), (With<Skybox>, With<MotionVectorPrepass>)>,
|
||||
) {
|
||||
for (entity, normal_prepass) in &views {
|
||||
let pipeline_key = SkyboxPrepassPipelineKey {
|
||||
samples: msaa.samples(),
|
||||
normal_prepass,
|
||||
};
|
||||
|
||||
let render_skybox_prepass_pipeline =
|
||||
pipelines.specialize(&pipeline_cache, &pipeline, pipeline_key);
|
||||
commands
|
||||
.entity(entity)
|
||||
.insert(RenderSkyboxPrepassPipeline(render_skybox_prepass_pipeline));
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates the required bind groups for the [`SkyboxPrepassPipeline`]. This binds the view uniforms
|
||||
/// from the CPU for access in the prepass shader on the GPU, allowing us to compute camera motion
|
||||
/// between frames. This is then stored in the [`SkyboxPrepassBindGroup`] component on the camera.
|
||||
pub fn prepare_skybox_prepass_bind_groups(
|
||||
mut commands: Commands,
|
||||
pipeline: Res<SkyboxPrepassPipeline>,
|
||||
view_uniforms: Res<ViewUniforms>,
|
||||
prev_view_uniforms: Res<PreviousViewUniforms>,
|
||||
render_device: Res<RenderDevice>,
|
||||
views: Query<Entity, (With<Skybox>, With<MotionVectorPrepass>)>,
|
||||
) {
|
||||
for entity in &views {
|
||||
let (Some(view_uniforms), Some(prev_view_uniforms)) = (
|
||||
view_uniforms.uniforms.binding(),
|
||||
prev_view_uniforms.uniforms.binding(),
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
let bind_group = render_device.create_bind_group(
|
||||
"skybox_prepass_bind_group",
|
||||
&pipeline.bind_group_layout,
|
||||
&BindGroupEntries::sequential((view_uniforms, prev_view_uniforms)),
|
||||
);
|
||||
|
||||
commands
|
||||
.entity(entity)
|
||||
.insert(SkyboxPrepassBindGroup(bind_group));
|
||||
}
|
||||
}
|
21
crates/bevy_core_pipeline/src/skybox/skybox_prepass.wgsl
Normal file
21
crates/bevy_core_pipeline/src/skybox/skybox_prepass.wgsl
Normal file
|
@ -0,0 +1,21 @@
|
|||
#import bevy_render::view::View
|
||||
#import bevy_core_pipeline::fullscreen_vertex_shader::FullscreenVertexOutput
|
||||
#import bevy_pbr::view_transformations::uv_to_ndc
|
||||
|
||||
struct PreviousViewUniforms {
|
||||
inverse_view: mat4x4<f32>,
|
||||
view_proj: mat4x4<f32>,
|
||||
}
|
||||
|
||||
@group(0) @binding(0) var<uniform> view: View;
|
||||
@group(0) @binding(1) var<uniform> previous_view: PreviousViewUniforms;
|
||||
|
||||
@fragment
|
||||
fn fragment(in: FullscreenVertexOutput) -> @location(1) vec4<f32> {
|
||||
let clip_pos = uv_to_ndc(in.uv); // Convert from uv to clip space
|
||||
let world_pos = view.inverse_view_proj * vec4(clip_pos, 0.0, 1.0);
|
||||
let prev_clip_pos = (previous_view.view_proj * world_pos).xy;
|
||||
let velocity = (clip_pos - prev_clip_pos) * vec2(0.5, -0.5); // Copied from mesh motion vectors
|
||||
|
||||
return vec4(velocity.x, velocity.y, 0.0, 1.0);
|
||||
}
|
|
@ -4,11 +4,13 @@ use super::{
|
|||
};
|
||||
use crate::{
|
||||
Material, MeshFlags, MeshTransforms, MeshUniform, NotShadowCaster, NotShadowReceiver,
|
||||
PreviousGlobalTransform, PreviousViewData, PreviousViewUniforms, RenderMaterialInstances,
|
||||
ShadowView,
|
||||
PreviousGlobalTransform, RenderMaterialInstances, ShadowView,
|
||||
};
|
||||
use bevy_asset::{AssetEvent, AssetId, AssetServer, Assets, Handle, UntypedAssetId};
|
||||
use bevy_core_pipeline::core_3d::Camera3d;
|
||||
use bevy_core_pipeline::{
|
||||
core_3d::Camera3d,
|
||||
prepass::{PreviousViewData, PreviousViewUniforms},
|
||||
};
|
||||
use bevy_ecs::{
|
||||
component::Component,
|
||||
entity::{Entity, EntityHashMap},
|
||||
|
|
|
@ -7,10 +7,10 @@ use super::{
|
|||
MeshletGpuScene,
|
||||
};
|
||||
use crate::{
|
||||
MeshViewBindGroup, PrepassViewBindGroup, PreviousViewUniformOffset, ViewFogUniformOffset,
|
||||
ViewLightProbesUniformOffset, ViewLightsUniformOffset, ViewScreenSpaceReflectionsUniformOffset,
|
||||
MeshViewBindGroup, PrepassViewBindGroup, ViewFogUniformOffset, ViewLightProbesUniformOffset,
|
||||
ViewLightsUniformOffset, ViewScreenSpaceReflectionsUniformOffset,
|
||||
};
|
||||
use bevy_core_pipeline::prepass::ViewPrepassTextures;
|
||||
use bevy_core_pipeline::prepass::{PreviousViewUniformOffset, ViewPrepassTextures};
|
||||
use bevy_ecs::{query::QueryItem, world::World};
|
||||
use bevy_render::{
|
||||
camera::ExtractedCamera,
|
||||
|
|
|
@ -2,8 +2,9 @@ use super::{
|
|||
gpu_scene::{MeshletViewBindGroups, MeshletViewResources},
|
||||
pipelines::MeshletPipelines,
|
||||
};
|
||||
use crate::{LightEntity, PreviousViewUniformOffset, ShadowView, ViewLightEntities};
|
||||
use crate::{LightEntity, ShadowView, ViewLightEntities};
|
||||
use bevy_color::LinearRgba;
|
||||
use bevy_core_pipeline::prepass::PreviousViewUniformOffset;
|
||||
use bevy_ecs::{
|
||||
query::QueryState,
|
||||
world::{FromWorld, World},
|
||||
|
|
|
@ -15,7 +15,7 @@ use bevy_ecs::{
|
|||
SystemParamItem,
|
||||
},
|
||||
};
|
||||
use bevy_math::{Affine3A, Mat4};
|
||||
use bevy_math::Affine3A;
|
||||
use bevy_render::{
|
||||
globals::{GlobalsBuffer, GlobalsUniform},
|
||||
prelude::{Camera, Mesh},
|
||||
|
@ -194,12 +194,6 @@ where
|
|||
#[derive(Resource)]
|
||||
struct AnyPrepassPluginLoaded;
|
||||
|
||||
#[derive(Component, ShaderType, Clone)]
|
||||
pub struct PreviousViewData {
|
||||
pub inverse_view: Mat4,
|
||||
pub view_proj: Mat4,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "meshlet"))]
|
||||
type PreviousViewFilter = (With<Camera3d>, With<MotionVectorPrepass>);
|
||||
#[cfg(feature = "meshlet")]
|
||||
|
@ -472,39 +466,12 @@ where
|
|||
let vertex_buffer_layout = layout.0.get_layout(&vertex_attributes)?;
|
||||
|
||||
// Setup prepass fragment targets - normals in slot 0 (or None if not needed), motion vectors in slot 1
|
||||
let mut targets = vec![
|
||||
let mut targets = prepass_target_descriptors(
|
||||
key.mesh_key.contains(MeshPipelineKey::NORMAL_PREPASS),
|
||||
key.mesh_key
|
||||
.contains(MeshPipelineKey::NORMAL_PREPASS)
|
||||
.then_some(ColorTargetState {
|
||||
format: NORMAL_PREPASS_FORMAT,
|
||||
// BlendState::REPLACE is not needed here, and None will be potentially much faster in some cases.
|
||||
blend: None,
|
||||
write_mask: ColorWrites::ALL,
|
||||
}),
|
||||
key.mesh_key
|
||||
.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS)
|
||||
.then_some(ColorTargetState {
|
||||
format: MOTION_VECTOR_PREPASS_FORMAT,
|
||||
// BlendState::REPLACE is not needed here, and None will be potentially much faster in some cases.
|
||||
blend: None,
|
||||
write_mask: ColorWrites::ALL,
|
||||
}),
|
||||
key.mesh_key
|
||||
.contains(MeshPipelineKey::DEFERRED_PREPASS)
|
||||
.then_some(ColorTargetState {
|
||||
format: DEFERRED_PREPASS_FORMAT,
|
||||
// BlendState::REPLACE is not needed here, and None will be potentially much faster in some cases.
|
||||
blend: None,
|
||||
write_mask: ColorWrites::ALL,
|
||||
}),
|
||||
key.mesh_key
|
||||
.contains(MeshPipelineKey::DEFERRED_PREPASS)
|
||||
.then_some(ColorTargetState {
|
||||
format: DEFERRED_LIGHTING_PASS_ID_FORMAT,
|
||||
blend: None,
|
||||
write_mask: ColorWrites::ALL,
|
||||
}),
|
||||
];
|
||||
.contains(MeshPipelineKey::MOTION_VECTOR_PREPASS),
|
||||
key.mesh_key.contains(MeshPipelineKey::DEFERRED_PREPASS),
|
||||
);
|
||||
|
||||
if targets.iter().all(Option::is_none) {
|
||||
// if no targets are required then clear the list, so that no fragment shader is required
|
||||
|
@ -623,16 +590,6 @@ pub fn extract_camera_previous_view_data(
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Resource, Default)]
|
||||
pub struct PreviousViewUniforms {
|
||||
pub uniforms: DynamicUniformBuffer<PreviousViewData>,
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct PreviousViewUniformOffset {
|
||||
pub offset: u32,
|
||||
}
|
||||
|
||||
pub fn prepare_previous_view_uniforms(
|
||||
mut commands: Commands,
|
||||
render_device: Res<RenderDevice>,
|
||||
|
|
Loading…
Reference in a new issue