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

Implement motion vectors and TAA for skinned meshes and meshes with morph targets. #13572

Merged
merged 4 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
8 changes: 8 additions & 0 deletions crates/bevy_pbr/src/deferred/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,14 @@ impl SpecializedRenderPipeline for DeferredLightingLayout {
shader_defs.push("SCREEN_SPACE_REFLECTIONS".into());
}

if key.contains(MeshPipelineKey::HAVE_PREVIOUS_SKIN) {
shader_defs.push("HAVE_PREVIOUS_SKIN".into());
}

if key.contains(MeshPipelineKey::HAVE_PREVIOUS_MORPH) {
shader_defs.push("HAVE_PREVIOUS_MORPH".into());
}

// Always true, since we're in the deferred lighting pipeline
shader_defs.push("DEFERRED_PREPASS".into());

Expand Down
14 changes: 14 additions & 0 deletions crates/bevy_pbr/src/material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,20 @@ pub fn queue_material_meshes<M: Material>(
mesh_key |= MeshPipelineKey::VISIBILITY_RANGE_DITHER;
}

// If the previous frame have skins or morph targets, note that.
if mesh_instance
.flags
.contains(RenderMeshInstanceFlags::HAVE_PREVIOUS_SKIN)
{
mesh_key |= MeshPipelineKey::HAVE_PREVIOUS_SKIN;
}
if mesh_instance
.flags
.contains(RenderMeshInstanceFlags::HAVE_PREVIOUS_MORPH)
{
mesh_key |= MeshPipelineKey::HAVE_PREVIOUS_MORPH;
}

let pipeline_id = pipelines.specialize(
&pipeline_cache,
&material_pipeline,
Expand Down
22 changes: 22 additions & 0 deletions crates/bevy_pbr/src/prepass/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,14 @@ where
shader_defs.push("MOTION_VECTOR_PREPASS".into());
}

if key.mesh_key.contains(MeshPipelineKey::HAVE_PREVIOUS_SKIN) {
shader_defs.push("HAVE_PREVIOUS_SKIN".into());
}

if key.mesh_key.contains(MeshPipelineKey::HAVE_PREVIOUS_MORPH) {
shader_defs.push("HAVE_PREVIOUS_MORPH".into());
}

if key.mesh_key.intersects(
MeshPipelineKey::NORMAL_PREPASS
| MeshPipelineKey::MOTION_VECTOR_PREPASS
Expand Down Expand Up @@ -853,6 +861,20 @@ pub fn queue_prepass_material_meshes<M: Material>(
mesh_key |= MeshPipelineKey::LIGHTMAPPED;
}

// If the previous frame have skins or morph targets, note that.
if mesh_instance
.flags
.contains(RenderMeshInstanceFlags::HAVE_PREVIOUS_SKIN)
{
mesh_key |= MeshPipelineKey::HAVE_PREVIOUS_SKIN;
}
if mesh_instance
.flags
.contains(RenderMeshInstanceFlags::HAVE_PREVIOUS_MORPH)
{
mesh_key |= MeshPipelineKey::HAVE_PREVIOUS_MORPH;
}

let pipeline_id = pipelines.specialize(
&pipeline_cache,
&prepass_pipeline,
Expand Down
59 changes: 54 additions & 5 deletions crates/bevy_pbr/src/prepass/prepass.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,26 @@ fn morph_vertex(vertex_in: Vertex) -> Vertex {
}
return vertex;
}
#endif

// Returns the morphed position of the given vertex from the previous frame.
//
// This function is used for motion vector calculation, and, as such, it doesn't
// bother morphing the normals and tangents.
fn morph_prev_vertex(vertex_in: Vertex) -> Vertex {
var vertex = vertex_in;
let weight_count = morph::layer_count();
for (var i: u32 = 0u; i < weight_count; i ++) {
let weight = morph::prev_weight_at(i);
if weight == 0.0 {
continue;
}
vertex.position += weight * morph::morph(vertex.index, morph::position_offset, i);
// Don't bother morphing normals and tangents; we don't need them for
// motion vector calculation.
}
return vertex;
}
#endif // MORPH_TARGETS

@vertex
fn vertex(vertex_no_morph: Vertex) -> VertexOutput {
Expand Down Expand Up @@ -93,12 +112,42 @@ fn vertex(vertex_no_morph: Vertex) -> VertexOutput {
out.color = vertex.color;
#endif

// Compute the motion vector, for TAA. For this we need to know where the
pcwalton marked this conversation as resolved.
Show resolved Hide resolved
// vertex was last frame.
#ifdef MOTION_VECTOR_PREPASS
// Use vertex_no_morph.instance_index instead of vertex.instance_index to work around a wgpu dx12 bug.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the vertex_no_morph.instance_index workaround no longer valid?

Copy link
Contributor Author

@pcwalton pcwalton May 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just tried animated_fox with TAA enabled on the Direct3D 12 backend and it works fine. I guess whatever the issue was is now fixed. Or my changes to the shaders perturbed the bug out of existence.

// See https://github.com/gfx-rs/naga/issues/2416

// Take morph targets into account.
#ifdef MORPH_TARGETS

#ifdef HAVE_PREVIOUS_MORPH
let prev_vertex = morph_prev_vertex(vertex_no_morph);
#else // HAVE_PREVIOUS_MORPH
let prev_vertex = vertex_no_morph;
#endif // HAVE_PREVIOUS_MORPH

#else // MORPH_TARGETS
let prev_vertex = vertex_no_morph;
#endif // MORPH_TARGETS

// Take skinning into account.
#ifdef SKINNED

#ifdef HAVE_PREVIOUS_SKIN
let prev_model = skinning::skin_prev_model(
prev_vertex.joint_indices,
prev_vertex.joint_weights,
);
#else // HAVE_PREVIOUS_SKIN
let prev_model = mesh_functions::get_previous_model_matrix(prev_vertex.instance_index);
#endif // HAVE_PREVIOUS_SKIN

#else // SKINNED
let prev_model = mesh_functions::get_previous_model_matrix(prev_vertex.instance_index);
#endif // SKINNED

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)
prev_model,
vec4<f32>(prev_vertex.position, 1.0)
);
#endif // MOTION_VECTOR_PREPASS

Expand Down
Loading