Dois-je utiliser des feuilles de sprites, à cause ou malgré mon grand nombre d'images?

13

Je développe un jeu 2D et j'ai beaucoup de sprites. J'ai utilisé des animations et des modèles 3D pour effectuer un rendu en 2D, pour leur donner un aspect "Fallout" ou "Diablo". C'est aussi plus facile que de dessiner à la main, lol.

J'ai déjà dû réduire le framerate à 15 images par seconde, ce qui était le plus bas que je pouvais abaisser sans leur donner un aspect saccadé. Cependant, c'était triste à cause de la fluidité incroyable de 24 images.

Il y a deux raisons pour lesquelles j'ai fait cela:

1) Réduisez l'espace disque dur. Moins il y a d'images, plus mon jeu sera petit.

2) Réduisez la consommation de RAM. Moins il y a d'images à charger, plus j'ai de chances d'éviter les problèmes de gonflement de ma limitation de RAM.

Cependant, s'il y avait un moyen de compresser les images dans l'espace disque dur et la RAM, je le ferais. Je l'ai testé auparavant, et la plupart ne reçoivent aucun changement de qualité lors du passage de RGBA8888 à RGBA5555 et seulement un petit coup lors de la conversion en RGBA4444 dans mon programme TexturePacker. Je ne le fais pas actuellement, car SFML semble utiliser la même quantité de mémoire quel que soit le type d'image .PNG dont il s'agit. J'ai cherché à le charger différemment, mais je n'ai rien trouvé sur le sujet.

J'ai beaucoup lu sur la façon de gérer les jeux vidéo 2D. Le consensus est écrasant: emballez vos Sprites dans une texture plus grande pour de grandes performances! J'ai donc emballé mes minuscules sprites dans une feuille de sprites beaucoup plus grande en utilisant TexturePacker.

Cependant, je prévois d'avoir 10 à 15 animations par personnage, 5 directions pour se déplacer et 15 à 40 images par animation (probablement une moyenne de 24). Avec 15 animations, 5 directions et une moyenne de 24 images par animation; Soit 1800 images individuelles par caractère. S'il est emballé dans une feuille de sprite, cela ne représente que 75 images à la place. (Une feuille de sprite par animation, par direction. 15 * 5)

Pour le seul grand boss du jeu, je ne peux pas utiliser de feuille de calcul et je dois programmer un moyen de charger simplement une image à la fois. Je ne sais pas encore si je peux le faire pour la performance.

Pour les personnages, je les ai déjà emballés dans une feuille de sprites. Pour un seul personnage qui se promène, cela semble fonctionner la plupart du temps, même si parfois cela cale. Cependant, j'attribue cela à mon code mal conçu qui permute les textures au lieu de précharger toutes les textures pour ce personnage.

Si je devais précharger les textures, cela a du sens pour les feuilles de sprite. J'imagine que c'est une mauvaise idée de précharger 1800 minuscules images pour chaque personnage.

Cependant, j'imagine que les diffuser dans et hors de la mémoire une par une serait extrêmement rapide, donc je n'aurais besoin que d'une seule image en mémoire à la fois. Cela ne signifierait-il pas qu'à un moment donné, je ne ferais que consommer par Ko quelques caractères au lieu de 45 + Mo?

J'imagine que cela tuerait mes performances, car le streaming devrait être incroyablement rapide (15 images entrant et sortant de la mémoire et du rendu, par seconde) et bien que les images soient très petites, il serait peut-être préférable de charger des feuilles de sprites de caractères en mémoire à la place. Mais je devrai quand même coder un système de rendu de type image unique pour mon plus grand personnage.

J'ai expérimenté, mais ce n'est pas un processus simple. Surtout étant donné que je travaille sur d'autres parties du moteur de jeu qui ne traitent pas actuellement avec les graphismes.

