R129 Spritesheeting algorithm

  • Do not worry, I'm not offended;)

    Construct 2 did not have algorism and it worked well.

    Algorism is a great idea and it works perfectly.

    If the user could choose which sprites to leave out (sprites that only appear 1 or 2 times in the game) would be a great memory saving.

    But I think the best thing is to let the C3 team work, they will surely achieve optimum performance.

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • Ashley, would it make sense to offer an import of sprites, and spritesheets, via TexturePacker?

    Not really - firstly this still has the same problem: as soon as you edit anything Construct will throw out the old spritesheets and create new ones, essentially undoing anything that was done in TexturePacker. Secondly Construct sometimes packs spritesheets differently depending on project settings, e.g. downscaling quality. If an external tool does not respect this setting or provide it as an option, it's incompatible with that project setting, meaning Construct has to either re-pack the spritesheets itself (again undoing anything done by TexturePacker), or ignore the project setting (creating the possibility of issues like graphical glitches that appear if TexturePacker created a spritesheet without using the same algorithm Construct does in high-quality downscaling mode).

    I think the best option would be to be able to choose which sprites go into algorism, an option within the properties of the sprite would solve all the "problem".

    So presumably you'd want to configure this to reduce memory use. In that case it's even better if Construct can do this automatically for you. We have an upcoming change designed to do exactly that.

    Maybe set a max spritesheet size?

    I was going to add exactly this for the next beta cycle - I've already tested it and it seems to be the single thing that makes the biggest difference (moreso even than packing objects that are used together on the same sheets). It's a shame this can't be detected automatically - I want to try to avoid ending up with loads of advanced project settings that all need to be configured just right - but at least the option's there in case you need it.

    I am sceptical that adding any other more options would be useful. Packing spritesheets is actually a far more complex and subtle process than most people imagine. You might just think it means "throw a lot of images on to one larger image". Suppose you then start downscaling images a long way with mipmapping enabled (which it is in Construct for best quality rendering), and find that bleed happens on the lower mip levels. Turning off mipmaps is actually slower, so is not a good solution. Adding padding at first looks like it solves this, but actually just postpones the problem to a lower mip level, where it still happens. So then the best approach is to position and pad at power-of-two sizes so only the very lowest mip levels exhibit any bleed. Then you find transparency still bleeds in to the edge pixels. So you need to repeat the outer pixels of the image. Repeating it once doesn't solve the problem for low mip levels, because transparency still bleeds in again. So you need to repeat the outer pixels until they fill the entire power-of-two sized cell it's been placed in. Then for good measure, center the image within that.

    This is just a single aspect of spritesheeting, regarding resizing smaller. It has been directly informed by bug reports from real users with real problems. There are many other caveats involving memory usage, efficiency, compatibility, rendering quality, etc. I think this has led Construct to a more sophisticated spritesheeting algorithm than other tools. For example I don't think I've seen any other tools that provide an option for automatic power-of-two padding to solve the mipmapping bleed issue. Providing a customisable padding is the first-level solution to that, but doesn't really solve the problem properly; the power-of-two padding is the second-level solution that we've ended up with. So to me this looks like they have not yet run in to all the same issues as we have yet, so have not developed the algorithm as far along as we have. This is the case in other areas too, such as repeating the outer pixels in to the padding to avoid bleed either between other images, or with the transparent background of the spritesheet, since it ensures even fractional texture sampling right at the edge of an image returns the same color pixel.

    On top of that, AFAIK there's no reason to keep spritesheets square, it simply wastes memory. It's impossible to keep everything on one sheet, because eventually you hit the maximum texture size limit - avoiding that makes multiple spritesheets mandatory. And so on.

    In short I think we have a much more refined and well-developed spritesheeting engine than most people think. Adding more options unnecessarily burdens users with difficult technical choices with tradeoffs they might not understand, and in some cases are wasteful or unnecessary. Since it makes a big difference I think the max spritesheet size is the sole exception to this. It'll turn up in the next beta cycle so you can try it out.

  • One thing i noticed with C3's spritesheeting is that spritesheets can be quite scrambled. You can have some animationframes from a single sprite, ending up on different sheets. So you get texture swap during the sprite animation. I havn't tested if it has any significant performance overhead though.

    One thing I did like about C2's way of handing spritesheets, regardless if it was more efficient or not was that when you exported the projected, the spritesheet was per object. So I could easily go in after export and apply color correction, and some other final touches.

    C3's exported spritesheets are scrambled and are often using shared sheets. Shared sheet's might be good in some cases, but what about if one sheet contains a lot of images that are not even used in the current layout. You're loading a huge shared sheet with a lot of useless sprite data that you're not currenlty using in the layout. I think that's the biggest problem.

    C2 didn't have any shared sheets, that's why It made sense to manually bundle Common UI elementes in one sprite object for example, since it was going to be used in several layouts.

    Here's an example of exported Kiwi story sprite sheet. Using a shared sheet with sprites from 3 different levels.. Cave, Forest, Temple. Levels, title screen.

    Edit2:

    I think it would make more sense to have a toggle for using shared sheets or not. Because the shared sheets are scrambled each layout you probably have to load a HUGE shared sheet even if you're only using one tiny sprite in that sheet on your current layout.

    Edit 3:

    Thinking about it some more, shared sheet is not a very good idea at all. Unless your game is pretty small and using pixel art and you can your whole game can be loaded in to memory. No loading times and load screens. But in any other case scrambled shared sprite sheets are not very desirable.

  • That's the "problem", you get more performance, but you use a lot of memory.

    Ashley explains it on page 1 of this post.

  • r130 seemed to be even worse with the shared sheets. Here's another one even bigger shared sheet. Shared across all layouts.

    I was under the impression that changing layout, would unload unused sprites, and loaded only the ones needed for that layout. While using these kind of HUGE shared sheets you load a bunch of unnecessary images, backgrounds and graphics kind of beats the purpose of unloading things from memory, as the shared sheets contain everything anyways and are completey scrambled.

    Ashley Could shared sheets possibly be a toggle?

  • Shared sheet's might be good in some cases, but what about if one sheet contains a lot of images that are not even used in the current layout.

    An upcoming release groups objects on to spritesheets according to those which are used together on layouts, which is aimed at solving exactly this. However with a couple of projects I tested, it didn't seem to make a big difference to memory usage, which I think indicates it's not a major problem.

    I don't think Kiwi Story is a very good example, because it's pretty tiny in terms of memory usage - only around 20mb or so. This is small enough that it's probably better to group as much as possible on to the fewest number of spritesheets, to get the maximum performance. It's only really important for scalability, when you have games which use hundreds of megabytes of image memory.

  • I still believe though that some minor degree of user setting would be good, like:

    Toggle for Shared sheets on or off,

    Max sheet size maybe?

    I'm sure you don't want to confuse newbies, but I'm also not sure that "one size fits all" approach is very good either.

    Games can vary greatly in terms or complexity and amount and size of assets used, so some minor control on the users end is always good. It doesn't have to be any complex settings. Just toggles or a choose A, or B, C, then we can at least easily test witch settings works best for our game. The default could of course be something with a balanced performance/memory usage...

  • I fear we're just going round in circles, because we already covered a max spritesheet size setting.

  • ...we already covered a max spritesheet size setting.

    And it's coming in the next beta release! Thanks Ashley, hopefully that helps Taximan's memory use.

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)