Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Motion vector animated mesh #13075

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions crates/bevy_core_pipeline/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,16 @@ use crate::{
fullscreen_vertex_shader::FULLSCREEN_SHADER_HANDLE,
fxaa::FxaaPlugin,
msaa_writeback::MsaaWritebackPlugin,
prepass::{DeferredPrepass, DepthPrepass, MotionVectorPrepass, NormalPrepass},
prepass::{
AnimatedMeshMotionVectors, DeferredPrepass, DepthPrepass, MotionVectorPrepass,
NormalPrepass,
},
tonemapping::TonemappingPlugin,
upscaling::UpscalingPlugin,
};
use bevy_app::{App, Plugin};
use bevy_asset::load_internal_asset;
use bevy_render::prelude::Shader;
use bevy_render::{prelude::Shader, RenderApp};

#[derive(Default)]
pub struct CorePipelinePlugin;
Expand Down Expand Up @@ -91,4 +94,10 @@ impl Plugin for CorePipelinePlugin {
CASPlugin,
));
}

fn finish(&self, app: &mut App) {
if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
render_app.init_resource::<AnimatedMeshMotionVectors>();
}
}
}
5 changes: 5 additions & 0 deletions crates/bevy_core_pipeline/src/prepass/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub mod node;
use std::ops::Range;