Carter81
la source
1. Vous n'avez pas spécifié vos contraintes de RAM ou de disque dur. Combien de personnages doivent être en accès rapide? 2. Il y a plusieurs questions le long du texte, peut-être pourriez-vous les concentrer en gras ou même diviser les questions en parties?
Kromster dit soutenir Monica le
Oh je suis désolé. Pas beaucoup. J'imagine que le nombre maximum de caractères individuels à l'écran à tout moment serait d'environ 40. Si les gens se faisaient un devoir d'essayer de planter leurs clients, alors ... 130 est le maximum absolu. En règle générale, il ne devrait y avoir que 10 pour le max typique, et le max absolu ne serait pas supérieur à <40. Tout ce qui dépasse 40 serait une rareté extrême, extrême, avec des utilisateurs essayant délibérément de bourrer des personnages sans autre raison qu'une capture d'écran ou pour le plaisir de bourrer des personnages. Tout ce qui est supérieur à 10 est rare, et tout ce qui est d'environ 40 est extrêmement, extrêmement rare.
Carter81
Le jeu est un rpg 2D uniquement sur PC (pas mobile), mais je ne voudrais pas exclure une plate-forme mobile à moins que ce ne soit tout simplement pas faisable. J'imagine que l'espace RAM dont je dispose est limité à la RAM sur le PC de l'utilisateur et à la VRAM de l'utilisateur. Je doute fortement que ce soit un disque dur de très grande taille. C'est juste qu'il est toujours vrai pour la consommation de disque dur que plus il est petit, mieux c'est.
Carter81
Combien de personnages UNIQUES devez-vous avoir à l'écran?
Kromster dit soutenir Monica le
Pas plus de 20. Tout ce qui est au-dessus de cela serait presque impossible à moins qu'ils ne trichent. Généralement 5-10.
Carter81

Réponses:

16

Nous avons un cas similaire avec notre remake RTS. Toutes les unités et maisons sont des sprites. Nous avons 18 000 sprites pour les unités, les maisons et le terrain, plus ~ 6 000 pour les couleurs des équipes (appliquées comme masques). Long-étiré, nous avons également environ 30 000 caractères utilisés dans les polices.

Donc, la principale raison derrière les atlas est:

  • moins de RAM gaspillée (dans les anciens jours lorsque vous téléchargez NPOT sur GPU, il l'étirait / le rembourrait sur POT, je lis que c'est toujours la même chose avec iOS et certains cadres. Vous feriez mieux de vérifier la gamme de matériel que vous ciblez)
  • moins de commutateurs de texture
  • chargement plus rapide de tout en moins de gros morceaux

Ce qui n'a pas fonctionné pour nous:

  • textures palettisées. La fonctionnalité n'existait que dans OpenGL 1.x 2.x et même alors, la plupart du temps, elle a été abandonnée par les fabricants de GPU. Cependant, si vous visez OpenGL + Shaders, vous pouvez le faire très bien dans le code des shaders!
  • Les textures NPOT, nous avons eu des problèmes avec de mauvaises bordures et des sprites flous, ce qui est inacceptable dans le pixel art. L'utilisation de la RAM était également beaucoup plus élevée.

