diff --git a/src/scene/view/render.rs b/src/scene/view/render.rs index e2e4d301b..c1e80b531 100644 --- a/src/scene/view/render.rs +++ b/src/scene/view/render.rs @@ -3009,11 +3009,13 @@ impl Scene { background.use_tiling as u8 as f32, image.width as f32 / image.height.max(1) as f32, ]; + // Offset, then the image's size in pixels at its scale: + // an image not fitted to the screen keeps its pixel size. result.image_transform = [ background.offset.x as f32, background.offset.y as f32, - background.scale.x as f32, - background.scale.y as f32, + background.scale.x as f32 * image.width as f32, + background.scale.y as f32 * image.height as f32, ]; result.params[0] = 4.0; result.image = Some(image); diff --git a/src/shaders/background.wgsl b/src/shaders/background.wgsl index c99da6201..25a004c50 100644 --- a/src/shaders/background.wgsl +++ b/src/shaders/background.wgsl @@ -81,8 +81,12 @@ fn equirect_uv(ndc: vec2, rotation: f32) -> vec2 { fn image_uv(source_uv: vec2) -> vec2 { var uv = source_uv; if u.background_image_params.x < 0.5 { - uv = (source_uv - u.background_image_transform.xy) - / max(abs(u.background_image_transform.zw), vec2(1e-6)); + // Not fitted: the image at its own pixel size (times its scale), + // centred on the viewport and moved by its offset. + let pixel = (source_uv - vec2(0.5)) * max(u.viewport_size, vec2(1.0)); + uv = pixel / max(abs(u.background_image_transform.zw), vec2(1e-6)) + + vec2(0.5) - u.background_image_transform.xy; + return select(uv, fract(uv), u.background_image_params.z > 0.5); } if u.background_image_params.y > 0.5 { let image_aspect = max(u.background_image_params.w, 1e-6);