use bevy_asset::AssetId;
use bevy_derive::Deref;
use bevy_ecs::prelude::*;
use bevy_reflect::Reflect;
use bevy_render::{
Expand Down Expand Up @@ -61,6 +62,10 @@ pub struct MotionVectorPrepass;
#[derive(Component, Default, Reflect)]
pub struct DeferredPrepass;

/// TODO: Docs
#[derive(Resource, Default, Deref)]
pub struct AnimatedMeshMotionVectors(pub bool);

/// Textures that are written to by the prepass.
///
/// This component will only be present if any of the relevant prepass components are also present.
Expand Down
5 changes: 2 additions & 3 deletions crates/bevy_core_pipeline/src/taa/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
core_3d::graph::{Core3d, Node3d},
fullscreen_vertex_shader::fullscreen_shader_vertex_state,
prelude::Camera3d,
prepass::{DepthPrepass, MotionVectorPrepass, ViewPrepassTextures},
prepass::{AnimatedMeshMotionVectors, DepthPrepass, MotionVectorPrepass, ViewPrepassTextures},
};
use bevy_app::{App, Plugin};
use bevy_asset::{load_internal_asset, Handle};
Expand Down Expand Up @@ -54,6 +54,7 @@ impl Plugin for TemporalAntiAliasPlugin {
};
render_app
.init_resource::<SpecializedRenderPipelines<TaaPipeline>>()
.insert_resource(AnimatedMeshMotionVectors(true))
.add_systems(ExtractSchedule, extract_taa_settings)
.add_systems(
Render,
Expand Down Expand Up @@ -123,8 +124,6 @@ pub struct TemporalAntiAliasBundle {
///
/// [Currently](https://github.com/bevyengine/bevy/issues/8423) cannot be used with [`bevy_render::camera::OrthographicProjection`].
///
/// Currently does not support skinned meshes and morph targets.
/// There will probably be ghosting artifacts if used with them.
/// Does not work well with alpha-blended meshes as it requires depth writing to determine motion.
///
/// It is very important that correct motion vectors are written for everything on screen.
Expand Down
21 changes: 15 additions & 6 deletions crates/bevy_pbr/src/prepass/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -438,13 +438,17 @@ where
shader_defs.push("PREPASS_FRAGMENT".into());
}

let bind_group = setup_morph_and_skinning_defs(
let (bind_group, animated_mesh_motion_vectors) = setup_morph_and_skinning(
&self.mesh_layouts,
layout,
5,
&key.mesh_key,
&mut shader_defs,
&mut vertex_attributes,
key.mesh_key
.contains(MeshPipelineKey::ANIMATED_SKIN_MOTION_VECTORS),
key.mesh_key
.contains(MeshPipelineKey::ANIMATED_MORPH_MOTION_VECTORS),
);
bind_group_layouts.insert(1, bind_group);

Expand Down Expand Up @@ -535,11 +539,7 @@ where
};

let mut push_constant_ranges = Vec::with_capacity(1);
if cfg!(all(
feature = "webgl",
target_arch = "wasm32",
not(feature = "webgpu")
)) {
if animated_mesh_motion_vectors {
push_constant_ranges.push(PushConstantRange {
stages: ShaderStages::VERTEX,
range: 0..4,
Expand Down Expand Up @@ -712,6 +712,8 @@ pub fn queue_prepass_material_meshes<M: Material>(
render_materials: Res<RenderAssets<PreparedMaterial<M>>>,
render_material_instances: Res<RenderMaterialInstances<M>>,
render_lightmaps: Res<RenderLightmaps>,
skins: Res<SkinUniform>,
morphs: Res<MorphUniform>,
mut views: Query<
(
&ExtractedView,
Expand Down Expand Up @@ -833,6 +835,13 @@ pub fn queue_prepass_material_meshes<M: Material>(
mesh_key |= MeshPipelineKey::LIGHTMAPPED;
}

if skins.previous_buffer.is_some() && motion_vector_prepass.is_some() {
mesh_key |= MeshPipelineKey::ANIMATED_SKIN_MOTION_VECTORS;
}
if morphs.previous_buffer.is_some() && motion_vector_prepass.is_some() {
mesh_key |= MeshPipelineKey::ANIMATED_MORPH_MOTION_VECTORS;
}

let pipeline_id = pipelines.specialize(
&pipeline_cache,
&prepass_pipeline,
Expand Down
7 changes: 7 additions & 0 deletions crates/bevy_pbr/src/prepass/prepass.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,14 @@ fn vertex(vertex_no_morph: Vertex) -> VertexOutput {
#ifdef MOTION_VECTOR_PREPASS
// Use vertex_no_morph.instance_index instead of vertex.instance_index to work around a wgpu dx12 bug.
// See https://github.com/gfx-rs/naga/issues/2416
#ifdef ANIMATED_MESH_MOTION_VECTORS
// TODO: Account for previous skin, morph, or skin+morph
#else
out.previous_world_position = mesh_functions::mesh_position_local_to_world(
mesh_functions::get_previous_model_matrix(vertex_no_morph.instance_index),
vec4<f32>(vertex.position, 1.0)
);
#endif // ANIMATED_MESH_MOTION_VECTORS
#endif // MOTION_VECTOR_PREPASS

#ifdef VERTEX_OUTPUT_INSTANCE_INDEX
Expand Down Expand Up @@ -136,6 +140,9 @@ fn fragment(in: VertexOutput) -> FragmentOutput {
// range -2,2, so this needs to be scaled by 0.5. And the V direction goes
// down where clip space y goes up, so y needs to be flipped.
out.motion_vector = (clip_position - previous_clip_position) * vec2(0.5, -0.5);
#ifdef ANIMATED_MESH_MOTION_VECTORS
out.motion_vector *= prepass_bindings::motion_vectors_mask;
#endif // ANIMATED_MESH_MOTION_VECTORS
#endif // MOTION_VECTOR_PREPASS

#ifdef DEFERRED_PREPASS
Expand Down
5 changes: 5 additions & 0 deletions crates/bevy_pbr/src/prepass/prepass_bindings.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,9 @@ struct PreviousViewUniforms {
@group(0) @binding(2) var<uniform> previous_view_uniforms: PreviousViewUniforms;
#endif // MOTION_VECTOR_PREPASS

// Zero if the current mesh did not have skin/morph data available last frame, else one
#ifdef ANIMATED_MESH_MOTION_VECTORS
var<push_constant> motion_vectors_mask: f32;
#endif

// Material bindings will be in @group(2)
Loading
Loading