diff --git a/assets/shaders/custom_material_chromatic_aberration.wgsl b/assets/shaders/custom_material_chromatic_aberration.wgsl index e8ccdcfb62513..e09580848f7f8 100644 --- a/assets/shaders/custom_material_chromatic_aberration.wgsl +++ b/assets/shaders/custom_material_chromatic_aberration.wgsl @@ -1,4 +1,5 @@ #import bevy_pbr::mesh_view_bindings +#import bevy_pbr::utils @group(1) @binding(0) var texture: texture_2d; @@ -12,7 +13,7 @@ fn fragment( #import bevy_sprite::mesh2d_vertex_output ) -> @location(0) vec4 { // Get screen position with coordinates from 0 to 1 - let uv = position.xy / vec2(view.width, view.height); + let uv = coords_to_viewport_uv(position.xy, view.viewport); let offset_strength = 0.02; // Sample each color channel with an arbitrary shift diff --git a/assets/shaders/custom_material_screenspace_texture.wgsl b/assets/shaders/custom_material_screenspace_texture.wgsl index aad35920c093e..468cc61475a08 100644 --- a/assets/shaders/custom_material_screenspace_texture.wgsl +++ b/assets/shaders/custom_material_screenspace_texture.wgsl @@ -1,4 +1,5 @@ #import bevy_pbr::mesh_view_bindings +#import bevy_pbr::utils @group(1) @binding(0) var texture: texture_2d; @@ -10,7 +11,7 @@ fn fragment( @builtin(position) position: vec4, #import bevy_pbr::mesh_vertex_output ) -> @location(0) vec4 { - let uv = position.xy / vec2(view.width, view.height); + let uv = coords_to_viewport_uv(position.xy, view.viewport); let color = textureSample(texture, texture_sampler, uv); return color; } diff --git a/crates/bevy_pbr/src/render/clustered_forward.wgsl b/crates/bevy_pbr/src/render/clustered_forward.wgsl index 46c54ad6f6390..674f996dd578f 100644 --- a/crates/bevy_pbr/src/render/clustered_forward.wgsl +++ b/crates/bevy_pbr/src/render/clustered_forward.wgsl @@ -16,7 +16,7 @@ fn view_z_to_z_slice(view_z: f32, is_orthographic: bool) -> u32 { } fn fragment_cluster_index(frag_coord: vec2, view_z: f32, is_orthographic: bool) -> u32 { - let xy = vec2(floor(frag_coord * lights.cluster_factors.xy)); + let xy = vec2(floor((frag_coord - view.viewport.xy) * lights.cluster_factors.xy)); let z_slice = view_z_to_z_slice(view_z, is_orthographic); // NOTE: Restricting cluster index to avoid undefined behavior when accessing uniform buffer // arrays based on the cluster index. diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 6b79102d3b844..9a68bc4be8656 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -967,8 +967,8 @@ pub fn prepare_lights( ambient_color: Vec4::from_slice(&ambient_light.color.as_linear_rgba_f32()) * ambient_light.brightness, cluster_factors: Vec4::new( - clusters.dimensions.x as f32 / extracted_view.width as f32, - clusters.dimensions.y as f32 / extracted_view.height as f32, + clusters.dimensions.x as f32 / extracted_view.viewport.z as f32, + clusters.dimensions.y as f32 / extracted_view.viewport.w as f32, cluster_factors_zw.x, cluster_factors_zw.y, ), @@ -1024,8 +1024,12 @@ pub fn prepare_lights( ), }, ExtractedView { - width: point_light_shadow_map.size as u32, - height: point_light_shadow_map.size as u32, + viewport: UVec4::new( + 0, + 0, + point_light_shadow_map.size as u32, + point_light_shadow_map.size as u32, + ), transform: view_translation * *view_rotation, projection: cube_face_projection, }, @@ -1076,8 +1080,12 @@ pub fn prepare_lights( pass_name: format!("shadow pass spot light {}", light_index,), }, ExtractedView { - width: directional_light_shadow_map.size as u32, - height: directional_light_shadow_map.size as u32, + viewport: UVec4::new( + 0, + 0, + directional_light_shadow_map.size as u32, + directional_light_shadow_map.size as u32, + ), transform: spot_view_transform, projection: spot_projection, }, @@ -1156,8 +1164,12 @@ pub fn prepare_lights( pass_name: format!("shadow pass directional light {}", i), }, ExtractedView { - width: directional_light_shadow_map.size as u32, - height: directional_light_shadow_map.size as u32, + viewport: UVec4::new( + 0, + 0, + directional_light_shadow_map.size as u32, + directional_light_shadow_map.size as u32, + ), transform: GlobalTransform::from(view.inverse()), projection, }, diff --git a/crates/bevy_pbr/src/render/mesh_view_types.wgsl b/crates/bevy_pbr/src/render/mesh_view_types.wgsl index ba6da2bb664f9..4abef78cfcf27 100644 --- a/crates/bevy_pbr/src/render/mesh_view_types.wgsl +++ b/crates/bevy_pbr/src/render/mesh_view_types.wgsl @@ -8,8 +8,8 @@ struct View { projection: mat4x4, inverse_projection: mat4x4, world_position: vec3, - width: f32, - height: f32, + // viewport(x_origin, y_origin, width, height) + viewport: vec4, }; struct PointLight { diff --git a/crates/bevy_pbr/src/render/utils.wgsl b/crates/bevy_pbr/src/render/utils.wgsl index ac13af027da7f..90ad0934e595a 100644 --- a/crates/bevy_pbr/src/render/utils.wgsl +++ b/crates/bevy_pbr/src/render/utils.wgsl @@ -21,3 +21,11 @@ fn hsv2rgb(hue: f32, saturation: f32, value: f32) -> vec3 { fn random1D(s: f32) -> f32 { return fract(sin(s * 12.9898) * 43758.5453123); } + +// returns the (0-1, 0-1) position within the given viewport for the current buffer coords . +// buffer coords can be obtained from `@builtin(position).xy`. +// the view uniform struct contains the current camera viewport in `view.viewport`. +// topleft = 0,0 +fn coords_to_viewport_uv(position: vec2, viewport: vec4) -> vec2 { + return (position - viewport.xy) / viewport.zw; +} diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index 0222b40eb6e3c..5b2ddbfb6f24f 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -17,7 +17,7 @@ use bevy_ecs::{ reflect::ReflectComponent, system::{Commands, ParamSet, Query, Res}, }; -use bevy_math::{Mat4, UVec2, Vec2, Vec3}; +use bevy_math::{Mat4, UVec2, UVec4, Vec2, Vec3}; use bevy_reflect::prelude::*; use bevy_reflect::FromReflect; use bevy_transform::components::GlobalTransform; @@ -418,7 +418,8 @@ pub fn extract_cameras( if !camera.is_active { continue; } - if let (Some(viewport_size), Some(target_size)) = ( + if let (Some((viewport_origin, _)), Some(viewport_size), Some(target_size)) = ( + camera.physical_viewport_rect(), camera.physical_viewport_size(), camera.physical_target_size(), ) { @@ -437,8 +438,12 @@ pub fn extract_cameras( ExtractedView { projection: camera.projection_matrix(), transform: *transform, - width: viewport_size.x, - height: viewport_size.y, + viewport: UVec4::new( + viewport_origin.x, + viewport_origin.y, + viewport_size.x, + viewport_size.y, + ), }, visible_entities.clone(), )); diff --git a/crates/bevy_render/src/view/mod.rs b/crates/bevy_render/src/view/mod.rs index 55ca6a31b6c23..92657ad8f8461 100644 --- a/crates/bevy_render/src/view/mod.rs +++ b/crates/bevy_render/src/view/mod.rs @@ -21,7 +21,7 @@ use crate::{ }; use bevy_app::{App, Plugin}; use bevy_ecs::prelude::*; -use bevy_math::{Mat4, Vec3}; +use bevy_math::{Mat4, UVec4, Vec3, Vec4}; use bevy_reflect::Reflect; use bevy_transform::components::GlobalTransform; use bevy_utils::HashMap; @@ -81,8 +81,8 @@ impl Default for Msaa { pub struct ExtractedView { pub projection: Mat4, pub transform: GlobalTransform, - pub width: u32, - pub height: u32, + // uvec4(origin.x, origin.y, width, height) + pub viewport: UVec4, } impl ExtractedView { @@ -101,8 +101,8 @@ pub struct ViewUniform { projection: Mat4, inverse_projection: Mat4, world_position: Vec3, - width: f32, - height: f32, + // viewport(x_origin, y_origin, width, height) + viewport: Vec4, } #[derive(Resource, Default)] @@ -163,8 +163,7 @@ fn prepare_view_uniforms( projection, inverse_projection, world_position: camera.transform.translation(), - width: camera.width as f32, - height: camera.height as f32, + viewport: camera.viewport.as_vec4(), }), }; diff --git a/crates/bevy_sprite/src/mesh2d/mesh2d_view_types.wgsl b/crates/bevy_sprite/src/mesh2d/mesh2d_view_types.wgsl index 0890ea7e567b1..b4b1e8d98c178 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh2d_view_types.wgsl +++ b/crates/bevy_sprite/src/mesh2d/mesh2d_view_types.wgsl @@ -8,6 +8,6 @@ struct View { projection: mat4x4, inverse_projection: mat4x4, world_position: vec3, - width: f32, - height: f32, + // viewport(x_origin, y_origin, width, height) + viewport: vec4, }; diff --git a/crates/bevy_sprite/src/render/sprite.wgsl b/crates/bevy_sprite/src/render/sprite.wgsl index 2f1e4f8e45f89..441140549a562 100644 --- a/crates/bevy_sprite/src/render/sprite.wgsl +++ b/crates/bevy_sprite/src/render/sprite.wgsl @@ -6,8 +6,8 @@ struct View { projection: mat4x4, inverse_projection: mat4x4, world_position: vec3, - width: f32, - height: f32, + // viewport(x_origin, y_origin, width, height) + viewport: vec4, }; @group(0) @binding(0) var view: View; diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 24fa992dc3251..cb7c24182fe9d 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -9,7 +9,7 @@ use crate::{prelude::UiCameraConfig, CalculatedClip, Node, UiColor, UiImage}; use bevy_app::prelude::*; use bevy_asset::{load_internal_asset, AssetEvent, Assets, Handle, HandleUntyped}; use bevy_ecs::prelude::*; -use bevy_math::{Mat4, Rect, Vec2, Vec3, Vec4Swizzles}; +use bevy_math::{Mat4, Rect, UVec4, Vec2, Vec3, Vec4Swizzles}; use bevy_reflect::TypeUuid; use bevy_render::{ camera::{Camera, CameraProjection, OrthographicProjection, WindowOrigin}, @@ -238,8 +238,9 @@ pub fn extract_default_ui_camera_view( if matches!(camera_ui, Some(&UiCameraConfig { show_ui: false, .. })) { continue; } - if let (Some(logical_size), Some(physical_size)) = ( + if let (Some(logical_size), Some((physical_origin, _)), Some(physical_size)) = ( camera.logical_viewport_size(), + camera.physical_viewport_rect(), camera.physical_viewport_size(), ) { let mut projection = OrthographicProjection { @@ -257,8 +258,12 @@ pub fn extract_default_ui_camera_view( 0.0, UI_CAMERA_FAR + UI_CAMERA_TRANSFORM_OFFSET, ), - width: physical_size.x, - height: physical_size.y, + viewport: UVec4::new( + physical_origin.x, + physical_origin.y, + physical_size.x, + physical_size.y, + ), }) .id(); commands.get_or_spawn(entity).insert_bundle(( diff --git a/crates/bevy_ui/src/render/ui.wgsl b/crates/bevy_ui/src/render/ui.wgsl index 4993e52d3908f..0cf8ed8aa784c 100644 --- a/crates/bevy_ui/src/render/ui.wgsl +++ b/crates/bevy_ui/src/render/ui.wgsl @@ -6,8 +6,8 @@ struct View { projection: mat4x4, inverse_projection: mat4x4, world_position: vec3, - width: f32, - height: f32, + // viewport(x_origin, y_origin, width, height) + viewport: vec4, }; @group(0) @binding(0) var view: View;