diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index df319a7857e34e..f66a65e6d6b2d6 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -361,7 +361,19 @@ pub fn extract_sprites( .map(|e| (commands.spawn_empty().id(), e)), ); } else { - let rect = sheet.and_then(|s| s.texture_rect(&texture_atlases)); + let atlas_rect = sheet.and_then(|s| s.texture_rect(&texture_atlases)); + let rect = match (atlas_rect, sprite.rect) { + (None, None) => None, + (None, Some(sprite_rect)) => Some(sprite_rect), + (Some(atlas_rect), None) => Some(atlas_rect), + (Some(atlas_rect), Some(mut sprite_rect)) => { + sprite_rect.min += atlas_rect.min; + sprite_rect.max += atlas_rect.min; + + Some(sprite_rect) + } + }; + // PERF: we don't check in this function that the `Image` asset is ready, since it should be in most cases and hashing the handle is expensive extracted_sprites.sprites.insert( entity, diff --git a/crates/bevy_sprite/src/sprite.rs b/crates/bevy_sprite/src/sprite.rs index 5c60d759a5468d..c62d6da82d4f35 100644 --- a/crates/bevy_sprite/src/sprite.rs +++ b/crates/bevy_sprite/src/sprite.rs @@ -21,8 +21,11 @@ pub struct Sprite { /// An optional custom size for the sprite that will be used when rendering, instead of the size /// of the sprite's image pub custom_size: Option, - /// An optional rectangle representing the region of the sprite's image to render, instead of - /// rendering the full image. This is an easy one-off alternative to using a texture atlas. + /// An optional rectangle representing the region of the sprite's image to render, instead of rendering + /// the full image. This is an easy one-off alternative to using a [`TextureAtlas`](crate::TextureAtlas). + /// + /// When used with a [`TextureAtlas`](crate::TextureAtlas), the rect + /// is offset by the atlas's minimal (top-left) corner position. pub rect: Option, /// [`Anchor`] point of the sprite in the world pub anchor: Anchor,