Question Quel est le moyen le plus rapide de dessiner sur une toile HTML 5?


J'étudie la possibilité de produire un jeu en utilisant uniquement le canevas HTML comme support d'affichage. Pour prendre un exemple de tâche que je dois faire, je dois créer l'environnement de jeu à partir de plusieurs tuiles isométriques. Bien sûr, travailler en 2D signifie qu'ils sont nécessairement fournis dans des boîtiers rectangulaires, de sorte qu'il y a un grand chevauchement entre les carreaux.

Je suis assez vieux pour que la solution naturelle à ce problème soit d'appeler BitBltMasked. Oh, attends, non, un canevas HTML n'a pas quelque chose d'aussi simple et plaisant que BitBlt. Il semble que le seul moyen de transférer des données de pixels dans un canevas soit drawImage () qui ne dispose pas de modes de dessin utiles qui ignorent le canal alpha ou d'utiliser des objets ImageData contenant les données d'image dans un tableau. accès. est. bornes. vérifié. et. donc. chien. lent.

OK, c'est plus une question qu'une question (les choses comme le W3C ont tendance à me provoquer), mais ce que je veux vraiment savoir, c'est comment dessiner rapidement sur une toile? J'ai beaucoup de mal à abandonner le sentiment que faire 100s de drawImages () une seconde où chaque tracé respecte la couche alpha est intrinsèquement pécheresse et susceptible de faire fonctionner mon application comme un cul dans de nombreux navigateurs. D'un autre côté, la seule façon d'implémenter BitBlt proprement dit repose fortement sur un navigateur utilisant une technique d'exécution de type hotspot pour le faire fonctionner rapidement.

Existe-t-il un moyen de parvenir rapidement à toutes les implémentations possibles ou dois-je simplement oublier les performances?


12
2018-01-18 21:03


origine


Réponses:


C'est un problème très intéressant, et vous pouvez faire certaines choses intéressantes pour le résoudre.

Tout d'abord, vous devez savoir que drawImage peut accepter une toile, pas seulement une image. Les sous-canevas n'ont même pas besoin d'être dans le DOM. Cela signifie que vous pouvez faire de la composition sur une toile, puis la dessiner sur une autre. Cela ouvre tout un monde d'opportunités d'optimisation, notamment dans le contexte des tuiles isométriques.

Disons que vous avez une zone de 50 tuiles de long sur 50 de large (je dirai des mètres pour ma santé mentale). Vous pouvez diviser la zone en morceaux de 10x10m. Chaque morceau est représenté par sa propre toile. Pour dessiner la scène complète, il vous suffit de dessiner chacun des objets Canvas de chaque morceau dans le canevas principal affiché à l'utilisateur. Si seulement quatre morceaux (une zone de 20x20m), vous ne feriez que quatre drawImage opérations.

Bien sûr, chacun de ces blocs individuels devra rendre son propre canevas. Sur les ticks de jeu où rien ne se passe dans le morceau, vous ne faites tout simplement rien: le canevas restera inchangé et sera dessiné comme prévu. Lorsque quelque chose change, vous pouvez faire une des choses en fonction de votre jeu:

  1. Si vos tuiles s'étendent dans la troisième dimension (c'est-à-dire que vous avez un axe Z), vous pouvez dessiner chaque "couche" du morceau dans sa propre toile et ne mettre à jour que les couches qui doivent être mises à jour. Par exemple, si chaque bloc contient dix couches de profondeur, vous disposez de dix objets Canvas. Si quelque chose sur le calque 6 a été mis à jour, il vous suffira de repeindre le canevas de la couche 6 (probablement un drawImagepar mètre carré, qui serait 100), puis effectuez une drawImage opération par couche dans le morceau (dix) pour re-dessiner le canevas du morceau. La diminution ou l'augmentation de la taille du bloc peut augmenter ou diminuer les performances en fonction du nombre de mises à jour apportées à l'environnement dans votre jeu. D'autres optimisations peuvent être faites pour éliminer drawImage appelle des tuiles obscurcies et similaires.
  2. Si vous n’avez pas de troisième dimension, vous pouvez simplement en effectuer une. drawImage par mètre carré de morceau. Si deux morceaux sont mis à jour, ce n'est que 200 drawImage appels par tick (plus un appel par morceau visible à l'écran). Si votre jeu comporte très peu de mises à jour, la diminution de la taille des blocs réduira encore le nombre d’appels.
  3. Vous pouvez effectuer des mises à jour des morceaux dans leur propre boucle de jeu. Si vous utilisez requestAnimationFrame (comme vous devriez le faire), il vous suffit de peindre les objets Canvas à l’écran. Indépendamment, vous pouvez effectuer une logique de jeu dans un setTimeout boucle ou similaire. Ensuite, chaque bloc peut être mis à jour dans sa propre coche entre les images sans affecter les performances. Cela peut également être fait dans un web worker en utilisant getImageData et putImageData renvoyer le fragment rendu au thread principal chaque fois qu'il doit être mis à jour, bien que cela demande beaucoup d'efforts.

