Je pose cette question parce que je n'ai pas trouvé de réponse définitive.
Permettez-moi tout d'abord de dire quelques choses sur le jeu et ce que j'ai déjà fait. Le jeu va être un RTS situé dans un monde généré de manière procédurale utilisant du bruit Simplex. Le monde se compose de morceaux de 16 x 16 en sprites de 64 x 64. J'ai réussi à charger et à décharger des morceaux de manière dynamique, ce qui fonctionne très bien. Le monde va ressembler un peu à Rimworld, donc de haut en bas avec différentes couches de sprites (terrain d'abord, sprites de transition, arbres, décalcomanies, etc.). Les mondes nouvellement générés peuvent contenir des entités qui peuvent affecter l'environnement (par exemple, un village qui est devenu une ville) et donc le morceau. Je suis sûr que cela peut être calculé en utilisant une sorte de fonction, mais c'est quelque chose à noter.
Le principal problème que j'ai, c'est quand je fais un zoom arrière, de plus en plus de tuiles sont dessinées, ce qui affecte gravement les performances. À environ 30000 sprites, la section de tirage prend 8 ms, ce qui est la moitié de ce qui est requis pour fonctionner à 60 FPS. Et c'est juste le terrain. J'utilise des atlas de texture pour limiter le nombre de tirages (30000 sprites dessinés en 6 coups).
L' objectif est de pouvoir effectuer un zoom arrière du niveau de la ville / du village / de la ville jusqu'à pouvoir voir un pays entier. Cela doit être fait de manière dynamique (par exemple, pas en cliquant sur une icône de mini-carte, mais juste en arrière comme dans Supreme Commander).
J'ai lu de nombreux articles sur ce problème, mais je n'ai pas trouvé ni vu un exemple clair de son fonctionnement. Voici une liste de techniques que j'ai trouvées qui sont censées fonctionner:
- Rectangles sales, comme décrit ici , où vous ne dessinez que de nouvelles choses et gardez le reste dans le backbuffer. Cela a beaucoup de sens, mais je ne sais pas comment l'implémenter dans Monogame.
- Mon choix préféré: faites un usage intensif de RenderTargets, comme décrit ici , où vous dessinez vers un RenderTarget puis enregistrez-le en tant que texture. Dans mon cas, un bloc 16 x 16 composé de 64 x 64 créerait une texture 1024 x 1024. Je doute vraiment que cela fonctionne en termes de performances, mais le résultat consisterait en des textures très détaillées et est également excellent à utiliser étant donné que la plupart d'entre elles sont statiques (terrain / arbres, etc.), et ne changent pas autant. Mais cela signifie également que chaque fois qu'un changement est apporté à un morceau, que Texture2D doit être modifié à l'aide de SetData, qui d'après ce que j'ai vécu est assez gourmand en ressources processeur. Cependant, si les textures étaient de 16 x 16, cela pourrait en fait fonctionner, et cela réduirait également l'utilisation de la mémoire et du disque.
- Til textures en spécifiant le SourceRectangle dans SpriteBatch. Pour les vastes prairies / océans, c'est un plus, car un seul sprite est dessiné. Cependant, pour un terrain détaillé avec différentes couleurs et différents sprites mélangés (biomes et transitions de biomes), je crains que cela ne fasse pas une énorme différence.
- Ma propre solution, qui compromet les détails, était d'utiliser une tuile blanche standard de 64 x 64, de lui donner la couleur des 4 tuiles environnantes, puis de la mettre à l'échelle pour qu'elle couvre les 4 tuiles précédentes. La différence ici (en plus de la tuile de couleur unie) est que le paysage a visiblement changé. Je dois également mentionner que les forêts doivent encore être dessinées individuellement car elles ne sont pas parfaitement carrées.
Si quelqu'un a une idée de la façon de résoudre ce problème, même si cela signifie compromettre certaines choses (comme les détails ou utiliser des sprites 16 x 16), j'aimerais l'entendre.
Réponses:
Les cartes graphiques sont optimisées pour dessiner plusieurs choses plusieurs fois plutôt que l'inverse.
Dans votre cas, vous avez beaucoup de choses (différentes textures) que vous souhaitez dessiner beaucoup de fois (nombre de tuiles).
IMO, les optimisations les plus simples que vous pouvez faire pour obtenir des gains de performances significatifs sont:
Je recommanderais de faire les deux choses. Bonne chance.
la source
J'ai découvert que SpriteBatch ne convient pas pour dessiner des carreaux. L'une des raisons est que les sprites sont destinés à des objets dynamiques et sont utilisés à des fins multiples. Une autre raison est qu'il est incroyablement lié au processeur , par exemple. comme expliqué dans le dessin de description, 30 000 objets coûtent 8 ms (alors que mon chipset a atteint un maximum de 30%). De plus, jusqu'à 3 000 sprites peuvent être dessinés avant qu'un nouvel appel de tirage ne soit effectué vers le GPU (par lots et tous).
La solution était de dessiner mes propres tuiles en utilisant des quads texturés . Ceci en combinaison avec un VertexBuffer m'a permis de dessiner jusqu'à 500 000 tuiles texturées en 1 appel de tirage où la méthode de tirage a consommé environ 1 / 20e de milliseconde. Bien sûr, je n'aurai probablement pas à en tirer autant, mais dans tous les cas, j'ai finalement obtenu que mon GPU ait une charge de travail de 75% à 60 images par seconde.
la source