Un nouveau jeu avec une vieille ambiance sur Three.js

Il y a beaucoup de fans de vieux jeux. Et ils ne sont pas opposés à laisser échapper une larme nostalgique avare et non, non, mais à jouer "Arkanoid", "Pakman" ou "Prince of Persia" comme vingt, trente, quarante ou - remplacer le nombre souhaité - il y a des années. DOS-box et émulateurs - pour les aider. Oui, ce qui est là, j'ai récemment regardé un flux du tout premier "Prince of Persia" 2D sur YouTube, où un assez jeune streamer, après avoir passé un autre obstacle mortel, en agitant la sueur de son front avec sa main, a déclaré: "Je n'ai jamais été aussi effrayé dans un jeu d'ordinateur ". Autrement dit, même les jeunes peuvent apprécier le hardcore et la fraîcheur des vieux jeux.


J'ai pensé, pourquoi ne pas créer un nouveau jeu dans un style similaire? Oui, il existe différents remakes et clones. De plus, les jeux modernes dans le style du pixel art ravissent. Cependant, tous, en règle générale, répètent des quêtes, des mécanismes et parfois même complètement le level design des anciens jeux, en fonction desquels ils ont été faits. Eh bien, ou, inversement, ils offrent une intrigue et des emplacements complètement nouveaux, qui sont simplement une stylisation visuelle de "l'antique". Mais si vous imaginez ce que serait la nouvelle partie de l'ancien jeu si elle suivait la dernière de la série? J'ai décidé d'en créer un.

J'ai pris un jeu de plateforme 2D et y ai ajouté des graphiques 3D, tout en conservant la vue latérale classique. Il a construit de nouveaux labyrinthes, proposé de nouvelles quêtes, introduit des tâches et implanté des emplacements d'inventaire. Légèrement diversifié la sensation d'espace, en ajoutant des virages à 90 degrés. Peut-être, dans ces temps anciens, avant la transition totale des jeux en 3D avec trois degrés de liberté, quelque chose comme ça pourrait bien sortir.

Comme j'aime écrire des jeux pour les navigateurs, j'ai décidé de faire un jeu pour le navigateur. En raison de sa spécificité, il n'a pas de nombre fou de polygones, du moins affiché à l'écran en même temps, il n'y a pas de monde ouvert. Par conséquent, tout cela ne chargera pas lourdement le navigateur. Pour afficher des graphiques 3D, j'ai choisi ma bibliothèque Three.js préférée (WebGL) avec mon propre wrapper. Aucune autre bibliothèque n'est utilisée et le code est écrit en javascript pur.

Three.js et les problèmes que j'ai rencontrés


Les développeurs de moteurs graphiques 3D publient périodiquement, environ une fois tous les deux ans, de nouvelles versions de leurs créations. Dans le cas de la bibliothèque de scripts Three.js, les développeurs nous font plaisir avec des mises à jour à une fréquence effrénée - environ une fois par mois. Au moment de la rédaction du présent rapport, la dernière version portait le numéro 106. Il semblerait que ce soit correct. (Non.)

Pourquoi personne ne pense-t-il même à la compatibilité descendante? Lorsque les développeurs de Three.js ont renommé la propriété matérielle ambient, j'ai réalisé: «Houston, nous avons des problèmes . » D'accord, disons qu'il n'a pas été difficile pour moi dans tout mon code de changer le mot "ambient" en "color" avec un remplacement de recherche. Mais quand ils ont exclu la possibilité d'une source de lumière créant une ombre sans éclairage en tant que tel, j'ai réalisé que maintenant l'atterrissage de l'Aigle est en danger réel, et la base Calme commence lentement à se transformer en base Rage . Cependant, comme il s'est avéré plus tard, ce n'était pas si mal ...

Le fait est que dans mon jeu, en plus de la lumière cuite, un éclairage dynamique est également utilisé. Le nombre de sources dynamiques dans une scène 3D affecte considérablement les performances.


J'ai fait le choix du nombre de sources dans les paramètres du jeu - de 1 à 7. Et selon la puissance de la carte vidéo, vous pouvez essayer différentes valeurs.

Il existe également un tableau qui contient les coordonnées et les caractéristiques de chaque source - intensité, couleur, etc. Ça fonctionne comme ça. Lorsque vous vous déplacez dans le monde du jeu dans un certain carré autour du joueur, le nombre de sources de lumière spécifiées dans les paramètres avec les caractéristiques spécifiées est allumé. Autrement dit, les sources lumineuses semblent suivre le joueur (autour de lui) par le nuage.

Alors, Houston, quels sont nos problèmes? Je rapporte.