L'autre option est d'utiliser une bibliothèque comme pixi.js pour rendre la scène avec WebGL. Même en 2D, cela augmentera les performances en diminuant la quantité de travail nécessaire à la CPU et en la déplaçant vers le GPU. Je recommande fortement de le vérifier.


3
2018-05-11 22:51



je le sais GameJS a des opérations de blit, et je suppose certainement que toutes les autres bibliothèques de jeux HTML5 fonctionnent aussi bien (gameQuery, LimeJS, etc.). Je ne sais pas si ces paquets ont résolu le problème spécifique de vérification des limites de tableau que vous aviez, mais dans la pratique, leurs échantillons semblent fonctionner rapidement sur toutes les plates-formes.

Vous ne devriez pas faire de suppositions sur ce que les accélérations ont de sens. Par exemple, le développeur GameJS signale qu'il allait mettre en œuvre un suivi de rectangle sale, mais il s'est avéré que les navigateurs modernes le font automatiquement ---lien.

Pour cette raison et pour d'autres, je suggère de faire quelque chose avant de penser à la vitesse. Utilisez également des bibliothèques de dessin, car les auteurs ont probablement passé un certain temps à optimiser les performances.

Je n'ai aucune connaissance personnelle à ce sujet, mais vous pouvez regarder dans l'élément HTML "direct canvas" appMobi qui est censé être une version beaucoup plus rapide du canevas normal, lien. Je ne comprends pas si cela fonctionne dans tous les navigateurs ou seulement dans les navigateurs Webkit ou seulement dans le navigateur spécial appMobi.

Encore une fois, vous ne devez pas faire de suppositions sur ce que les accélérations ont de sens sans une connaissance très approfondie des processus internes des navigateurs Web. Cette page Web sur le "canevas direct" mentionne un tas de choses qui ralentissent le dessin sur toile: "Reflet du texte, mappage des points chauds, création d'index pour les liens de référence, etc." Le mélange alpha et la vérification des limites de tableau ne sont pas mentionnés comme des causes importantes de lenteur!


1
2018-05-11 13:31



Malheureusement, la composition de l’alpha ne peut pas être dépassée. Le clipping peut être une solution, mais je doute qu'il y ait beaucoup, voire aucun gain de performance. Sans parler de la complexité d'une telle voie à mettre en œuvre sur des formes irrégulières.

Lorsque vous devez dessiner l’affichage complet, vous allez devoir faire face à la performance. Bien que, par la suite, vous disposez d’une image alpha pré-calculée sur tout l’écran, vous pouvez dessiner ces données d’image avec un décalage dessinerImage appel. Ensuite, il vous suffira de dessiner individuellement les nouvelles tuiles qui défilent pour les afficher.

Mais encore, le navigateur doit redessiner chaque pixel à un endroit différent de la toile. Ce qui est assez cher. Ce serait bien s'il y avait une méthode pour faire défiler les pixels, mais pas de chance non plus.

Une idée qui vient à l'esprit est que vous pouvez mettre en œuvre plusieurs toiles, traduisant chaque individu Toile au lieu de redessiner les pixels. Cela permettrait au navigateur de décider comment redessiner ces pixels de manière plus native, du moins en théorie du moins. Ensuite, vous pouvez rendre les tuiles nouvellement visibles sur un élément de canevas neuf, ou utilisé / mis en cache. Le positionner pour correspondre au dernier rendu d'écran.

Mais ce ne sont que mes deux blit ... Je veux dire des morceaux ... Duh, je veux dire des cents:]


0
2017-08-04 08:12