Salut,
Ca fait un moment que je n’ai pas posté un article (plus ou moins) technique. Alors aujourd’hui, je vais parler d’un ajout récent dans le jeu: l’eau polluée.
L’eau polluée sur la Grande Mer
I – Qu’est-ce que l’eau polluée?
C’est très simple: c’est une eau très sombre (noire) qu’il ne faut pas traverser. Si le joueur y va, ça le blesse, s’il y reste, ça le tue. Dans le jeu, l’eau polluée encercle les zones des chapitres 1, 2 et 3.
II – Pourquoi ajouter de l’eau polluée?
Il y a plusieurs idées derrière cet ajout:
1 – Le 1er but est de pouvoir créer des « zones interdites », au moins au début du jeu. C’est assez classique dans les jeux d’aventure: le joueur n’est pas autorisé à explorer l’intégralité du monde, car il pourrait vite être perdu et ne pas trop savoir où il doit aller.
Ainsi, en créant une zone polluée tout autour des 1ères îles du jeu, le joueur n’a accès qu’à une petite partie du monde lorsqu’il démarre le jeu.
2 – Ensuite, l’eau polluée a une utilité dans le scénario. Sa présence a une raison d’être, et aussi des conséquences sur les êtes vivants, notamment les animaux (vous avez pu avoir un aperçu dans la démo).
3 – Enfin, j’ai choisi de l’eau polluée plutôt que d’autres types de « murs invisibles » (par exemple, j’avais notamment pensé à une grande barrière de corail pour stopper le joueur) parce qu’à un moment du jeu, il faut que cette zone bloquante puisse disparaître pour laisser le joueur passer. De plus, il faut que ce soit relativement léger en temps de calcul CPU, et utiliser d’immenses objets 3D maillés (comme des coraux) tout autour du monde ferait ramer le jeu à coup sûr.
III – Comment ajouter de l’eau polluée?
Techniquement, c’est un point compliqué, car le monde est immense et je veux créer un « anneau » de pollution autour de plusieurs îles, donc ça doit être un objet de plusieurs kilomètres (par rapport à l’échelle du jeu).
Comme tout objet du jeu, cette zone polluée à une apparence visuelle, mais aussi des propriétés de collision ou d’autre types. J’ai donc travaillé sur ces 2 aspects.
Apparence / Rendu / Shader
Concernant l’apparence visuelle, j’avais une idée bien précise en tête, donc j’ai créé un shader particulier:
- Je voulais quelque chose qui bouge lentement et qui ait une apparence très « liquide ». Donc j’ai créé un shader basé sur plusieurs textures de bruit raccordables. Ces textures bougent l’une par rapport à l’autre et sont mixées avec des échelles et des directions de mouvement différentes.
- Je voulais comme couleur un noir pur qui tranche clairement avec le bleu de l’océan, donc je n’ai pas implémenté de calcul de luminosité.
- Je voulais des bords très nets, comme s’il s’agissait de tâches d’huile sur l’eau, donc j’ai utilisé une approche « alpha cutout » sur la texture résultante.
- Je voulais éviter les répétitions de textures évidentes. Pour ça, j’ai créé des textures immenses que j’ai fusionnées avec des échelles dont les facteurs sont premiers entre eux, ce qui produit un motif assez unique sur une longue distance.
- Je voulais que la création du mesh et l’uv mapping dans Blender soient le plus facile possible (je dois créer des kilomètres de ce truc): j’ai créé des formes simples, et j’utilise un uv mapping automatique.
Une section d’eau polluée dans Blender. Je peux facilement déformer le volume, et appliquer ensuite un uv mapping automatique sans trop d’efforts.
La puissance de l’uv mapping automatique.
- Mais en même temps, je voulais que les bords de la zone polluée se dissolvent en tâches de plus en plus petites au fur et à mesure qu’on s’éloignait du centre. J’ai donc choisi d’utiliser les couleurs des sommets comme paramètre de transparence (alpha), et de mixer ce paramètre avec la texture finale: au centre de la zone polluée, les sommets sont blancs, et la texture est bien visible. Sur les bords, les sommets sont noirs, et la texture est invisible. La transition entre ces points est faite automatiquement grâce à l’interpolation linéaire des propriétés des sommets. Mais, grâce au rendu « alpha cutout », on n’a pas un dégradé évanescent, mais bien des zones polluées nettes de plus en plus petites.
Les couleurs des sommets dans Blender: opacité maximum au centre, transparence maximum à l’extérieur.
…résultant dans le jeu en une pollution opaque au centre (sur la droite ici), et des tâches de plus en plus éparse sur l’extérieur (à gauche ici), en limite de zone.
- De plus, à un moment du jeu, je veux que le joueur puisse faire disparaître cette zone polluée pour explorer l’intégralité du monde. Il faut donc que j’intègre un certains nombre de paramètres qui permettront l’animation de la quantité d’eau polluée. Il faut que cette animation soit continue et qu’elle n’entre pas en conflit avec les autres paramètres.
Collision et propriétés
Quand j’ai créé cette zone de pollution, je me suis posé beaucoup de questions sur le gameplay:
1 – Est-ce que le joueur peut nager au travers? Si ce n’est pas le cas, ça signifie que je vais devoir mettre un « mur invisible » pour l’empêcher d’aller plus loin. Je ne veux pas, car ça va à l’encontre du sentiment de liberté que je veux instiller dans le jeu.
Cela signifie donc qu’il faut que le joueur prenne des dégâts en rentrant dans la zone polluée. Et donc, je dois mettre en place un calcul de collision assez précis. Je ne peux pas utiliser les mesh colliders (maillages) car ils ne présentent pas assez de détails, et ce serait très perturbant pour le joueur de prendre des dégâts en limite de zone polluée, là où la pollution est invisible, mais où il est pourtant dans la zone du mesh. En tant que joueur, je détesterai ça.
Donc j’ai du coder un test de collision « pixel perfect ». J’ai du trouver un moyen pour savoir si le joueur est sur une tâche polluée. J’ai envisagé d’échantillonner l’écran sur la position de joueur avant de l’afficher pour savoir si la position était polluée ou pas, mais ça remettait en cause les ordre d’affichage des objets, ça ne garantissait pas la justesse du test (s’il y a un objet devant?), et ça ne marchait plus si un jour j’envisageais de changer l’apparence de la zone polluée. Donc j’ai choisi de recalculer le shader de l’eau polluée sur le CPU, avec les mêmes paramètres. Au final j’ai donc codé 2 fois le shader, sur GPU et sur CPU. J’étais assez stressé au niveau des précisions de calcul (architectures différentes…), mais, pour le moment, les résultats sont suffisamment précis.
2 – Mais affecter des dommages au personnage n’est pas suffisant: je dois m’assurer que le joueur ne pourra pas traverser, même s’il a plein d’énergie et beaucoup de pommes. Comment faire ça? Ça m’oblige à calculer une largeur minimum pour cette zone polluée afin de m’assurer mathématiquement que le joueur ne pourra pas passer, quelques soient ses ressources.
3 – Et enfin, j’ai également un problème avec la tortue: que se passe-t-il si le joueur veut traverser à dos de tortue? Est-ce que ça tue la tortue? Je n’aimais pas cette idée là, alors j’ai fait en sorte que la tortue refuse d’y aller tout simplement. Dès que la tortue approche de la zone, tout mouvement en direction de la zone polluée est amorti. C’était un peu technique à mettre en place, car il faut récupérer la normale au bord le plus proche pour filtrer les mouvements; ce n’est pas immédiat.
Bien sûr, il s’agit ici d’une sorte de mur invisible, qui va à l’encontre de la philosophie de « liberté » du jeu. Mais ça a tout de même du sens au niveau du jeu: la tortue nous obéit, mais pas si on met sa vie en danger. Dans ce cas, ça me parait suffisamment logique pour être accepté des joueurs. De plus j’ai rendu la chose encore plus claire en faisant en sorte que la tortue signale le problème. Et une fois de plus, ça n’empêche pas le joueur de traverser tout seul s’il le souhaite, mais c’est son choix, pas celui de la tortue.
La tortue ne veut pas aller là. Elle craint pour sa vie.
Voilà pour le post du jour! C’est toujours beaucoup plus long que ce à quoi je m’attends. J’espère que vous aurez trouvé ça intéressant! N’hésitez pas à me donner votre avis!
PS: A l’heure actuelle, je n’ai pas modélisé l’intégralité de la zone polluée. Je suis sûr que vue l’échelle finale de la zone, d’autres problèmes vont survenir (précision des calculs avec les grandes distances, z fighting, …)
Laisser un commentaire