Problème numéro 1: les ombres


Les sources lumineuses créent des ombres. J'ai remarqué que les ombres provenant de sources lumineuses ponctuelles consomment beaucoup plus de ressources que les ombres dirigées (lumière spot). Et cela est compréhensible: dans le cas d'une source ponctuelle, les ombres sont projetées dans toutes les directions et directionnelles - uniquement dans un cône donné. Cependant, j'ai suggéré que lorsque des ombres dans toutes les directions ne sont pas nécessaires, alors deux sources peuvent être utilisées à la fois: un point ne créera que de l'éclairage et une directionnelle ne créera des ombres que dans une certaine direction. C'est parfait pour mon jeu et, comme il s'est avéré, économise vraiment beaucoup de puissance de calcul.


La pyramide limite la zone dans laquelle les ombres peuvent apparaître.

Mais voici le problème, à partir de la version three.js r73, une source de lumière directionnelle ne peut plus seulement projeter une ombre, elle donne également toujours de l'éclairage. Et la lumière qui en découle se propage dans la zone, ainsi que l'ombre. Il est impossible de supprimer une source ponctuelle et de n'en laisser qu'une directionnelle: j'ai besoin d'éclairage dans toutes les directions. Et en utilisant les deux sources, en les ajustant à la luminosité souhaitée, cela ne fonctionne pas non plus: alors les objets à l'intérieur du cône seront illuminés beaucoup plus lumineux. L'utilisation d'un éclairage "honnête" avec des ombres dans toutes les directions affecte de façon fatale les performances du jeu.

Et ils ont supprimé la propriété nécessaire d'une source de lumière directionnelle .onlyShadow, juste parce que l'auteur du moteur le voulait.

Problème numéro 2: noms de propriété


J'ai décidé que je préfèrerais rester sur la version r71, où la propriété d'éclairage dont j'ai besoin est toujours présente. Pourquoi pas r72 alors? Après tout, la propriété n'a disparu que dans la version r73. Parce que j'ai déjà écrit pas mal de code pour charger des modèles 3D, des animations et de la physique pour la version r71. Et dans la version r72, un grand nombre de noms de propriétés ont changé: type - shadowMap est devenu shadow.map, etc. En général, je ne voulais pas non plus renommer tout cela. Et la différence entre une version est petite. Donc, on reste sur la version r71.

Problème numéro 3: rôtir les ombres



La lumière cuite dans différentes versions du moteur est également différente. Je ne sais pas ce qu'ils font avec lui là-bas, mais lorsque vous appliquez une texture d'ombre à la texture, la luminosité et même la couleur changent considérablement. En général, j'ai en quelque sorte résolu ce problème en sous-moquant le moteur en code GLSL et en réglant la correction automatique des couleurs dans le chargeur de modèles 3D dans les endroits où des shadow maps sont utilisées. Cela ne fonctionne, bien sûr, que pour la version r71. Pour les autres versions, vous devrez utiliser d'autres paramètres. C'est une autre raison de rester sur la version r71.


En fait, cela n'a aucun sens de passer aux dernières versions, car le résultat du travail, par rapport à l'ancienne, ne diffère pas fondamentalement en termes de performances.

Bon. Une source de lumière directionnelle crée uniquement une ombre. Je peux cuire et charger des ombres dans l'assemblage sur la version r71. Et maintenant - l'embuscade la plus importante. Personnages.

Problème 4: animation squelettique


C'est ce que j'ai combattu pendant très longtemps. Au total, j'ai passé quelques semaines à essayer de trouver une sorte d'algorithme de travail pour transférer un personnage avec un ensemble d'animations dans le jeu.


Les versions récentes de Three.js n'ont pas ce problème. Là, j'ai réussi à créer un modèle de personnage animé dans un service en ligne bien connu, à le convertir au format gltf populaire et à le télécharger sur la scène de test. Cependant, si les nouvelles versions de Three.js utilisent le format gltf 2.0, la mienne ne prend en charge que 1.0. Il semblerait, quel est le problème, eh bien, convertir en 1.0 et télécharger. Cela ne s'est pas avéré si simple. Apparemment, il existe plusieurs variantes du format gltf 1.0. J'en avais besoin d'un où, en plus du fichier de modèle principal, deux autres fichiers avec l'extension * .glsl devraient être présents. Mais dans ce cas, le format du fichier principal peut varier ... En général, je n'ai pas pu trouver un convertisseur qui satisferait tous les paramètres, d'autant plus qu'il a également converti du nouveau format à l'ancien. Je ne pouvais pas non plus terminer l'ancienne version de three.js à la prise en charge de gltf 2.0: cette prise en charge est trop profonde dans le code, ancrée dans les mathématiques, implémentée différemment dans les différentes versions du moteur ... En général, cela n'a pas fonctionné avec gltf.

