Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Is having 1 Trillion Textures or more bad

Discussion in '2D' started by Rizembus, Feb 23, 2019.

  1. Rizembus

    Rizembus

    Joined:
    Sep 13, 2014
    Posts:
    29
    -Lets say i have a character composed of 30 layers of sprites

    -Lets say i need to have over 500 of these characters on screen at the same time.
    -Because of this using 30 sprite renderers per character kills performance so that is a no go
    - However if each character had only 1 sprite renderer all would be well

    -Lets say i use texture2d set pixels to overlay the 30 layers into 1 texture and make a sprite
    - however i cant call this outside of loadings because texture.apply crashes the game for 2secs but i can use it to create every combination of 30 sprites ahead of time and call them later from a dictionary

    but things get complicated when each layer has more than 2 options; 2^30 combinations becomes and outrageous number of textures ( 1 trilion ) and this would be only the beggining

    just having them as png with 2kb per png would mean 1000 Terabytes of space...

    Now the question:

    is there a way to store this amount of textures in a feasible way? Maybe by serializing it in a dictionary of bytes in a binary formatter?

    Even if it was would having these amount of textures in memory overload the ram into oblivion?

    Or is there someway to speed up texture.apply?

    I could solve this by having a big loading to create all animations for a given combination each time a piece of equipment is changed (this avoids the need to have every combination on call) but this may be very off putting to the player who is just switching around his equipment, or when another character switches their equipment...

    Any thoughts would be appreciated, it may help me look at it from a new perspective
     
  2. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,754
    As per thread title, you have answers your own question already.

    Other than that, you are approaching problem from wrong angle. Firstly, you can use material instancing, to reduce rendering material calls. Then consider use shaders? For changing color for example. You can combine static none animated textures, into single texture for sprite. Then you will end up with only handful number of sprites per char.
    One static and few animated at most. Use atlasses.

    And finally, reduce number of enemies.
     
  3. Rizembus

    Rizembus

    Joined:
    Sep 13, 2014
    Posts:
    29
    Thanks for the reply,

    the shader is a nice solution for the colors but the bulk of the layers differs by shape and animation, the batching and atlassing is a non issue if i could only setup the sprites i needed in advance. each character would have north of 20 animations for each direction also.

    its hard to cut down on enemies the game is about clashing armies, like an RTS
     
  4. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,754
    Can you post screenshot, of what you are trying achieve? Seams somehow overcomplicating.
     
  5. foxnne

    foxnne

    Joined:
    Apr 18, 2016
    Posts:
    59
    Hi.

    I don't have as many textures and combinations as you, but Im solving a similar problem with layered sprites on characters using Texture2DArrays.

    I'm still working this out, so this isn't perfected. but the small tests Ive done seem promising.

    Here's the long version of my thought process and how it works, I'll put a TLDR at the end:

    To benefit from batching, 3 things have to be fulfilled to my knowledge:

    1. Objects must use the same material.
    2. Objects must use same texture within that material.
    3. Objects must be rendered without a seperate material drawn between them.
    If these are satisfied, two objects will be drawn as a single draw call.

    The third gotcha is what I was unaware of, but testing revealed it. Setting the camera to sort on the y axis for my top-down game is a must, and when using this, if a second sprite of a different material is between two sprites sharing a material along the sorting axis, a draw call is added.

    In my mind, this means trying to share materials between each character is not worth doing unless your game has tons of characters. It becomes less worth it when your sprite atlases will become large and spread across multiple atlases meaning multiple draw calls per character anyway, potentially, dependent on the combination of sprites.

    So my thinking was, only for these layered characters, to instead make small sprite sheets for a single animation, per outfit piece. So for my game, a small 8 frame sheet for body, head, hair, clothing, etc. Would represent a walk animation in a single direction. These small sheets are easily created in my software (pyxel edit) as I can export an animation as a square sheet (mine are 128x128).

    Then I keep a collection of these sheets, with each sheet being an "animation". Durin runtime, when I need to switch animations or outfits, i can generate a texture2DArray with each layer indexed in the array using Graphics.CopyTexture.

    So far, especially with such small sheets, this function is performing very quickly with 10 layers. Again, i only replace the texture2dArray layers when an animation changes.

    Then, using a shader, i sample through the indices and overwrite each layer "flattening" the images on a quad. I then animate the UVs to animate the sprite.

    The result is that each character regardless of layers is a single draw call and i only load the textures necessary for the currently playing animation.

    I hope this helps. I need to do more stress testing soon and double check that Graphics.CopyTexture is fast enough, but it seems to be made for GPU side copying. Copying textures into the array seems very fast.

    TL; DR:

    I'm splitting my sprites into small sprite sheets containing only one animation/outfit per sheet. I manage these sheets myself and choose which to load into a Texture2DArray for the current situation using Graphics. CopyTexture . I then animate the UV of the quad Im drawing to to animate the texture.
     
  6. Nivbot

    Nivbot

    Joined:
    Mar 21, 2015
    Posts:
    65
    If you are using that many sheets for animations and what not why not just use anima. It’s a great tool. Cuts waaaaaay down on images and is much smoother than frame by frame sprite sheets
     
  7. foxnne

    foxnne

    Joined:
    Apr 18, 2016
    Posts:
    59
    Can't speak for OP but usually the reason is preferring the look of frame based animation. I'm not a huge fan of the paper doll look in general, but with pixel art, it's extra jarring. It can look really nice with higher res sprites though.
     
  8. Nivbot

    Nivbot

    Joined:
    Mar 21, 2015
    Posts:
    65
    1.5mb per 2048 sprite sheet for maybe 3 animations if you scrimp on them. Or like 20 mobs on one 2048 sprite sheet that you can make any animation you want with and can combine the meshes into one making each part of the sprite into one draw call.

    I mean the space and times saved is tremendous. And the paper doll thing isn’t a big issue if you animate well enough. There are things you can do with frames that you can’t with anima but that’s what particles are for.

    Anyway, whatever he is trying to do is just not going to be possible. Like not even close to possible.
     
    foxnne likes this.
  9. foxnne

    foxnne

    Joined:
    Apr 18, 2016
    Posts:
    59
    The solution i posted makes it possible. Even with 10 layers for different character parts, which is trivial to draw as you draw it as a whole character, and lots of variations, the number of different combinations gets exceedingly high.

    This doesnt mean you have that many individual textures. Just that many combinations. Using the texture2DArray method I outlined, you only load the number of textures at the size you need for a single animation and draw that animation until it needs to change.

    It also means a single gameobject and renderer regardless of numbers of layers you need, as the shader handles collapsing these layers.

    While its true that anima cuts down on the number of frames, it wont help with the number of combinations of sprite reskins. He will still need to swap out each piece of the animation as he is needing to do now.
     
  10. Nivbot

    Nivbot

    Joined:
    Mar 21, 2015
    Posts:
    65
    Swapping a out a ready made sprite object is a lot simpler in my opinion. And you’re doing basically the same but with whole frames that need space for each frame. Images are the bulk of the game size. Again, it depends on what you’re trying to do but the ease of use of anima makes it very nice. The reduction of file size is simply astronomical

    I don’t really know exactly what he’s trying to do but it sounds like it would be much easier than messing with 30 layers for an animation.
     
  11. foxnne

    foxnne

    Joined:
    Apr 18, 2016
    Posts:
    59
    Im not positive of his sprite size. but he states a 2kb png. So that would be very small.

    Even with anima, if you wanted to do character customization with different types of hair, clothing, body shapes, equipment, etc. You would still have this issue. 30 layers is a lot, but you would deal with this problem sooner than you would issues due to number of frames. If his pngs are 2kb it's likely pixel art.

    With my own, characters are 32x64px. Animations are only 8 frames. I could save space with anima, but 8 frames is only 128x128 at that size.

    So yes, anima would save me 8 frames per animation over all combinations, but the size of the images im using already is very small. Uncompressed, it seems to be around 20kb per png for me, which is an entire animation. With top down as mine is, that gets multiplied by 5 for 5 directions, 3 of which will be mirrored for the other 3 directions.

    So now I'm at 100kb for an animation in 8 directions. Multiply by 10 for 10 layers and I'm now at 1mb. I'd say that's pretty insignificant. A variation of clothing for me is only adding 100kb per animation.

    I don't mean that you're wrong. But I can see where the art style would drive one away from anima and need to come up with some new solution to handle so many variations of sprites. Even with anima.

    No doubt its easier with anima though.
     
  12. Nivbot

    Nivbot

    Joined:
    Mar 21, 2015
    Posts:
    65
    1mb is insignificant itself yes, but when you have NPCs and mobs it adds up. If you’re making for pc or Mac then no big deal regardless. On phone it gets more important.

    But yes, you can certainly do it in another ways and there’s nothing wrong with that, especially if you want to use frames.

    Personally, I don’t have time to make all my art (I can draw but making game level art is also a problem) so I have to buy it and if I buy a commissioned one it’s much cheaper to get a paper doll made than a series of frames that may or may not be sufficient once it’s in game. This way, if I find myself needing a bow animation I can just do it in like 1 minute in the animator.
     
  13. zioth

    zioth

    Joined:
    Jan 9, 2019
    Posts:
    111
    If you really have that many combinations after the suggested optimizations from other posters, you can render the layered textures on the fly, and cache them in a LRU cache. You may have a trillion possible texture combinations, but like you said, only 500 will be on the screen at any given time. Cache the most recently used 2000, and you'll be in good shape, without needing an overwhelming amount of storage.

    Or you can make some trade-offs between storage and performance. Every combination of 30 textures gives you a trillion, but if you're willing to render two layers instead of one, you're down to a million. Render four layers, and you're down to just a thousand combinations. Not great, but better than 30.
     
    foxnne likes this.
  14. Rizembus

    Rizembus

    Joined:
    Sep 13, 2014
    Posts:
    29
    Thank you for the replies, I solved this by merging every sprite on demand, i create a small loading everytime a character changes equipment to create all the textures for that character. I discovered that what was eating through my cpu was not texture.apply but the getpixel loop which was going through each pixel of a 320x320 image.( a lot of useless checks since most of the image was empty space, so i filled a dictionary with all the pixels that contained color and a 1million pixel loop became just a 20 pixel loop per png. I create the dictionaries ahead of time(this may take days but its me waiting not the player) and then save them to a list which i then load on start, so every pixel position in every image is already know and this makes it very fast to create only the combinations that are in use. ( of 1 trillion or 1 quadrillion of combinations i only render the ones I need on demand, and unload them from memory when they are no longer used )

    Ps - about the art aspect, since I'm more pixel artist than coder I really focus on my art and style, I do all my art myself, I understand if some people like to use the fast animating tools but i just dislike the feel of these animations. Probably like the relationship between a professional C# dev and telling him to use playmaker
     
    Last edited: Mar 9, 2019