Fix resolution override to work even if the camera lacks a viewport

This commit is contained in:
JMS55 2025-07-07 22:27:11 -04:00
parent 1b714636ab
commit 10c96e8301
8 changed files with 48 additions and 20 deletions

View File

@ -80,14 +80,20 @@ impl Viewport {
}
}
pub fn with_override(
&self,
pub fn from_viewport_and_override(
viewport: Option<&Self>,
main_pass_resolution_override: Option<&MainPassResolutionOverride>,
) -> Self {
let mut viewport = self.clone();
) -> Option<Self> {
let mut viewport = viewport.cloned();
if let Some(override_size) = main_pass_resolution_override {
viewport.physical_size = **override_size;
if viewport.is_none() {
viewport = Some(Viewport::default());
}
viewport.as_mut().unwrap().physical_size = **override_size;
}
viewport
}
}
@ -101,7 +107,7 @@ impl Viewport {
/// * Insert this component on a 3d camera entity in the render world.
/// * The resolution override must be smaller than the camera's viewport size.
/// * The resolution override is specified in physical pixels.
#[derive(Component, Reflect, Deref)]
#[derive(Component, Reflect, Deref, Debug)]
#[reflect(Component)]
pub struct MainPassResolutionOverride(pub UVec2);

View File

@ -2,6 +2,7 @@ use crate::{
core_3d::Opaque3d,
skybox::{SkyboxBindGroup, SkyboxPipelineId},
};
use bevy_camera::Viewport;
use bevy_ecs::{prelude::World, query::QueryItem};
use bevy_render::{
camera::{ExtractedCamera, MainPassResolutionOverride},
@ -91,8 +92,10 @@ impl ViewNode for MainOpaquePass3dNode {
let mut render_pass = TrackedRenderPass::new(&render_device, render_pass);
let pass_span = diagnostics.pass_span(&mut render_pass, "main_opaque_pass_3d");
if let Some(viewport) = camera.viewport.as_ref() {
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
if let Some(viewport) =
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
{
render_pass.set_camera_viewport(&viewport);
}
// Opaque draws

View File

@ -1,5 +1,6 @@
use super::{Camera3d, ViewTransmissionTexture};
use crate::core_3d::Transmissive3d;
use bevy_camera::Viewport;
use bevy_ecs::{prelude::*, query::QueryItem};
use bevy_image::ToExtents;
use bevy_render::{
@ -110,8 +111,11 @@ impl ViewNode for MainTransmissivePass3dNode {
let mut render_pass =
render_context.begin_tracked_render_pass(render_pass_descriptor);
if let Some(viewport) = camera.viewport.as_ref() {
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
if let Some(viewport) = Viewport::from_viewport_and_override(
camera.viewport.as_ref(),
resolution_override,
) {
render_pass.set_camera_viewport(&viewport);
}
if let Err(err) = transmissive_phase.render(&mut render_pass, world, view_entity) {

View File

@ -1,4 +1,5 @@
use crate::core_3d::Transparent3d;
use bevy_camera::Viewport;
use bevy_ecs::{prelude::*, query::QueryItem};
use bevy_render::{
camera::{ExtractedCamera, MainPassResolutionOverride},
@ -69,8 +70,10 @@ impl ViewNode for MainTransparentPass3dNode {
let pass_span = diagnostics.pass_span(&mut render_pass, "main_transparent_pass_3d");
if let Some(viewport) = camera.viewport.as_ref() {
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
if let Some(viewport) =
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
{
render_pass.set_camera_viewport(&viewport);
}
if let Err(err) = transparent_phase.render(&mut render_pass, world, view_entity) {

View File

@ -1,3 +1,4 @@
use bevy_camera::Viewport;
use bevy_ecs::{prelude::*, query::QueryItem};
use bevy_render::camera::MainPassResolutionOverride;
use bevy_render::experimental::occlusion_culling::OcclusionCulling;
@ -221,8 +222,10 @@ fn run_deferred_prepass<'w>(
occlusion_query_set: None,
});
let mut render_pass = TrackedRenderPass::new(&render_device, render_pass);
if let Some(viewport) = camera.viewport.as_ref() {
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
if let Some(viewport) =
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
{
render_pass.set_camera_viewport(&viewport);
}
// Opaque draws

View File

@ -1,3 +1,4 @@
use bevy_camera::Viewport;
use bevy_ecs::{prelude::*, query::QueryItem};
use bevy_render::{
camera::{ExtractedCamera, MainPassResolutionOverride},
@ -63,8 +64,10 @@ impl ViewNode for OitResolveNode {
occlusion_query_set: None,
});
if let Some(viewport) = camera.viewport.as_ref() {
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
if let Some(viewport) =
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
{
render_pass.set_camera_viewport(&viewport);
}
render_pass.set_render_pipeline(pipeline);

View File

@ -1,3 +1,4 @@
use bevy_camera::Viewport;
use bevy_ecs::{prelude::*, query::QueryItem};
use bevy_render::{
camera::{ExtractedCamera, MainPassResolutionOverride},
@ -186,8 +187,10 @@ fn run_prepass<'w>(
let mut render_pass = TrackedRenderPass::new(&render_device, render_pass);
let pass_span = diagnostics.pass_span(&mut render_pass, label);
if let Some(viewport) = camera.viewport.as_ref() {
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
if let Some(viewport) =
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
{
render_pass.set_camera_viewport(&viewport);
}
// Opaque draws

View File

@ -12,6 +12,7 @@
use std::ops::Range;
use bevy::camera::Viewport;
use bevy::pbr::SetMeshViewEmptyBindGroup;
use bevy::{
core_pipeline::core_3d::graph::{Core3d, Node3d},
@ -618,8 +619,10 @@ impl ViewNode for CustomDrawNode {
occlusion_query_set: None,
});
if let Some(viewport) = camera.viewport.as_ref() {
render_pass.set_camera_viewport(&viewport.with_override(resolution_override));
if let Some(viewport) =
Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
{
render_pass.set_camera_viewport(&viewport);
}
// Render the phase