J'ai essayé d'utiliser le format .dae pour les modèles 3D. En conséquence, le modèle lui-même était en cours de chargement, mais je n'ai pas pu faire fonctionner correctement les animations des personnages. Il y avait aussi des problèmes de textures.

Cela s'est bien passé avec le format .md2. Le personnage a été immédiatement affiché et toutes les animations ont fonctionné correctement. Mais, si je comprends bien, md2 est un format de modèle pour Quake 2 et quelqu'un a implémenté son support dans Three.js juste pour le plaisir. Et où trouver des modèles dans ce format, et plus encore, pour concevoir et enregistrer mon propre personnage dedans, je ne l'ai pas trouvé.

J'ai essayé quelques autres formats. Mais sous eux, il n'y avait pas de chargeur de démarrage pour three.js, il n'y avait aucun programme pour créer la préservation de leur personnage en eux, alors ils ne supportaient pas du tout l'animation squelettique.

La base «Rage» a eu raison de renommer la base «Désespoir».

Déjà presque désespéré et pensant passer à une nouvelle version du moteur au détriment des performances (l'histoire d'une source de lumière directionnelle), j'ai décidé pour la dernière fois de tourmenter le format json, avec lequel j'ai en fait commencé. Mais pour la première fois, je n'ai pas pu répéter le processus de conversion d'un personnage à partir du fichier d'exemple fourni dans le paquet Three.js du format .blend original en .json dans l'éditeur Blender 3D. Les animations se sont gâtées et se sont comportées de manière aléatoire, et avec une douzaine de variantes de l'exportateur de Blender à json, chacune a fonctionné incorrectement. De plus, je les ai également essayés sur plusieurs versions de Blender. JSONLoader lui-même, c'est-à-dire un chargeur de modèle au format json, a maintenant été supprimé de three.js. J'ai décidé de regarder quelle version son support avait cessé, afin de prendre lui et un échantillon du modèle 3D non pas de ma version, mais de celle où il était encore. Elle s'est avérée être r88. Et voilà! J'ai réussi à reproduire l'exportation du modèle de test en r71 et tout, y compris les animations de personnages, a bien fonctionné dans le jeu!

"Eagle" a atterri en toute sécurité.

J'ai ensuite décidé d'éditer l'une des animations du personnage de test dans Blender pour voir si je pouvais créer la mienne. Une déception m'attendait ici. L'animation que j'ai éditée ne voulait pas du tout fonctionner dans le jeu. Le personnage s'est figé dans sa position initiale. Bien que d'autres animations aient fonctionné sans problème. Mais c'est quelque chose. Autrement dit, le problème est maintenant mon ignorance de certaines nuances de l'édition de l'animation.

Alors j'ai pensé - et si je demandais à l'auteur de cet exemple comment il l'avait fait. Mais rejoindre l'auteur n'a pas été facile. Il n'a aucun contact personnel chez Github. Une recherche d'un surnom et quelques paramètres supplémentaires ont été apportés à son Twitter, cependant, les messages privés y ont été fermés. Mais à partir de là, j'ai appris qu'il était professeur dans une université américaine et je suis allé sur le site Web de cet établissement d'enseignement. Il s'est avéré que le professeur était engagé dans le graphisme 3D avec ses étudiants, en utilisant son exemple comme matériau méthodologique. Ensuite, je suis retourné à Github et j'ai parcouru tous ses référentiels. Ici, j'attendais le succès. Comme je m'y attendais, son exemple a été stocké dans un référentiel séparé. Et pas seulement une copie de ce que j'ai déjà vu dans les exemples de three.js, mais un exemple soigneusement fourni avec des instructions (apparemment, pour les étudiants). J'ai téléchargé l'archive et, en suivant les instructions, j'ai tout répété. Hourra!

C'est un petit pas pour l'humanité, mais un énorme bond en avant pour une personne et son jeu!

Pas de problème, Houston!



Maintenant, je comprends que si je m'en tiens à ce format, à ces instructions et à ces versions de Three.js, JSONLoader et Blender et que je fais tout de la même manière, je peux créer et charger n'importe lequel de mes personnages dans le jeu par navigateur. La bonne nouvelle était que, malgré l'utilisation de l'ancienne version du moteur, vous pouvez utiliser la dernière version de l'éditeur 3D Blender et créer des personnages avec animation. À ce moment-là, vous devez les exporter selon un schéma strictement défini à l'aide de cette boîte à outils spécifique.

