bevy icon indicating copy to clipboard operation
bevy copied to clipboard

Sprite slice scaling and tiling

Open ManevilleF opened this issue 3 years ago • 5 comments

Objective

Implement sprite tiling and 9 slice scaling for bevy_sprite. Allowing slice scaling and texture tiling.

Basic scaling vs 9 slice scaling:

Traditional_scaling_vs_9-slice_scaling

Slicing example:

Screenshot 2022-07-05 at 15 05 49

Tiling example:

Screenshot 2022-07-06 at 14 35 34

Solution

  • Sprite now has a draw_mode field storing a SpriteDrawMode enum with three variants:
    • Simple
    • Tiled to have sprites tile horizontally and/or vertically
    • Sliced allowing 9 slicing the texture and optionally tile some sections with a Textureslicer.
  • I updated the bevy_sprite extraction stage to extract potentially multiple textures instead of one, depending on the draw_mode
  • I added two examples showcasing the slicing and tiling feature.

TODO list

  • [x] slicing
  • [x] scale factor limit
  • [x] Slice Tiling:
    • [x] Basic stretch mode
    • [x] Center tiling
    • [x] Sides tiling
  • [x] Sprite tiling without slices

Blocking

  • [ ] ~~Requires https://github.com/bevyengine/bevy/pull/5247 to be merged to move the tile and slice computations in the prepare stage of the sprite render pipeline~~
  • [ ] https://github.com/bevyengine/bevy/pull/6621
  • [ ] Once #5103 is merged I can enable tiling and slicing for texture sheets.
  • [ ] Once #5070 is merged I can add this to bevy_ui

To discuss

I want to move the slicer to be an Asset and avoid to compute the slices every frame, like for TextureAtlas but the slicing depends on the Sprite::custom_size and therefore needs to be updated every frame or on Changed<Sprite> detection

ManevilleF avatar Jul 05 '22 13:07 ManevilleF

Now I'm not sure if I can put the slicer in an Asset, I can compute the Rect values from a given image size and store it but the slices must be computed every frame since the sprite can be resized. Or maybe I can compute some change detection..

@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

ManevilleF avatar Jul 05 '22 14:07 ManevilleF

Slicing and tiling work, I think this is ready to be reviewed @alice-i-cecile

ManevilleF avatar Jul 06 '22 12:07 ManevilleF

@alice-i-cecile I changed the logic to enable sprite tiling even without slicing, using an enum in Sprite::draw_mode and removing TextureSlicer from being a component.

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

ManevilleF avatar Jul 06 '22 15:07 ManevilleF

many_sprites stress test:

On this MR:

2022-07-07T09:27:50.191875Z  INFO many_sprites: Sprites: 102400
2022-07-07T09:27:50.191926Z  INFO bevy diagnostic: frame_time                      :    0.058695s (avg 0.060466s)
2022-07-07T09:27:50.191937Z  INFO bevy diagnostic: fps                             :   17.037371  (avg 16.569809)
2022-07-07T09:27:50.191941Z  INFO bevy diagnostic: frame_count                     : 403.000000

On Main:

2022-07-07T09:29:16.821865Z  INFO many_sprites: Sprites: 102400
2022-07-07T09:29:16.821931Z  INFO bevy diagnostic: frame_time                      :    0.052531s (avg 0.050298s)
2022-07-07T09:29:16.821944Z  INFO bevy diagnostic: fps                             :   19.036325  (avg 19.903592)
2022-07-07T09:29:16.821949Z  INFO bevy diagnostic: frame_count                     : 415.000000

So there is some performance regression for regular sprites. I'm going to investigate this

ManevilleF avatar Jul 07 '22 09:07 ManevilleF

The big issue is accessing the Image from the handle in the extraction stage. I removed this step for SpriteDrawMode::Simple sprites, meaning no performance regressions.

Now this is still required for Sliced and Tiled draw modes. A more optimized solution would be to retrieve the image size lazily on the Added<Sprite> event or to ask the user to give the image dimensions. I'm trying to think about a more ergonomic way to handle this, since the image dimensions are accessed again in the queue stage of the pipeline.

ManevilleF avatar Jul 07 '22 09:07 ManevilleF

Closing in favor of #10588

ManevilleF avatar Nov 16 '23 13:11 ManevilleF