Les prémices d'un énième portfolio 😒
Il y a déjà plus d'un an, j'ai commencé à créer un système procédural en WebGL pour mon nouveau portfolio. C'était un challenge que je m'étais fixé comme base de ma nouvelle vitrine. J'avais envie d'approfondir mes connaissances en 3D temps réel sur le web.
Je suis donc parti sur la classique librairie three.js, et j'ai composé mon système initial. Voici le résultat du système. Chaque planète est unique et recréée à chaque visite.
Résultat actuel du système






On se croirait dans No Man's Sky... ou pas. 🎮
La génération "infinie" des planètes est basée sur le mélange de plusieurs textures choisies aléatoirement pour créer une texture unique. Celle-ci est ensuite appliquée sur une sphère en tant que couleur et normal map.
En plus d'une texture unique, la planète a une taille aléatoire, une certaine probabilité d'avoir une atmosphère, une lune, ou une ceinture d'astéroïdes.
Voici des exemples de textures générées sur un canvas.



La soupe de code pour vos mirettes 👨💻
Pour mélanger les textures, j'ai créé un shader qui prend comme paramètres trois textures. Deux servent à récupérer la couleur et la dernière sert à définir la façon dont les deux premières se mélangent.
planet.frag
varying vec2 vUv;
varying vec4 vPos;
varying vec3 vNormal;
// Chaque image est choisie parmi 6 textures différentes.
uniform sampler2D image;
uniform sampler2D image2;
uniform sampler2D image3;
uniform vec2 resolution;
// Les deux variables suivantes permettent de donner des
// résultats toujours plus aléatoires et intéressants.
uniform float random;
uniform int randomInt;
void main()
{
// Définition de l'uv
vec2 uv = gl_FragCoord.xy / resolution.xy;
// Déclaration des variables
vec4 col = vec4(1.0);
vec4 col1 = texture2D(image, uv);
vec4 col2 = texture2D(image2, uv);
vec4 col3 = texture2D(image3, uv);
// Je renforce ici la texture qui va servir à mélanger
// les deux autres pour qu'elle soit plus nette et donne
// un meilleur résultat final.
col3 = smoothstep(random / 2.0, .9, col3);
// Pour la texture de mixe, je n'ai besoin que d'un seul canal de couleur.
// Je choisis et modifie un canal de couleur pour créer plus de variations.
// Ce shader n'est pas optimisé mais il va être exécuté qu'une seule fois.
float mixColor = 1.0;
if(randomInt == 0){
mixColor = col3.r;
col1 = smoothstep(random / 3.0, .9, col1);
}else if(randomInt == 1){
mixColor = col3.g;
col2 = smoothstep(random / 3.0, .9, col2);
}else{
mixColor = col3.b;
col3 = smoothstep(random / 3.0, 1.0, col2);
}
// Je mixe chaque canal de couleur de chaque texture comme prévu.
col.r = mix( col1.r, col2.r, mixColor );
col.g = mix( col1.g, col2.g, mixColor );
col.b = mix( col1.b, col2.b, mixColor );
// Je définie la couleur du pixel final
gl_FragColor = col;
}
Le shader du soleil quand à lui n'est qu'un noise 3D coloré appliqué sur une sphère. Il se base tout de même sur une texture pour créer une matière plus réaliste.
Retour vers le futur 🔥
Le soleil n'est pas encore abouti. Je pense ajouter des éruptions solaires autour de l'astre. Les planètes quand à elles manquent d'eau et éventuellement de civilisations. La navigation entre les planètes se fera via le cockpit de votre vaisseau et le tout sera accompagné d'un storytelling immersif. Oui rien que ça, on a le droit d'être optimiste !
Si vous avez des questions ou des suggestions, n'hésitez pas !