Oui, j'ai remarqué un autre problème avec la nouvelle version de Three.js: pendant le jeu, lors du défilement de l'écran, pour une raison quelconque, des frises constantes sont observées. Et cela n'est pas dû à une consommation accrue de ressources - le processeur et la carte vidéo ne se chargent pas à 100%. Et dans l'ancien r71, il n'y a pas une telle honte.

Maintenant, il ne reste plus qu'à faire pour le jeu dans l'éditeur de personnages 3D avec animation. Et, bien sûr, la géométrie des niveaux. Je ne sais pas combien de temps cela me prendra. Mais jusqu'à présent, je viens de collecter une version de démonstration gratuite sur Webkit et de la télécharger sur les magasins d'applications populaires.

Un peu sur le jeu


Nom. J'ai appelé le jeu Percy Lancaster. Tout est évident ici: "Je suis un artiste, et je le vois."

Comment les graphiques ont été créés . J'ai créé deux plans dans l'éditeur 3D, les ai disposés à distance l'un de l'autre afin que le plus éloigné soit caché derrière le plus proche, j'ai dessiné une texture de pierre sur eux, j'ai fait des trous dans le plus proche, puis j'ai supprimé les parties inutiles, c'est-à-dire invisibles. Puis il a modélisé les avions pour les planchers et les plafonds. Il s'est donc avéré être un couloir où le joueur pouvait marcher. J'ai diversifié les lieux avec différentes textures.


Dans le jeu lui-même, il n'y en a pas, il n'y a qu'une vue latérale et aucun espace noir n'est perceptible. Ceci est juste une vue générale du couloir.

J'ai décidé de créer des couloirs entrecroisés. Pendant le virage, un mur de l'autre couloir est terminé, toute la structure tourne, puis le mur du premier couloir est supprimé. Sur la base de cette mécanique, je prévois également de créer des tours à l'intérieur desquelles vous pourrez monter l'escalier en colimaçon.


Avec les graphiques statiques, en fait, il n'y a aucun problème, il est facilement exporté vers json à partir de n'importe quel éditeur 3D. Les difficultés, comme je l'ai déjà mentionné, ne sont apparues qu'avec les ombres de cuisson et l'animation des personnages.

Performance. Dans la résolution d'écran HD, c'est-à-dire 1280x720, ma carte graphique GT-730 pas si puissante est chargée d'environ 35 à 40% et le processeur Xeon E5440 est chargé d'environ 30%. Je pense que c'est plus qu'un résultat acceptable.

OS Jusqu'à présent, la démo n'est disponible que sous Windows en tant qu'assemblage sur Webkit. À l'avenir, je prévois de lancer une version de navigateur. Je suis tombé sur le fait que tous les navigateurs ne font pas défiler l'écran en douceur. J'ai encore besoin de travailler sur la gestion et l'appel de la fonction de sortie graphique. En attendant, je me suis installé sur Webkit version 26.0. Elle pèse peu et tout fonctionne bien pour elle.

Le son. Les sons proviennent en partie de bibliothèques gratuites, en partie générés. En général, elles ont été faites jusqu'à présent, «pour être». Bien que je ne m'en préoccupe pas beaucoup.

Vidéo Niveau de démonstration de passage complet.


Plans


J'ai l'intention d'aller au crowdfunding et d'embaucher un modélisateur 3D avec l'argent récolté, ce qui créera un personnage normal et des animations pour lui. Pourtant, les graphismes ne sont pas les miens. Mais maintenant, je sais comment introduire un personnage dans mon jeu.

Je prévois également de lancer une version de navigateur pour les dernières versions de Chrome et Firefox. Permettez-moi de vous dire un secret, j'ai même réussi à exécuter le jeu sur MS Edge, mais pour une raison quelconque, il n'y avait aucun objet sur lequel les textures des ombres cuites se chevauchaient, je ne l'ai toujours pas compris. Ensuite, je déboguerai pour les navigateurs pour Linux et Android, et si je reçois des appareils Apple pour quelqu'un à tester, alors aussi pour les navigateurs sur iOS et MacOS.

À long terme - écrire votre propre bibliothèque pour travailler avec WebGL, comme Three.js: je n'aime pas qu'ils renomment brusquement les propriétés et suppriment les fonctionnalités dont j'ai besoin. À l'inverse, la plupart des nombreuses opportunités que Three.js offre ne me sont pas nécessaires.

Je pense que plus tard, quand je trouverai le bon fonctionnement du jeu pour tous les navigateurs sur différents OS, j'écrirai un article à ce sujet avec quelques détails techniques.

Source: https://habr.com/ru/post/fr468261/


All Articles