Maintenant, nous avons tout emballé dans plusieurs dizaines d'atlas 1024x1024 (les GPU modernes prennent en charge des dimensions encore plus grandes) et cela fonctionne très bien en ne consommant que ~ 300 Mo de mémoire, ce qui est très bien pour un jeu PC. Quelques optimisations que nous avons eues:

  • ajouter une option utilisateur pour utiliser RGB5_A1 au lieu de RGBA8 (ombres en damier)
  • éviter l'alpha 8 bits lorsque cela est possible et utiliser le format RGB5_A1
  • emballer étroitement les sprites dans des atlas (voir Algorithmes d'emballage de bin)
  • stocker et charger tout en un seul morceau à partir du disque dur (les fichiers de ressources doivent être générés hors ligne)
  • vous pouvez également essayer des formats de compression matérielle (DXT, S3TC, etc.)

Lorsque vous envisagez sérieusement de passer à des appareils mobiles, vous vous inquiétez des contraintes. Pour l'instant, lancez le jeu et attirez les joueurs! ;)

Kromster dit soutenir Monica
la source
C'était de loin la meilleure solution! Mes sprites ne sont même pas différents dans RGB5_A1 ou RGBA4444, mais cela économise de la mémoire. Une suggestion dans le chat pour précharger tous mes actifs en RAM et VRAM est parfaite. Encore plus loin, vous avez suggéré d'avoir des niveaux graphiques optionnels, comme un client haute définition pour ceux qui ont la RAM, ou une option pour réduire le nombre d'images par seconde, etc. Excellentes suggestions tout autour, et exactement ce dont j'avais besoin!
Carter81
5

J'ai une réponse tangentielle ici , mais l'idée générale est que, si vous chargez et dessinez des textures à des moments différents (vous ne chargez pas de textures supplémentaires pendant le rendu), il y a deux endroits où ce que vous cela affectera vos performances:

Temps de chargement:

C'est le moment où vous téléchargez vos textures en mémoire. La quantité totale de données que vous envoyez à VRAM est ce qui définira principalement la durée de votre chargement. Faire de vos textures des formats plus petits, comme RGBA4444, rendra cela plus rapide. Cependant, à moins que vous ne téléchargiez des textures de centaines de mégaoctets sur VRAM, vous n'aurez probablement pas de goulot d'étranglement ici. Si vous le faites, un joli écran de chargement peut faciliter l'attente.

Joindre vos textures dans des atlas aura peu d'effet, car la quantité totale d'informations que vous envoyez dans VRAM sera la même. En fait, si vous atlasez vos textures et que vous devez laisser des espaces vides dans vos atlas, vous enverrez en fait plus de données dans la VRAM, et donc cette partie sera plus lente!

Performances de rendu:

Une fois que toutes vos textures sont en VRAM, la quantité de textures que vous avez n'affectera pas les performances de rendu. Quatre éléments affectent vos performances de rendu:

  1. Modifications de l'état du rendu : chaque fois que vous modifiez l'image à partir de laquelle vous souhaitez effectuer le rendu, le temps nécessaire pour le rendre augmente considérablement. En général, vous souhaitez minimiser la quantité de changements d'état et vous pouvez réduire la quantité de changements d'état en regroupant plusieurs images que vous dessinerez consécutivement dans un atlas de texture.

    L'atlas ne suffit pas. Vous devez atlaser de manière à réduire les changements d'état afin d'obtenir des gains de performances. Par exemple, on peut penser que le fait d'avoir votre personnage principal dans une feuille de sprite vous donnera un gain de performances, mais si vous ne dessinez qu'un sprite à partir de cette feuille de sprite par image, vous n'obtiendrez aucun gain de performances par rapport à avoir chaque sprite dans un fichier séparé.

    Un bon atlas n'est pas anodin, mais en général, vous pouvez regrouper en toute sécurité les sprites de la même couche. Par exemple, avoir tous les éléments de l'interface graphique dans une seule feuille de sprite est une idée très prometteuse, alors que le regroupement alphabétique des monstres peut ne pas l'être.

  2. Appeler des appels: En général, vous souhaiterez peut-être limiter au maximum vos appels. Une bonne règle est que s'il n'y a pas de changement d'état de rendu entre deux appels de tirage, vous pouvez les joindre en un seul appel de tirage. Pour des gains de performances plus avancés, vous pouvez utiliser, par exemple, 8 échantillonneurs de texture et des appels de dessin de groupe pour toutes les 8 textures, vous n'avez donc qu'à changer les textures toutes les 8 textures.

  3. Nombre de triangles: en fait, plus vous dessinez de triangles, plus il vous faudra de temps pour les dessiner. Cependant, dans les ordinateurs modernes, et pour la plupart des jeux 2D, vous serez très loin de maximiser cela. Vous pouvez dessiner en toute sécurité des centaines de milliers de sprites par image tout en obtenant des fréquences d'images incroyablement bonnes. Vous serez probablement plus lié au processeur si vous dessinez des quantités extrêmes de sprites avant de rencontrer des problèmes avec votre GPU.

  4. Paramètres API: si vous faites tout correctement et que vous obtenez toujours des fréquences d'images étrangement basses, vérifiez les paramètres avec lesquels vous dessinez vos sprites. Je ne connais pas SFML, mais par exemple, dans Direct3D 9, la création d'un tampon de vertex avec D3DUSAGE_DYNAMICou dans D3DPOOL_MANAGEDpeut facilement décupler votre temps de rendu. Bien sûr, l'utilisation de vSync plafonnera votre taux de rafraîchissement au taux de rafraîchissement de votre moniteur. En outre, l'utilisation de FVF non alignés peut réduire les performances de certains GPU. Cela aussi, c'est pour Direct3D 9.

    Dans votre cas, consultez la documentation de l'API que vous utilisez.

Si vous ne disposez que d'une quantité de textures faible à modérée (moins de 1 Go) et que vous dessinez de faibles quantités de sprites (moins d'un million par image), la première chose que je regarderais serait de changer les paramètres de l'API, et puis en réduisant la quantité d'états de rendu et d'appels d'appel.

