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

Fix motion vector computation after #17688. #17717

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions crates/bevy_pbr/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ bevy_asset = { path = "../bevy_asset", version = "0.16.0-dev" }
bevy_color = { path = "../bevy_color", version = "0.16.0-dev" }
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.16.0-dev" }
bevy_derive = { path = "../bevy_derive", version = "0.16.0-dev" }
bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.16.0-dev" }
bevy_ecs = { path = "../bevy_ecs", version = "0.16.0-dev" }
bevy_image = { path = "../bevy_image", version = "0.16.0-dev" }
bevy_math = { path = "../bevy_math", version = "0.16.0-dev" }
Expand Down
1 change: 0 additions & 1 deletion crates/bevy_pbr/src/meshlet/instance_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ impl InstanceManager {
None,
None,
None,
None,
);

// Append instance data
Expand Down
23 changes: 12 additions & 11 deletions crates/bevy_pbr/src/render/gpu_preprocess.rs
Original file line number Diff line number Diff line change
Expand Up @@ -626,12 +626,10 @@ impl Node for EarlyGpuPreprocessNode {
continue;
};

// If we're drawing indirectly, make sure the mesh preprocessing
// shader has access to the view info it needs to do culling.
let mut dynamic_offsets: SmallVec<[u32; 1]> = smallvec![];
if !no_indirect_drawing {
dynamic_offsets.push(view_uniform_offset.offset);
}
// Make sure the mesh preprocessing shader has access to the
// view info it needs to do culling and motion vector
// computation.
let dynamic_offsets = [view_uniform_offset.offset];

// Are we drawing directly or indirectly?
match *phase_bind_groups {
Expand Down Expand Up @@ -1317,6 +1315,11 @@ fn preprocess_direct_bind_group_layout_entries() -> DynamicBindGroupLayoutEntrie
DynamicBindGroupLayoutEntries::new_with_indices(
ShaderStages::COMPUTE,
(
// `view`
(
0,
uniform_buffer::<ViewUniform>(/* has_dynamic_offset= */ true),
),
// `current_input`
(3, storage_buffer_read_only::<MeshInputUniform>(false)),
// `previous_input`
Expand Down Expand Up @@ -1361,11 +1364,6 @@ fn gpu_culling_bind_group_layout_entries() -> DynamicBindGroupLayoutEntries {
8,
storage_buffer_read_only::<MeshCullingData>(/* has_dynamic_offset= */ false),
),
// `view`
(
0,
uniform_buffer::<ViewUniform>(/* has_dynamic_offset= */ true),
),
))
}

Expand Down Expand Up @@ -1802,11 +1800,14 @@ impl<'a> PreprocessBindGroupBuilder<'a> {
)
.ok();

let view_uniforms_binding = self.view_uniforms.uniforms.binding()?;

