-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sprite slice scaling and tiling #5213
Conversation
Now I'm not sure if I can put the slicer in an @mockersf how did you do it in https://github.com/vleue/bevy_ninepatch ? I looked at the code after you gave me the link but I don't understand the logic |
Slicing and tiling work, I think this is ready to be reviewed @alice-i-cecile |
crates/bevy_sprite/src/rect.rs
Outdated
/// Struct defining a [`Sprite`](crate::Sprite) border with padding values | ||
#[repr(C)] | ||
#[derive(Default, Clone, Copy, Debug, Reflect)] | ||
pub struct BorderRect { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This duplicates the Rect
type, which is re-exported from taffy
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So should bevy_sprite include taffy as a dependency?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure. I dislike that as it's not a light dependency.
I think we should keep this as it is for now, but probably open an issue once this is merged to think about how we can reduce tech debt here. It's going to be very silly once we try to implement this for bevy_ui.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that I think about it I could use a Rect
directly, with the min/max
values. Adding a constructor from padding values could do the trick but it sacrifices ergonomics a bit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very useful feature, and the code quality is good! There are a couple conceptual / architecture questions for you, plus some nits.
@alice-i-cecile I changed the logic to enable sprite tiling even without slicing, using an enum in I think this is better. But now that I changed a lot of stuff in the extraction stage of the sprite render pipeline, benchmarking is definetely required |
341ce4d
to
931d64b
Compare
On this MR:
On Main:
So there is some performance regression for regular sprites. I'm going to investigate this |
The big issue is accessing the Now this is still required for |
}; | ||
|
||
let slices = match &sprite.draw_mode { | ||
SpriteDrawMode::Sliced(slicer) => slicer.compute_slices( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'compute' suggests something that should be done in prepare
as it is work that takes time to do and extract is meant to be as fast as possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note though that if it doesn't take any significant amount of time for a lot of such entities (i.e. doesn't add more than say 0.1ms compared to as many entities that just use simple sprites) but it would take more time in a separate prepare
stage system due to having to iterate over them all again, then it can be OK to do it here. So basically profile and present results.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having now seen the slicer code, I suggest moving that to the prepare
stage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll move every computation in prepare
once #5247 is merged
draw_size: sprite.custom_size.unwrap_or(image_size), | ||
offset: Vec2::ZERO, | ||
}; | ||
slice.tiled(*stretch_value, (*tile_x, *tile_y)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This also looks like something that should be done in prepare
.
crates/bevy_sprite/src/render/mod.rs
Outdated
}; | ||
for slice in slices { | ||
let mut transform: GlobalTransform = *transform; | ||
transform.translation = transform.mul_vec3(slice.offset.extend(0.0)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is another example of something that should be done in prepare
.
01107a8
to
07c0ab7
Compare
07c0ab7
to
a893795
Compare
register example Refactoring Fixed issue on top/bot rects, added max scaling for corners Tiling Fixed example artifacts Update Cargo.toml Co-authored-by: Alice Cecile <[email protected]> Example page update Sprite draw mode removed extra type registration Fixed performance regression Rect slicing Code cleanup Applied review suggestions Rebased on main
a893795
to
9f85d5a
Compare
Closing in favor of #10588 |
> Replaces #5213 # Objective Implement sprite tiling and [9 slice scaling](https://en.wikipedia.org/wiki/9-slice_scaling) for `bevy_sprite`. Allowing slice scaling and texture tiling. Basic scaling vs 9 slice scaling: ![Traditional_scaling_vs_9-slice_scaling](https://user-images.githubusercontent.com/26703856/177335801-27f6fa27-c569-4ce6-b0e6-4f54e8f4e80a.svg) Slicing example: <img width="481" alt="Screenshot 2022-07-05 at 15 05 49" src="https://user-images.githubusercontent.com/26703856/177336112-9e961af0-c0af-4197-aec9-430c1170a79d.png"> Tiling example: <img width="1329" alt="Screenshot 2023-11-16 at 13 53 32" src="https://github.com/bevyengine/bevy/assets/26703856/14db39b7-d9e0-4bc3-ba0e-b1f2db39ae8f"> # Solution - `SpriteBundlue` now has a `scale_mode` component storing a `SpriteScaleMode` enum with three variants: - `Stretched` (default) - `Tiled` to have sprites tile horizontally and/or vertically - `Sliced` allowing 9 slicing the texture and optionally tile some sections with a `Textureslicer`. - `bevy_sprite` has two extra systems to compute a `ComputedTextureSlices` if necessary,: - One system react to changes on `Sprite`, `Handle<Image>` or `SpriteScaleMode` - The other listens to `AssetEvent<Image>` to compute slices on sprites when the texture is ready or changed - I updated the `bevy_sprite` extraction stage to extract potentially multiple textures instead of one, depending on the presence of `ComputedTextureSlices` - I added two examples showcasing the slicing and tiling feature. The addition of `ComputedTextureSlices` as a cache is to avoid querying the image data, to retrieve its dimensions, every frame in a extract or prepare stage. Also it reacts to changes so we can have stuff like this (tiling example): https://github.com/bevyengine/bevy/assets/26703856/a349a9f3-33c3-471f-8ef4-a0e5dfce3b01 # Related - [ ] Once #5103 or #10099 is merged I can enable tiling and slicing for texture sheets as ui # To discuss There is an other option, to consider slice/tiling as part of the asset, using the new asset preprocessing but I have no clue on how to do it. Also, instead of retrieving the Image dimensions, we could use the same system as the sprite sheet and have the user give the image dimensions directly (grid). But I think it's less user friendly --------- Co-authored-by: Alice Cecile <[email protected]> Co-authored-by: ickshonpe <[email protected]> Co-authored-by: Alice Cecile <[email protected]>
Objective
Implement sprite tiling and 9 slice scaling for
bevy_sprite
.Allowing slice scaling and texture tiling.
Basic scaling vs 9 slice scaling:
Slicing example:
Tiling example:
Solution
Sprite
now has adraw_mode
field storing aSpriteDrawMode
enum with three variants:Simple
Tiled
to have sprites tile horizontally and/or verticallySliced
allowing 9 slicing the texture and optionally tile some sections with aTextureslicer
.bevy_sprite
extraction stage to extract potentially multiple textures instead of one, depending on thedraw_mode
TODO list
Blocking
Requires Adding a Prepare stage for the sprite pipeline #5247 to be merged to move the tile and slice computations in theprepare
stage of the sprite render pipelinebevy_ui
To discuss
I want to move the slicer to be an
Asset
and avoid to compute the slices every frame, like forTextureAtlas
but the slicing depends on theSprite::custom_size
and therefore needs to be updated every frame or onChanged<Sprite>
detection