Skip to content

Commit b378e0a

Browse files
authored
MainPassResolutionOverride changes (#20403)
Lots of changes extracted from #19864. I haven't added support for MainPassResolutionOverride to every rendering feature yet. Mostly just Solari and some of the main passes as a proof of concept.
1 parent 2adb7a9 commit b378e0a

File tree

15 files changed

+131
-69
lines changed

15 files changed

+131
-69
lines changed

crates/bevy_camera/src/camera.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,20 @@ impl Viewport {
8080
}
8181
}
8282

83-
pub fn with_override(
84-
&self,
83+
pub fn from_viewport_and_override(
84+
viewport: Option<&Self>,
8585
main_pass_resolution_override: Option<&MainPassResolutionOverride>,
86-
) -> Self {
87-
let mut viewport = self.clone();
86+
) -> Option<Self> {
87+
let mut viewport = viewport.cloned();
88+
8889
if let Some(override_size) = main_pass_resolution_override {
89-
viewport.physical_size = **override_size;
90+
if viewport.is_none() {
91+
viewport = Some(Viewport::default());
92+
}
93+
94+
viewport.as_mut().unwrap().physical_size = **override_size;
9095
}
96+
9197
viewport
9298
}
9399
}
@@ -101,7 +107,8 @@ impl Viewport {
101107
/// * Insert this component on a 3d camera entity in the render world.
102108
/// * The resolution override must be smaller than the camera's viewport size.
103109
/// * The resolution override is specified in physical pixels.
104-
#[derive(Component, Reflect, Deref)]
110+
/// * In shaders, use `View::main_pass_viewport` instead of `View::viewport`.
111+
#[derive(Component, Reflect, Deref, Debug)]
105112
#[reflect(Component)]
106113
pub struct MainPassResolutionOverride(pub UVec2);
107114

crates/bevy_core_pipeline/src/core_3d/main_opaque_pass_3d_node.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::{
22
core_3d::Opaque3d,
33
skybox::{SkyboxBindGroup, SkyboxPipelineId},
44
};
5+
use bevy_camera::Viewport;
56
use bevy_ecs::{prelude::World, query::QueryItem};
67
use bevy_render::{
78
camera::{ExtractedCamera, MainPassResolutionOverride},
@@ -91,8 +92,10 @@ impl ViewNode for MainOpaquePass3dNode {
9192
let mut render_pass = TrackedRenderPass::new(&render_device, render_pass);
9293
let pass_span = diagnostics.pass_span(&mut render_pass, "main_opaque_pass_3d");
9394

94-
if let Some(viewport) = camera.viewport.as_ref() {
95-
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
95+
if let Some(viewport) =
96+
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
97+
{
98+
render_pass.set_camera_viewport(&viewport);
9699
}
97100

98101
// Opaque draws

crates/bevy_core_pipeline/src/core_3d/main_transmissive_pass_3d_node.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::{Camera3d, ViewTransmissionTexture};
22
use crate::core_3d::Transmissive3d;
3+
use bevy_camera::Viewport;
34
use bevy_ecs::{prelude::*, query::QueryItem};
45
use bevy_image::ToExtents;
56
use bevy_render::{
@@ -110,8 +111,11 @@ impl ViewNode for MainTransmissivePass3dNode {
110111
let mut render_pass =
111112
render_context.begin_tracked_render_pass(render_pass_descriptor);
112113

113-
if let Some(viewport) = camera.viewport.as_ref() {
114-
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
114+
if let Some(viewport) = Viewport::from_viewport_and_override(
115+
camera.viewport.as_ref(),
116+
resolution_override,
117+
) {
118+
render_pass.set_camera_viewport(&viewport);
115119
}
116120

117121
if let Err(err) = transmissive_phase.render(&mut render_pass, world, view_entity) {

crates/bevy_core_pipeline/src/core_3d/main_transparent_pass_3d_node.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::core_3d::Transparent3d;
2+
use bevy_camera::Viewport;
23
use bevy_ecs::{prelude::*, query::QueryItem};
34
use bevy_render::{
45
camera::{ExtractedCamera, MainPassResolutionOverride},
@@ -69,8 +70,10 @@ impl ViewNode for MainTransparentPass3dNode {
6970

7071
let pass_span = diagnostics.pass_span(&mut render_pass, "main_transparent_pass_3d");
7172

72-
if let Some(viewport) = camera.viewport.as_ref() {
73-
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
73+
if let Some(viewport) =
74+
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
75+
{
76+
render_pass.set_camera_viewport(&viewport);
7477
}
7578

7679
if let Err(err) = transparent_phase.render(&mut render_pass, world, view_entity) {

crates/bevy_core_pipeline/src/deferred/node.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use bevy_camera::Viewport;
12
use bevy_ecs::{prelude::*, query::QueryItem};
23
use bevy_render::camera::MainPassResolutionOverride;
34
use bevy_render::experimental::occlusion_culling::OcclusionCulling;
@@ -222,8 +223,10 @@ fn run_deferred_prepass<'w>(
222223
occlusion_query_set: None,
223224
});
224225
let mut render_pass = TrackedRenderPass::new(&render_device, render_pass);
225-
if let Some(viewport) = camera.viewport.as_ref() {
226-
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
226+
if let Some(viewport) =
227+
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
228+
{
229+
render_pass.set_camera_viewport(&viewport);
227230
}
228231

229232
// Opaque draws

crates/bevy_core_pipeline/src/oit/resolve/node.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use bevy_camera::Viewport;
12
use bevy_ecs::{prelude::*, query::QueryItem};
23
use bevy_render::{
34
camera::{ExtractedCamera, MainPassResolutionOverride},
@@ -63,8 +64,10 @@ impl ViewNode for OitResolveNode {
6364
occlusion_query_set: None,
6465
});
6566

66-
if let Some(viewport) = camera.viewport.as_ref() {
67-
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
67+
if let Some(viewport) =
68+
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
69+
{
70+
render_pass.set_camera_viewport(&viewport);
6871
}
6972

7073
render_pass.set_render_pipeline(pipeline);

crates/bevy_core_pipeline/src/prepass/node.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use bevy_camera::Viewport;
12
use bevy_ecs::{prelude::*, query::QueryItem};
23
use bevy_render::{
34
camera::{ExtractedCamera, MainPassResolutionOverride},
@@ -186,8 +187,10 @@ fn run_prepass<'w>(
186187
let mut render_pass = TrackedRenderPass::new(&render_device, render_pass);
187188
let pass_span = diagnostics.pass_span(&mut render_pass, label);
188189

189-
if let Some(viewport) = camera.viewport.as_ref() {
190-
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
190+
if let Some(viewport) =
191+
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
192+
{
193+
render_pass.set_camera_viewport(&viewport);
191194
}
192195

193196
// Opaque draws

crates/bevy_pbr/src/meshlet/material_shade_nodes.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::{
1010
MeshViewBindGroup, PrepassViewBindGroup, ViewEnvironmentMapUniformOffset, ViewFogUniformOffset,
1111
ViewLightProbesUniformOffset, ViewLightsUniformOffset, ViewScreenSpaceReflectionsUniformOffset,
1212
};
13+
use bevy_camera::Viewport;
1314
use bevy_core_pipeline::prepass::{
1415
MotionVectorPrepass, PreviousViewUniformOffset, ViewPrepassTextures,
1516
};
@@ -102,8 +103,10 @@ impl ViewNode for MeshletMainOpaquePass3dNode {
102103
timestamp_writes: None,
103104
occlusion_query_set: None,
104105
});
105-
if let Some(viewport) = camera.viewport.as_ref() {
106-
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
106+
if let Some(viewport) =
107+
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
108+
{
109+
render_pass.set_camera_viewport(&viewport);
107110
}
108111

109112
render_pass.set_bind_group(
@@ -223,8 +226,10 @@ impl ViewNode for MeshletPrepassNode {
223226
timestamp_writes: None,
224227
occlusion_query_set: None,
225228
});
226-
if let Some(viewport) = camera.viewport.as_ref() {
227-
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
229+
if let Some(viewport) =
230+
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
231+
{
232+
render_pass.set_camera_viewport(&viewport);
228233
}
229234

230235
if view_has_motion_vector_prepass {
@@ -354,8 +359,10 @@ impl ViewNode for MeshletDeferredGBufferPrepassNode {
354359
timestamp_writes: None,
355360
occlusion_query_set: None,
356361
});
357-
if let Some(viewport) = camera.viewport.as_ref() {
358-
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
362+
if let Some(viewport) =
363+
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
364+
{
365+
render_pass.set_camera_viewport(&viewport);
359366
}
360367

361368
if view_has_motion_vector_prepass {

crates/bevy_render/src/view/mod.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pub mod window;
33

44
use bevy_camera::{
55
primitives::Frustum, CameraMainTextureUsages, ClearColor, ClearColorConfig, Exposure,
6+
MainPassResolutionOverride,
67
};
78
use bevy_diagnostic::FrameCount;
89
pub use visibility::*;
@@ -568,6 +569,7 @@ pub struct ViewUniform {
568569
pub exposure: f32,
569570
// viewport(x_origin, y_origin, width, height)
570571
pub viewport: Vec4,
572+
pub main_pass_viewport: Vec4,
571573
/// 6 world-space half spaces (normal: vec3, distance: f32) ordered left, right, top, bottom, near, far.
572574
/// The normal vectors point towards the interior of the frustum.
573575
/// A half space contains `p` if `normal.dot(p) + distance > 0.`
@@ -901,6 +903,7 @@ pub fn prepare_view_uniforms(
901903
Option<&Frustum>,
902904
Option<&TemporalJitter>,
903905
Option<&MipBias>,
906+
Option<&MainPassResolutionOverride>,
904907
)>,
905908
frame_count: Res<FrameCount>,
906909
) {
@@ -913,13 +916,28 @@ pub fn prepare_view_uniforms(
913916
else {
914917
return;
915918
};
916-
for (entity, extracted_camera, extracted_view, frustum, temporal_jitter, mip_bias) in &views {
919+
for (
920+
entity,
921+
extracted_camera,
922+
extracted_view,
923+
frustum,
924+
temporal_jitter,
925+
mip_bias,
926+
resolution_override,
927+
) in &views
928+
{
917929
let viewport = extracted_view.viewport.as_vec4();
930+
let mut main_pass_viewport = viewport;
931+
if let Some(resolution_override) = resolution_override {
932+
main_pass_viewport.z = resolution_override.0.x as f32;
933+
main_pass_viewport.w = resolution_override.0.y as f32;
934+
}
935+
918936
let unjittered_projection = extracted_view.clip_from_view;
919937
let mut clip_from_view = unjittered_projection;
920938

921939
if let Some(temporal_jitter) = temporal_jitter {
922-
temporal_jitter.jitter_projection(&mut clip_from_view, viewport.zw());
940+
temporal_jitter.jitter_projection(&mut clip_from_view, main_pass_viewport.zw());
923941
}
924942

925943
let view_from_clip = clip_from_view.inverse();
@@ -953,6 +971,7 @@ pub fn prepare_view_uniforms(
953971
.map(|c| c.exposure)
954972
.unwrap_or_else(|| Exposure::default().exposure()),
955973
viewport,
974+
main_pass_viewport,
956975
frustum,
957976
color_grading: extracted_view.color_grading.clone().into(),
958977
mip_bias: mip_bias.unwrap_or(&MipBias(0.0)).0,

crates/bevy_render/src/view/view.wgsl

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,15 @@ struct View {
4848
// `clip_from_view[3][3] == 1.0` is the standard way to check if a projection is orthographic
4949
//
5050
// Wgsl matrices are column major, so for example getting the near plane of a perspective projection is `clip_from_view[3][2]`
51-
//
51+
//
5252
// Custom projections are also possible however.
5353
clip_from_view: mat4x4<f32>,
5454
view_from_clip: mat4x4<f32>,
5555
world_position: vec3<f32>,
5656
exposure: f32,
5757
// viewport(x_origin, y_origin, width, height)
5858
viewport: vec4<f32>,
59+
main_pass_viewport: vec4<f32>,
5960
// 6 world-space half spaces (normal: vec3, distance: f32) ordered left, right, top, bottom, near, far.
6061
// The normal vectors point towards the interior of the frustum.
6162
// A half space contains `p` if `normal.dot(p) + distance > 0.`
@@ -78,7 +79,7 @@ struct View {
7879
/// https://www.w3.org/TR/webgpu/#coordinate-systems
7980
/// (-1.0, -1.0) in NDC is located at the bottom-left corner of NDC
8081
/// (1.0, 1.0) in NDC is located at the top-right corner of NDC
81-
/// Z is depth where:
82+
/// Z is depth where:
8283
/// 1.0 is near clipping plane
8384
/// Perspective projection: 0.0 is inf far away
8485
/// Orthographic projection: 0.0 is far clipping plane
@@ -209,7 +210,7 @@ fn perspective_camera_near(clip_from_view: mat4x4<f32>) -> f32 {
209210
return clip_from_view[3][2];
210211
}
211212

212-
/// Convert ndc depth to linear view z.
213+
/// Convert ndc depth to linear view z.
213214
/// Note: Depth values in front of the camera will be negative as -z is forward
214215
fn depth_ndc_to_view_z(ndc_depth: f32, clip_from_view: mat4x4<f32>, view_from_clip: mat4x4<f32>) -> f32 {
215216
#ifdef VIEW_PROJECTION_PERSPECTIVE
@@ -222,7 +223,7 @@ fn depth_ndc_to_view_z(ndc_depth: f32, clip_from_view: mat4x4<f32>, view_from_cl
222223
#endif
223224
}
224225

225-
/// Convert linear view z to ndc depth.
226+
/// Convert linear view z to ndc depth.
226227
/// Note: View z input should be negative for values in front of the camera as -z is forward
227228
fn view_z_to_depth_ndc(view_z: f32, clip_from_view: mat4x4<f32>) -> f32 {
228229
#ifdef VIEW_PROJECTION_PERSPECTIVE

0 commit comments

Comments
 (0)