Pyjama Panda
la source
Si je ne me soucie pas des temps de chargement, dois-je supposer qu'à moins de manquer de RAM ou de VRAM, je devrais simplement tout charger en mémoire au préalable?
Carter81
Je ne m'inquiète que de tout PARCE QUE j'ai peur de manquer de RAM / VRAM. Je ne sais pas pourquoi, mais cela me pétrifie que les utilisateurs qui jouent à mon jeu plantent chaque fois qu'ils essaient de se charger dans une zone contenant trop de sprites uniques, ou se bloquent chaque fois que trop de personnages entrent sur leur écran. Si je ne me trompe pas et que chaque sprite individuel consomme 96 Ko, alors si chaque personnage unique a 15 animations, 5 directions et en moyenne 24 images par animation - chaque personnage individuel entièrement chargé est de 173 Mo. Il peut y avoir 10, voire plus, des personnages uniques à l'écran à la fois.
Carter81
@KromStern: Si vous faites de l'atlas et que vous devez laisser des espaces vides (remplissage), les données seront plus grandes et donc les temps de chargement seront plus longs. Il est clair que la cause des temps de chargement plus longs est l'espace vide et que le temps de chargement total est lié à la quantité totale de données et non à la quantité de textures. Je ne vois rien de trompeur là-dedans, et je pense qu'une personne ayant suffisamment de connaissances pour comprendre la question d'origine, pourra rejoindre les points et tirer ses propres conclusions pour tous les cas lorsque les textures et les atlas sont PoT et nPoT.
Panda Pyjama
1
@ Carter81: Vous devez choisir votre configuration matérielle cible, comme "i5, 1 Go de RAM, NVidia GT260, 400 Mo hdd" et travailler à partir de cela. Il y aura toujours des PC plus faibles et ayant moins de RAM.
Kromster dit soutenir Monica le
De toute évidence, ils n'ont pas besoin des 15 animations à tout moment. Cependant, que se passe-t-il si les 10 personnages uniques passent en "Mode Combat" en même temps, et nécessitent donc 5 ensembles d'animations (marche, course, ralenti, sans combat, etc.) pour être échangés avec 5 autres (marche de combat, combat inactif, combat etc.)? J'ai peur d'échanger des textures parce que lorsque j'ai essayé de le faire avec SFML, cela a créé un gel ou une pause notable du client lors du changement d'atlas de texture. Je ne sais pas quel serait mon goulot d'étranglement avec les différentes stratégies pour gérer autant de sprites.
Carter81