Some(PhasePreprocessBindGroups::Direct(
self.render_device.create_bind_group(
"preprocess_direct_bind_group",
&self.pipelines.direct_preprocess.bind_group_layout,
&BindGroupEntries::with_indices((
(0, view_uniforms_binding),
(3, self.current_input_buffer.as_entire_binding()),
(4, self.previous_input_buffer.as_entire_binding()),
(
Expand Down
26 changes: 18 additions & 8 deletions crates/bevy_pbr/src/render/mesh.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::material_bind_groups::{MaterialBindGroupIndex, MaterialBindGroupSlot};
use crate::{
material_bind_groups::{MaterialBindGroupIndex, MaterialBindGroupSlot},
skin::mark_meshes_as_changed_if_their_skins_changed,
};
use allocator::MeshAllocator;
use bevy_asset::{load_internal_asset, AssetId, UntypedAssetId};
use bevy_core_pipeline::{
Expand All @@ -8,6 +11,7 @@ use bevy_core_pipeline::{
prepass::MotionVectorPrepass,
};
use bevy_derive::{Deref, DerefMut};
use bevy_diagnostic::FrameCount;
use bevy_ecs::{
prelude::*,
query::ROQueryItem,
Expand Down Expand Up @@ -163,7 +167,13 @@ impl Plugin for MeshRenderPlugin {

app.add_systems(
PostUpdate,
(no_automatic_skin_batching, no_automatic_morph_batching),
(
no_automatic_skin_batching,
no_automatic_morph_batching,
mark_meshes_as_changed_if_their_skins_changed
.ambiguous_with_all()
.after(mark_3d_meshes_as_changed_if_their_assets_changed),
),
)
.add_plugins((
BinnedRenderPhasePlugin::<Opaque3d, MeshPipeline>::default(),
Expand Down Expand Up @@ -536,17 +546,15 @@ pub struct MeshInputUniform {
pub index_count: u32,
/// The current skin index, or `u32::MAX` if there's no skin.
pub current_skin_index: u32,
/// The previous skin index, or `u32::MAX` if there's no previous skin.
pub previous_skin_index: u32,
/// The material and lightmap indices, packed into 32 bits.
///
/// Low 16 bits: index of the material inside the bind group data.
/// High 16 bits: index of the lightmap in the binding array.
pub material_and_lightmap_bind_group_slot: u32,
pub timestamp: u32,
/// User supplied tag to identify this mesh instance.
Copy link
Contributor

Choose a reason for hiding this comment

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

Why call it timestamp if it's a frame count?

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe frame_count_when_updated or something like that? That seems to be the semantics of it.

pub tag: u32,
/// Padding.
pub pad: u32,
}

/// Information about each mesh instance needed to cull it on GPU.
Expand Down Expand Up @@ -1104,6 +1112,7 @@ impl RenderMeshInstanceGpuBuilder {
render_material_bindings: &RenderMaterialBindings,
render_lightmaps: &RenderLightmaps,
skin_indices: &SkinIndices,
timestamp: FrameCount,
) -> u32 {
let (first_vertex_index, vertex_count) =
match mesh_allocator.mesh_vertex_slice(&self.shared.mesh_asset_id) {
Expand All @@ -1122,7 +1131,6 @@ impl RenderMeshInstanceGpuBuilder {
),
None => (false, 0, 0),
};

let current_skin_index = match skin_indices.current.get(&entity) {
Some(skin_indices) => skin_indices.index(),
None => u32::MAX,
Expand Down Expand Up @@ -1156,6 +1164,7 @@ impl RenderMeshInstanceGpuBuilder {
lightmap_uv_rect: self.lightmap_uv_rect,
flags: self.mesh_flags.bits(),
previous_input_index: u32::MAX,
timestamp: timestamp.0,
first_vertex_index,
first_index_index,
index_count: if mesh_is_indexed {
Expand All @@ -1169,7 +1178,6 @@ impl RenderMeshInstanceGpuBuilder {
self.shared.material_bindings_index.slot,
) | ((lightmap_slot as u32) << 16),
tag: self.shared.tag,
pad: 0,
};

// Did the last frame contain this entity as well?
Expand Down Expand Up @@ -1595,6 +1603,7 @@ pub fn collect_meshes_for_gpu_building(
render_material_bindings: Res<RenderMaterialBindings>,
render_lightmaps: Res<RenderLightmaps>,
skin_indices: Res<SkinIndices>,
frame_count: Res<FrameCount>,
) {
let RenderMeshInstances::GpuBuilding(ref mut render_mesh_instances) =
render_mesh_instances.into_inner()
Expand Down Expand Up @@ -1634,6 +1643,7 @@ pub fn collect_meshes_for_gpu_building(
&render_material_bindings,
&render_lightmaps,
&skin_indices,
*frame_count,
);
}

Expand Down Expand Up @@ -1661,6 +1671,7 @@ pub fn collect_meshes_for_gpu_building(
&render_material_bindings,
&render_lightmaps,
&skin_indices,
*frame_count,
);
mesh_culling_builder
.update(&mut mesh_culling_data_buffer, instance_data_index as usize);
Expand Down Expand Up @@ -1843,7 +1854,6 @@ impl GetBatchData for MeshPipeline {

let current_skin_index = skin_indices.current.get(&main_entity).map(SkinIndex::index);
let previous_skin_index = skin_indices.prev.get(&main_entity).map(SkinIndex::index);

let material_bind_group_index = mesh_instance.material_bindings_index;

Some((
Expand Down
18 changes: 14 additions & 4 deletions crates/bevy_pbr/src/render/mesh_preprocess.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -192,18 +192,28 @@ fn main(@builtin(global_invocation_id) global_invocation_id: vec3<u32>) {
}
#endif

// Was the mesh transform updated this frame?
let timestamp = current_input[input_index].timestamp;
let mesh_changed_this_frame = timestamp == view.frame_count;

// Look up the previous model matrix.
let previous_input_index = current_input[input_index].previous_input_index;
var previous_world_from_local_affine_transpose: mat3x4<f32>;
if (previous_input_index == 0xffffffff) {
previous_world_from_local_affine_transpose = world_from_local_affine_transpose;
} else {
if (mesh_changed_this_frame && previous_input_index != 0xffffffffu) {
previous_world_from_local_affine_transpose =
previous_input[previous_input_index].world_from_local;
} else {
previous_world_from_local_affine_transpose = world_from_local_affine_transpose;
}
let previous_world_from_local =
maths::affine3_to_square(previous_world_from_local_affine_transpose);

let previous_skin_index = select(
0xffffffffu,
current_input[input_index].previous_skin_index,
mesh_changed_this_frame
);

// Occlusion cull if necessary. This is done by calculating the screen-space
// axis-aligned bounding box (AABB) of the mesh and testing it against the
// appropriate level of the depth pyramid (a.k.a. hierarchical Z-buffer). If
Expand Down Expand Up @@ -342,7 +352,7 @@ fn main(@builtin(global_invocation_id) global_invocation_id: vec3<u32>) {
output[mesh_output_index].lightmap_uv_rect = current_input[input_index].lightmap_uv_rect;
output[mesh_output_index].first_vertex_index = current_input[input_index].first_vertex_index;
output[mesh_output_index].current_skin_index = current_input[input_index].current_skin_index;
output[mesh_output_index].previous_skin_index = current_input[input_index].previous_skin_index;
output[mesh_output_index].previous_skin_index = previous_skin_index;
output[mesh_output_index].material_and_lightmap_bind_group_slot =
current_input[input_index].material_and_lightmap_bind_group_slot;
output[mesh_output_index].tag = current_input[input_index].tag;
Expand Down
18 changes: 17 additions & 1 deletion crates/bevy_pbr/src/render/skin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::sync::OnceLock;
use bevy_asset::Assets;
use bevy_ecs::prelude::*;
use bevy_math::Mat4;
use bevy_render::mesh::Mesh3d;
use bevy_render::sync_world::MainEntityHashMap;
use bevy_render::{
batching::NoAutomaticBatching,
Expand All @@ -25,7 +26,7 @@ use bevy_transform::prelude::GlobalTransform;
pub const MAX_JOINTS: usize = 256;

/// The location of the first joint matrix in the skin uniform buffer.
#[derive(Component)]
#[derive(Component, Clone, Copy)]
pub struct SkinIndex {
/// The byte offset of the first joint matrix.
pub byte_offset: u32,
Expand Down Expand Up @@ -232,3 +233,18 @@ pub fn no_automatic_skin_batching(
commands.entity(entity).try_insert(NoAutomaticBatching);
}
}

pub fn mark_meshes_as_changed_if_their_skins_changed(
Copy link
Contributor

Choose a reason for hiding this comment

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

For consistency:

Suggested change
pub fn mark_meshes_as_changed_if_their_skins_changed(
pub fn mark_3d_meshes_as_changed_if_their_skins_changed(

It would be nice to port all this to 2D as well... :)

mut skinned_meshes_query: Query<(&mut Mesh3d, &SkinnedMesh)>,
changed_joints_query: Query<Entity, Changed<GlobalTransform>>,
) {
for (mut mesh, skinned_mesh) in &mut skinned_meshes_query {
if skinned_mesh
.joints
.iter()
.any(|&joint| changed_joints_query.contains(joint))
{
mesh.set_changed();
}
}
}
16 changes: 10 additions & 6 deletions crates/bevy_pbr/src/render/skinning.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn skin_model(
+ weights.z * joint_matrices.data[indexes.z]
+ weights.w * joint_matrices.data[indexes.w];
#else // SKINS_USE_UNIFORM_BUFFERS
let skin_index = mesh[instance_index].current_skin_index;
var skin_index = mesh[instance_index].current_skin_index;
return weights.x * joint_matrices[skin_index + indexes.x]
+ weights.y * joint_matrices[skin_index + indexes.y]
+ weights.z * joint_matrices[skin_index + indexes.z]
Expand All @@ -57,11 +57,15 @@ fn skin_prev_model(
+ weights.z * prev_joint_matrices.data[indexes.z]
+ weights.w * prev_joint_matrices.data[indexes.w];
#else // SKINS_USE_UNIFORM_BUFFERS
let skin_index = mesh[instance_index].previous_skin_index;
return weights.x * prev_joint_matrices[skin_index + indexes.x]
+ weights.y * prev_joint_matrices[skin_index + indexes.y]
+ weights.z * prev_joint_matrices[skin_index + indexes.z]
+ weights.w * prev_joint_matrices[skin_index + indexes.w];
let prev_skin_index = mesh[instance_index].previous_skin_index;
if (prev_skin_index == 0xffffffffu) {
return skin_model(indexed, weights, instance_index);
}

return weights.x * prev_joint_matrices[prev_skin_index + indexes.x]
+ weights.y * prev_joint_matrices[prev_skin_index + indexes.y]
+ weights.z * prev_joint_matrices[prev_skin_index + indexes.z]
+ weights.w * prev_joint_matrices[prev_skin_index + indexes.w];
#endif // SKINS_USE_UNIFORM_BUFFERS
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ struct MeshInput {
// Low 16 bits: index of the material inside the bind group data.
// High 16 bits: index of the lightmap in the binding array.
material_and_lightmap_bind_group_slot: u32,
timestamp: u32,
// User supplied index to identify the mesh instance
tag: u32,
pad: u32,
}

// The `wgpu` indirect parameters structure. This is a union of two structures.
Expand Down
5 changes: 5 additions & 0 deletions crates/bevy_render/src/render_resource/buffer_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ impl<T: NoUninit> RawBufferVec<T> {
self.values.append(&mut other.values);
}

/// Returns the value at the given index.
pub fn get(&self, index: u32) -> Option<&T> {
self.values.get(index as usize)
}

/// Sets the value at the given index.
///
/// The index must be less than [`RawBufferVec::len`].
Expand Down
4 changes: 4 additions & 0 deletions crates/bevy_render/src/view/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod visibility;
pub mod window;

use bevy_asset::{load_internal_asset, weak_handle, Handle};
use bevy_diagnostic::FrameCount;
pub use visibility::*;
pub use window::*;

Expand Down Expand Up @@ -568,6 +569,7 @@ pub struct ViewUniform {
pub frustum: [Vec4; 6],
pub color_grading: ColorGradingUniform,
pub mip_bias: f32,
pub frame_count: u32,
}

#[derive(Resource)]
Expand Down Expand Up @@ -889,6 +891,7 @@ pub fn prepare_view_uniforms(
Option<&TemporalJitter>,
Option<&MipBias>,
)>,
frame_count: Res<FrameCount>,
) {
let view_iter = views.iter();
let view_count = view_iter.len();
Expand Down Expand Up @@ -942,6 +945,7 @@ pub fn prepare_view_uniforms(
frustum,
color_grading: extracted_view.color_grading.clone().into(),
mip_bias: mip_bias.unwrap_or(&MipBias(0.0)).0,
frame_count: frame_count.0,
}),
};

Expand Down
1 change: 1 addition & 0 deletions crates/bevy_render/src/view/view.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,5 @@ struct View {
frustum: array<vec4<f32>, 6>,
color_grading: ColorGrading,
mip_bias: f32,
frame_count: u32,
};
Loading