Logo Spiria

Comment créer une animation 3D sans modèle, à l'aide de WebGL et Three.js

26 janvier 2016.

Lorsque l’on m’a annoncé que mon prochain projet impliquerait WebGL, j’ai fait mes recherches. En bref, il suffit d’ajouter un Canvas HTML à notre page Web et d’en déléguer le rendu à OpenGL pour tirer partie (si elle est disponible) de l’accélération matérielle. On interagit avec la surface de rendu par le biais de JavaScript. J’ai choisi de m’intéresser au projet three.js, au sujet duquel je ne lis que du bien.

Après avoir fait le tour de démos et quelques tests, j’avais besoin d’un sujet pour un petit projet plus concret. À côté de moi, l’équipe de design en était à polir une des dernières versions du nouveau logo de l’entreprise. Voilà, c'était parfait.

Le projet

Bâtir une animation interactive du logo en 3D construite à l’aide d’un nuage de point. Simple, mais suffisamment complexe pour me faire la main, visuellement intéressant et… peut-être éventuellement utile pour notre site.

Le modèle

J’ai un logo... mais en 3D, je vais avoir besoin d’un modèle. Three.js supporte, entre autre, l’importation de modèles Collada, mais en y regardant de plus près, je peux probablement m’en sortir simplement avec une image.

decorative

Dans le logo, il y a du noir et du blanc. En chargeant l’image dans un canvas invisible du navigateur, je peux accéder aux pixels. Cette image ne sera jamais affichée sur le site, elle ne contient que les données que nous allons utiliser pour fabriquer un modèle.

var im = document.getElementById('logo');

var canvas = document.getElementById('canvas');

canvas = getContext('2d').drawImage(im, 0, 0, im.width, im.height);

var data = canvas.getContext('2d').getImageData(0, 0, im.width, im.height).data;

Il ne reste qu’à ne conserver que le noir comme positions valides avec un test sur la composante rouge du rgba (4 valeurs par pixel, rouge étant la première).

var x=0;

var y=0;

for (var i=0; i<data.length; i+=4){

    // if red is lower than 16, it’s black

    if(data[i] < 16) {    

        blacks.push([x,y]);

    }

    if(++x == im.width) {

        x=0;

        y++;

    }

};

Je peux ainsi générer des points sur les faces avant et arrière du modèle du logo. En forçant la position en z (profondeur) à deux valeurs fixes, voici ce qu'on obtient en regardant la scène avec un angle de 45 degrés :

decorative

Reste les côtés. Les côtés de notre modèle, du point de vue de l’image, se trouvent à la frontière du noir et du blanc. Comment en extraire les coordonnées? Appliquons un simple filtre de flou gaussien et ajoutons à notre logique une nouvelle couleur : si le pixel est gris, nous avons une position valide pour les particules qui composent les côtés.

decorative

À l’aide de valeurs aléatoires en profondeur (comprises entre le Z de la face de devant et celui de derrière), on a désormais :

decorative

Suffit ensuite d’intégrer le tout dans l’exemple « points / sprites » de three.js, de faire quelques ajustements et de glisser le canvas sous le contenu du site.

Et vous, qu’avez-vous bâti avec WebGL?