Add previous_view_uniforms.inverse_view (#12902)

# Objective
- Upload previous frame's inverse_view matrix to the GPU for use with
https://github.com/bevyengine/bevy/pull/12898.

---

## Changelog
- Added `prepass_bindings::previous_view_uniforms.inverse_view`.
- Renamed `prepass_bindings::previous_view_proj` to
`prepass_bindings::previous_view_uniforms.view_proj`.
- Renamed `PreviousViewProjectionUniformOffset` to
`PreviousViewUniformOffset`.
- Renamed `PreviousViewProjection` to `PreviousViewData`.

## Migration Guide
- Renamed `prepass_bindings::previous_view_proj` to
`prepass_bindings::previous_view_uniforms.view_proj`.
- Renamed `PreviousViewProjectionUniformOffset` to
`PreviousViewUniformOffset`.
- Renamed `PreviousViewProjection` to `PreviousViewData`.
This commit is contained in:
JMS55 2024-04-07 14:59:16 -04:00 committed by GitHub
parent 452821dd52
commit 31b5943ad4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 67 additions and 64 deletions

View file

@ -7,8 +7,8 @@ use super::{
MeshletGpuScene,
};
use crate::{
MeshViewBindGroup, PrepassViewBindGroup, PreviousViewProjectionUniformOffset,
ViewFogUniformOffset, ViewLightProbesUniformOffset, ViewLightsUniformOffset,
MeshViewBindGroup, PrepassViewBindGroup, PreviousViewUniformOffset, ViewFogUniformOffset,
ViewLightProbesUniformOffset, ViewLightsUniformOffset,
};
use bevy_core_pipeline::prepass::ViewPrepassTextures;
use bevy_ecs::{query::QueryItem, world::World};
@ -135,7 +135,7 @@ impl ViewNode for MeshletPrepassNode {
&'static ExtractedCamera,
&'static ViewPrepassTextures,
&'static ViewUniformOffset,
Option<&'static PreviousViewProjectionUniformOffset>,
Option<&'static PreviousViewUniformOffset>,
&'static MeshletViewMaterialsPrepass,
&'static MeshletViewBindGroups,
&'static MeshletViewResources,
@ -149,7 +149,7 @@ impl ViewNode for MeshletPrepassNode {
camera,
view_prepass_textures,
view_uniform_offset,
previous_view_projection_uniform_offset,
previous_view_uniform_offset,
meshlet_view_materials,
meshlet_view_bind_groups,
meshlet_view_resources,
@ -209,15 +209,13 @@ impl ViewNode for MeshletPrepassNode {
render_pass.set_camera_viewport(viewport);
}
if let Some(previous_view_projection_uniform_offset) =
previous_view_projection_uniform_offset
{
if let Some(previous_view_uniform_offset) = previous_view_uniform_offset {
render_pass.set_bind_group(
0,
prepass_view_bind_group.motion_vectors.as_ref().unwrap(),
&[
view_uniform_offset.offset,
previous_view_projection_uniform_offset.offset,
previous_view_uniform_offset.offset,
],
);
} else {
@ -258,7 +256,7 @@ impl ViewNode for MeshletDeferredGBufferPrepassNode {
&'static ExtractedCamera,
&'static ViewPrepassTextures,
&'static ViewUniformOffset,
Option<&'static PreviousViewProjectionUniformOffset>,
Option<&'static PreviousViewUniformOffset>,
&'static MeshletViewMaterialsDeferredGBufferPrepass,
&'static MeshletViewBindGroups,
&'static MeshletViewResources,
@ -272,7 +270,7 @@ impl ViewNode for MeshletDeferredGBufferPrepassNode {
camera,
view_prepass_textures,
view_uniform_offset,
previous_view_projection_uniform_offset,
previous_view_uniform_offset,
meshlet_view_materials,
meshlet_view_bind_groups,
meshlet_view_resources,
@ -337,15 +335,13 @@ impl ViewNode for MeshletDeferredGBufferPrepassNode {
render_pass.set_camera_viewport(viewport);
}
if let Some(previous_view_projection_uniform_offset) =
previous_view_projection_uniform_offset
{
if let Some(previous_view_uniform_offset) = previous_view_uniform_offset {
render_pass.set_bind_group(
0,
prepass_view_bind_group.motion_vectors.as_ref().unwrap(),
&[
view_uniform_offset.offset,
previous_view_projection_uniform_offset.offset,
previous_view_uniform_offset.offset,
],
);
} else {

View file

@ -22,7 +22,7 @@
#ifdef PREPASS_FRAGMENT
#ifdef MOTION_VECTOR_PREPASS
#import bevy_pbr::{
prepass_bindings::previous_view_proj,
prepass_bindings::previous_view_uniforms,
pbr_prepass_functions::calculate_motion_vector,
}
#endif
@ -153,9 +153,9 @@ fn resolve_vertex_output(frag_coord: vec4<f32>) -> VertexOutput {
let previous_world_position_1 = mesh_position_local_to_world(previous_model, vec4(vertex_1.position, 1.0));
let previous_world_position_2 = mesh_position_local_to_world(previous_model, vec4(vertex_2.position, 1.0));
let previous_world_position_3 = mesh_position_local_to_world(previous_model, vec4(vertex_3.position, 1.0));
let previous_clip_position_1 = previous_view_proj * vec4(previous_world_position_1.xyz, 1.0);
let previous_clip_position_2 = previous_view_proj * vec4(previous_world_position_2.xyz, 1.0);
let previous_clip_position_3 = previous_view_proj * vec4(previous_world_position_3.xyz, 1.0);
let previous_clip_position_1 = previous_view_uniforms.view_proj * vec4(previous_world_position_1.xyz, 1.0);
let previous_clip_position_2 = previous_view_uniforms.view_proj * vec4(previous_world_position_2.xyz, 1.0);
let previous_clip_position_3 = previous_view_uniforms.view_proj * vec4(previous_world_position_3.xyz, 1.0);
let previous_partial_derivatives = compute_partial_derivatives(
array(previous_clip_position_1, previous_clip_position_2, previous_clip_position_3),
frag_coord_ndc,

View file

@ -143,7 +143,7 @@ where
PreUpdate,
(
update_mesh_previous_global_transforms,
update_previous_view_projections,
update_previous_view_data,
),
);
}
@ -154,7 +154,7 @@ where
if no_prepass_plugin_loaded {
render_app
.add_systems(ExtractSchedule, extract_camera_previous_view_projection)
.add_systems(ExtractSchedule, extract_camera_previous_view_data)
.add_systems(
Render,
(
@ -163,7 +163,7 @@ where
sort_binned_render_phase::<AlphaMask3dPrepass>
).in_set(RenderSet::PhaseSort),
(
prepare_previous_view_projection_uniforms,
prepare_previous_view_uniforms,
batch_and_prepare_binned_render_phase::<Opaque3dPrepass, MeshPipeline>,
batch_and_prepare_binned_render_phase::<AlphaMask3dPrepass,
MeshPipeline>,
@ -201,17 +201,20 @@ where
struct AnyPrepassPluginLoaded;
#[derive(Component, ShaderType, Clone)]
pub struct PreviousViewProjection {
pub struct PreviousViewData {
pub inverse_view: Mat4,
pub view_proj: Mat4,
}
pub fn update_previous_view_projections(
pub fn update_previous_view_data(
mut commands: Commands,
query: Query<(Entity, &Camera, &GlobalTransform), (With<Camera3d>, With<MotionVectorPrepass>)>,
) {
for (entity, camera, camera_transform) in &query {
commands.entity(entity).try_insert(PreviousViewProjection {
view_proj: camera.projection_matrix() * camera_transform.compute_matrix().inverse(),
let inverse_view = camera_transform.compute_matrix().inverse();
commands.entity(entity).try_insert(PreviousViewData {
inverse_view,
view_proj: camera.projection_matrix() * inverse_view,
});
}
}
@ -263,8 +266,8 @@ impl<M: Material> FromWorld for PrepassPipeline<M> {
uniform_buffer::<ViewUniform>(true),
// Globals
uniform_buffer::<GlobalsUniform>(false),
// PreviousViewProjection
uniform_buffer::<PreviousViewProjection>(true),
// PreviousViewUniforms
uniform_buffer::<PreviousViewData>(true),
),
),
);
@ -603,16 +606,16 @@ where
}
// Extract the render phases for the prepass
pub fn extract_camera_previous_view_projection(
pub fn extract_camera_previous_view_data(
mut commands: Commands,
cameras_3d: Extract<Query<(Entity, &Camera, Option<&PreviousViewProjection>), With<Camera3d>>>,
cameras_3d: Extract<Query<(Entity, &Camera, Option<&PreviousViewData>), With<Camera3d>>>,
) {
for (entity, camera, maybe_previous_view_proj) in cameras_3d.iter() {
for (entity, camera, maybe_previous_view_data) in cameras_3d.iter() {
if camera.is_active {
let mut entity = commands.get_or_spawn(entity);
if let Some(previous_view) = maybe_previous_view_proj {
entity.insert(previous_view.clone());
if let Some(previous_view_data) = maybe_previous_view_data {
entity.insert(previous_view_data.clone());
}
}
}
@ -620,23 +623,20 @@ pub fn extract_camera_previous_view_projection(
#[derive(Resource, Default)]
pub struct PreviousViewProjectionUniforms {
pub uniforms: DynamicUniformBuffer<PreviousViewProjection>,
pub uniforms: DynamicUniformBuffer<PreviousViewData>,
}
#[derive(Component)]
pub struct PreviousViewProjectionUniformOffset {
pub struct PreviousViewUniformOffset {
pub offset: u32,
}
pub fn prepare_previous_view_projection_uniforms(
pub fn prepare_previous_view_uniforms(
mut commands: Commands,
render_device: Res<RenderDevice>,
render_queue: Res<RenderQueue>,
mut view_uniforms: ResMut<PreviousViewProjectionUniforms>,
views: Query<
(Entity, &ExtractedView, Option<&PreviousViewProjection>),
With<MotionVectorPrepass>,
>,
views: Query<(Entity, &ExtractedView, Option<&PreviousViewData>), With<MotionVectorPrepass>>,
) {
let views_iter = views.iter();
let view_count = views_iter.len();
@ -647,18 +647,22 @@ pub fn prepare_previous_view_projection_uniforms(
else {
return;
};
for (entity, camera, maybe_previous_view_proj) in views_iter {
let view_projection = match maybe_previous_view_proj {
for (entity, camera, maybe_previous_view_uniforms) in views_iter {
let view_projection = match maybe_previous_view_uniforms {
Some(previous_view) => previous_view.clone(),
None => PreviousViewProjection {
view_proj: camera.projection * camera.transform.compute_matrix().inverse(),
},
None => {
let inverse_view = camera.transform.compute_matrix().inverse();
PreviousViewData {
inverse_view,
view_proj: camera.projection * inverse_view,
}
}
};
commands
.entity(entity)
.insert(PreviousViewProjectionUniformOffset {
offset: writer.write(&view_projection),
});
commands.entity(entity).insert(PreviousViewUniformOffset {
offset: writer.write(&view_projection),
});
}
}
@ -673,7 +677,7 @@ pub fn prepare_prepass_view_bind_group<M: Material>(
prepass_pipeline: Res<PrepassPipeline<M>>,
view_uniforms: Res<ViewUniforms>,
globals_buffer: Res<GlobalsBuffer>,
previous_view_proj_uniforms: Res<PreviousViewProjectionUniforms>,
previous_view_uniforms: Res<PreviousViewProjectionUniforms>,
mut prepass_view_bind_group: ResMut<PrepassViewBindGroup>,
) {
if let (Some(view_binding), Some(globals_binding)) = (
@ -686,14 +690,14 @@ pub fn prepare_prepass_view_bind_group<M: Material>(
&BindGroupEntries::sequential((view_binding.clone(), globals_binding.clone())),
));
if let Some(previous_view_proj_binding) = previous_view_proj_uniforms.uniforms.binding() {
if let Some(previous_view_uniforms_binding) = previous_view_uniforms.uniforms.binding() {
prepass_view_bind_group.motion_vectors = Some(render_device.create_bind_group(
"prepass_view_motion_vectors_bind_group",
&prepass_pipeline.view_layout_motion_vectors,
&BindGroupEntries::sequential((
view_binding,
globals_binding,
previous_view_proj_binding,
previous_view_uniforms_binding,
)),
));
}
@ -918,16 +922,16 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetPrepassViewBindGroup<
type Param = SRes<PrepassViewBindGroup>;
type ViewQuery = (
Read<ViewUniformOffset>,
Option<Read<PreviousViewProjectionUniformOffset>>,
Option<Read<PreviousViewUniformOffset>>,
);
type ItemQuery = ();
#[inline]
fn render<'w>(
_item: &P,
(view_uniform_offset, previous_view_projection_uniform_offset): (
(view_uniform_offset, previous_view_uniform_offset): (
&'_ ViewUniformOffset,
Option<&'_ PreviousViewProjectionUniformOffset>,
Option<&'_ PreviousViewUniformOffset>,
),
_entity: Option<()>,
prepass_view_bind_group: SystemParamItem<'w, '_, Self::Param>,
@ -935,15 +939,13 @@ impl<P: PhaseItem, const I: usize> RenderCommand<P> for SetPrepassViewBindGroup<
) -> RenderCommandResult {
let prepass_view_bind_group = prepass_view_bind_group.into_inner();
if let Some(previous_view_projection_uniform_offset) =
previous_view_projection_uniform_offset
{
if let Some(previous_view_uniform_offset) = previous_view_uniform_offset {
pass.set_bind_group(
I,
prepass_view_bind_group.motion_vectors.as_ref().unwrap(),
&[
view_uniform_offset.offset,
previous_view_projection_uniform_offset.offset,
previous_view_uniform_offset.offset,
],
);
} else {

View file

@ -4,7 +4,7 @@
prepass_io::{Vertex, VertexOutput, FragmentOutput},
skinning,
morph,
mesh_view_bindings::{view, previous_view_proj},
mesh_view_bindings::view,
}
#ifdef DEFERRED_PREPASS
@ -127,7 +127,7 @@ fn fragment(in: VertexOutput) -> FragmentOutput {
#ifdef MOTION_VECTOR_PREPASS
let clip_position_t = view.unjittered_view_proj * in.world_position;
let clip_position = clip_position_t.xy / clip_position_t.w;
let previous_clip_position_t = prepass_bindings::previous_view_proj * in.previous_world_position;
let previous_clip_position_t = prepass_bindings::previous_view_uniforms.view_proj * in.previous_world_position;
let previous_clip_position = previous_clip_position_t.xy / previous_clip_position_t.w;
// These motion vectors are used as offsets to UV positions and are stored
// in the range -1,1 to allow offsetting from the one corner to the

View file

@ -1,7 +1,12 @@
#define_import_path bevy_pbr::prepass_bindings
struct PreviousViewUniforms {
inverse_view: mat4x4<f32>,
view_proj: mat4x4<f32>,
}
#ifdef MOTION_VECTOR_PREPASS
@group(0) @binding(2) var<uniform> previous_view_proj: mat4x4<f32>;
@group(0) @binding(2) var<uniform> previous_view_uniforms: PreviousViewUniforms;
#endif // MOTION_VECTOR_PREPASS
// Material bindings will be in @group(2)

View file

@ -2,7 +2,7 @@
#import bevy_pbr::{
prepass_io::VertexOutput,
prepass_bindings::previous_view_proj,
prepass_bindings::previous_view_uniforms,
mesh_view_bindings::view,
pbr_bindings,
pbr_types,
@ -47,7 +47,7 @@ fn prepass_alpha_discard(in: VertexOutput) {
fn calculate_motion_vector(world_position: vec4<f32>, previous_world_position: vec4<f32>) -> vec2<f32> {
let clip_position_t = view.unjittered_view_proj * world_position;
let clip_position = clip_position_t.xy / clip_position_t.w;
let previous_clip_position_t = previous_view_proj * previous_world_position;
let previous_clip_position_t = previous_view_uniforms.view_proj * previous_world_position;
let previous_clip_position = previous_clip_position_t.xy / previous_clip_position_t.w;
// These motion vectors are used as offsets to UV positions and are stored
// in the range -1,1 to allow offsetting from the one corner to the