IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

rocessing

Processing - langage de programmation et environnement de développement libre.


précédentsommairesuivant

III. Dessiner plus

III-A. Les images

Ce que nous appelons « image » dans Processing n'est en fait rien d'autre qu'une collection de pixels, rassemblés à l'intérieur d'un rectangle. Pour dessiner une image à l'écran, nous devons donner une couleur à chacun des pixels d'un rectangle, puis donner la position en {x,y} où nous voulons dessiner cette collection de pixels. Il est aussi possible de modifier la taille {largeur,hauteur} de notre image, même si ces dimensions ne correspondent pas à la taille originelle de l'image.

III-A-1. Trouver une image

Pour dessiner une image dans Processing, il faut commencer par trouver une image et l'importer dans notre sketch. Vous pouvez prendre une photo à l'aide de votre appareil numérique ou directement depuis votre webcam ou bien encore effectuer une recherche d'images se trouvant déjà dans le disque dur de votre ordinateur. Pour cet exercice, l'origine de l'image importe peu. Par contre, nous recommandons de commencer avec une image relativement petite, par exemple d'une largeur de 400 × 300 pixels.

Image non disponible

Ici nous allons commencer avec une image légèrement réduite de l'ile des peupliers à Ermenonville, trouvée sur le site Commons de Wikimedia (base de données d'images et de médias appartenant au domaine public ou sous licence libre) à l'adresse suivante : https://fr.wikipedia.org/wiki/Fichier:Erm6.JPG

III-A-2. Formats d'image

Trois formats de fichier d'image sont acceptés dans Processing : PNG, JPEG, ou GIF. Ceux qui ont de l'expérience dans la conception de sites web devraient reconnaître ces trois formats, car ce sont les plus répandus sur la Toile. Chaque format utilise ses propres méthodes de compression de l'image (réduction de la taille mémoire de l'image occupée sur l'ordinateur), lui donnant à la fois des avantages et des désavantages et que nous pouvons résumer de la manière suivante :

  • JPEG est souvent utilisé pour compresser des images de type photographique. Ce format ne permet pas d'avoir des zones transparentes.
  • GIF est historiquement utilisé pour l'illustration de boutons et autres éléments graphiques de l'espace de travail d'un programme. Sur les sites internet, ce format est utilisé pour les logos et de manière générale pour les dessins réalisés par ordinateur (notamment ceux qui comportent des aplats de couleurs). Ce format peut contenir des zones transparentes binaires (soit opaques soit transparentes, sans possibilité d'opacité intermédiaire). Il existe des images gif animées, mais Processing ignorera cet aspect.
  • PNG est de plus en plus utilisé pour les deux usages (photos + dessins) et peut contenir des zones transparentes non binaires, offrant des niveaux d'opacité (opaque, semi-opaque, totalement transparent).

III-A-3. Glisser-déposer

Nous allons maintenant importer le fichier de cette image dans l'environnement Processing. Pour bien réussir cette étape, nous vous recommandons de sauvegarder d'abord votre sketch, de préférence dans le dossier processing qui devrait se trouver par défaut dans le dossier Documents ou Mes documents de votre ordinateur.

Localisez maintenant votre fichier d'image, et glissez-le directement sur la fenêtre Processing :

Image non disponible

Lorsque nous glissons les fichiers de cette manière, Processing nous indique dans la bande grisée de la console qu'il a ajouté ce fichier « dans le sketch ». En réalité, Processing a simplement copié cette image dans un dossier nommé data, qui devrait maintenant se trouver à côté de votre programme.pde que vous venez de sauvegarder.

Image non disponible

C'est dans ce dossier data que nous devons placer en réalité toutes les images dont nous voulons nous servir dans notre sketch. C'est dans cet emplacement que doivent également être rangés les autres fichiers médias comme les polices ou les sons.

Pour accéder rapidement à ce dossier, afin par exemple d'y placer de nouveaux fichiers d'images, il suffit de sélectionner, dans le menu Sketch, l'option Show Sketch Folder. Cette option est également accessible via le raccourci Ctrl-k sur Windows et GNU/Linux ou Cmd-k sur Mac :

Image non disponible

III-A-4. Importer une image

Image non disponible

Maintenant que nous avons placé une image dans notre dossier data, nous pouvons désormais nous en servir dans notre programme.

 
Sélectionnez
size(500,400);
 
PImage ile;
ile = loadImage("ile.jpg");
 
image(ile,50,10);

D'abord nous avons donné à notre espace de dessin une taille plus grande que notre image, juste pour mieux comprendre comment celle-ci peut être positionnée dans le sketch final.

Il y a trois étapes pour afficher une image dans Processing :

  • Créer une variable qui contiendra les données (en pixels) de notre image.
  • Importer les pixels d'un fichier dans notre variable.
  • Dessiner les pixels de cette variable dans notre espace de dessin.

Tout d'abord, nous devons créer une variable Processing, avant d'importer notre fichier dedans. Mais avant tout, à quoi sert une variable ? Hé bien dans ce cas précis, il s'agit d'un nom interne à notre programme qui contient l'ensemble des pixels de notre fichier ile.jpg. À chaque fois que nous écrirons par la suite le mot «  ile » dans notre programme, Processing comprendra qu'il s'agit de la suite de valeurs en pixels qui composent notre image. C'est justement le rôle de cette action loadImage("nomdefichier") d'aller chercher ces pixels dans le fichier et les importer dans notre variable nommée « ile ».

Vous avez peut-être également noté un mot étrange au tout début du code ci-dessus, le mot PImage. Celui-ci indique à Processing le genre de la variable et lui permettra de consacrer assez de mémoire dans votre ordinateur pour contenir l'ensemble des données de ce genre. Dans le cas de n'importe quelle variable, la syntaxe à utiliser est {type de la variable} {nom de la variable} = {les valeurs de la variable}.

Par exemple, si par un tour de force il était possible d'importer un petit chien tout mignon dans Processing, il suffirait d'écrire PetitChiot milou = loadDog("milou.dog");  On écrit d'abord le type de la chose, le nom de la chose, et enfin on lui donne sa valeur.

Ici, cette valeur est donnée par la fonction loadImage() qui va aller chercher les pixels de l'image dans le fichier et les importera dans notre variable nommée ile.

Pour plus d'informations sur les variables et les différents types de variables, reportez-vous au chapitre dédié à ce sujet.

Enfin, une fois notre variable remplie, nous la dessinons à une position {x,y} dans notre sketch. Si nous voulons dessiner notre image à sa taille originelle, nous utilisons la version courte de l'instruction image qui nécessite uniquement trois paramètres : {PImage}, {x}, {y}.

 
Sélectionnez
image(ile,50,10)

III-A-5. Importer une image web

Nous pouvons également importer des images directement depuis internet, en indiquant l'adresse web de l'image à la place du nom de fichier.

 
Sélectionnez
size(400,400);
 
PImage webcam;
webcam = loadImage("http://www.gutenberg.org/files/3913/3913-h/images/rousseau.jpg");
image(webcam,10,20,width,height);

Si notre programme n'est pas animé, comme c'est le cas ici, il y aura juste une longue pause lorsque l'image se charge dans Processing.

Par contre, faites bien attention à placer ce type d'instructions au début du sketch sinon vous risquez de ralentir fortement le fonctionnement des autres parties du programme, celles-ci devant attendre le téléchargement complet de vos images depuis internet avant de s'exécuter. Dans des cas très spécifiques, si vous avez besoin d'importer des images web en plein milieu de votre sketch, sachez qu'il existe des techniques appropriées dénommées « fils d'exécution ». Ces techniques séparent le chargement de fichiers médias depuis internet du reste des fonctions du programme. Il s'agit malheureusement d'un sujet trop avancé pour ce manuel. Pour davantage d'informations sur les fils d'exécution, reportez-vous au forum du site de Processing en faisant une recherche sur le mot « thread ».

III-A-6. Changer de taille

En ajoutant deux paramètres, nous pouvons changer la taille de l'image. Cette taille peut être plus petite ou plus grande que l'image d'origine, et a priori il n'y a pas vraiment de limite. Par contre, au-delà de la taille d'origine de l'image, Processing sera obligé d'inventer des pixels en doublant les originaux, ce qui donnera un effet pixelisé. Cet effet n'est pas forcément indésirable, à vous de voir.

Pour changer la taille de l'image, il suffit de rajouter deux paramètres à votre image, {largeur, hauteur}, ce qui nous amène à cinq paramètres : {variableImage, x, y, largeur,hauteur}.

Image non disponible
 
Sélectionnez
size(500,250);
 
PImage ile;
ile = loadImage("ile.jpg");
 
image(ile,10,10,20,15);
image(ile,20,20,50,30);
image(ile,45,45,100,75);
image(ile,95,95,1000,750);

Notez que nous avons importé qu'une seule fois l'image dans notre variable ile et que celle-ci peut être dorénavant utilisée pour le restant de notre programme. Notez également que nous avons respecté les proportions {x,y} de notre image dans le changement de la taille, mais que celles-ci auraient pu prendre n'importe quelle valeur, ce qui reviendrait à étirer l'image sur un de ces deux axes.

Image non disponible

III-A-7. Rendre transparent l'arrière-plan d'une image

Souvent nous avons besoin d'importer des images qui ne sont ni carrées, ni rectangulaires, comme dans le cas d'un petit jeu vidéo utilisant des silhouettes de personnages en deux dimensions : nous ne voulons pas voir en permanence un carré blanc autour du profil de notre héros. Malheureusement, à ce jour, les images à base de pixels doivent être importées dans un format carré.

Pour lever cette contrainte, certains formats de fichiers font appel à une couche alpha pour gérer la transparence de certaines zones de l'image et ainsi laisser apparaître les éléments qui sont situés derrière elles (un fond coloré ou illustré par exemple). Cette couche se superpose aux couches rouge, vert, bleu utilisées pour composer l'image et indique l'intensité de la transparence pour chaque pixel, avec même la possibilité de pixels semi-transparents dans le cas du format PNG.

Si vous voulez sauvegarder votre image avec une couche alpha, vous avez trois possibilités qu'il faut choisir lors de l'exportation de votre image dans votre logiciel de traitement d'image préféré :

Image non disponible

Chaque logiciel exportera les images à sa manière. Sachez juste qu'il existe une différence par exemple entre GIF, PNG-8, et PNG-24, notamment sur la façon dont chaque format va traiter cette couche alpha. Le plus sûr des trois, et qui vous donnera plus d'options, c'est le PNG-24.

Voici une image du philosophe Jean-Jacques Rousseau avec un fond transparent.

Image non disponible

Quel que soit le fond sur lequel elle sera placée, cette image s'y intègrera parfaitement parce qu'elle contient justement une couche alpha décrivant les parties transparentes et non transparentes du carré de pixels qui la composent. Notez que les pixels autour de Rousseau sont transparents, alors que son front et son cou sont opaques.

N'hésitez pas à copier cette image au format png sur votre ordinateur depuis la version en ligne de ce manuel : http://fr.flossmanuals.net/processing/, chapitre Les images (conçue à partir d'une illustration mise à disposition sur le site Commons de Wikimedia, cette image est libre de droits).

Dans notre programme Processing, nous allons pouvoir constater que les pixels situés autour du personnage sont effectivement transparents en superposant l'image de Rousseau (au format png) avec celle du paysage précédemment utilisée (au format jpg) :

Image non disponible
 
Sélectionnez
size(400,300);
 
PImage ile;
ile = loadImage("ile.jpg");
 
PImage rousseau;
rousseau = loadImage("rousseau.png");
 
image(ile,0,0);
image(rousseau,20,20);

III-A-8. Colorier les images

On peut également colorier les images. Autrement dit, on peut changer la couleur des pixels, soit dans leur ensemble, soit individuellement. La plus simple de ces méthodes concerne le coloriage de l'ensemble des pixels. Cette méthode de coloriage ressemble à peu près au coloriage de rectangles, mais nécessite une nouvelle instruction, tint(), pour le distinguer du coloriage direct des pixels à l'intérieur du rectangle. Dans le cas de tint(), Processing va modifier la couleur de chaque pixel au moment où celui-ci est dessiné dans l'espace de dessin.

Image non disponible
 
Sélectionnez
size(500,130);
 
PImage ile;
ile = loadImage("ile.jpg");
 
tint(255,0,0);
image(ile, 10,10, 110,110);
 
tint(255,255,0);
image(ile, 130,10, 110,110);
 
tint(255,255,255,127);
image(ile, 250,10, 110,110);
 
tint(0,0,255,127);
image(ile, 320,10, 110,110);

Tout comme les instructions fill() et stroke(), l'instruction tint() peut prendre une, deux, trois, ou quatre valeurs, selon ce que nous voulons faire. En indiquant trois paramètres, par exemple, nous pouvons augmenter/diminuer l'intensité de la couche rouge, vert, ou bleu de notre image. En indiquant quatre paramètres, nous pouvons augmenter/diminuer, en plus de ces trois couleurs, la valeur de transparence/opacité de l'image.

III-B. Les styles de bordures

Le style des traits et des bordures des formes géométriques peut être ajusté afin d'éviter l'apparition d'effets graphiques indésirables sur les lignes obliques, aux intersections ou en bout de ligne. Différentes commandes permettant d'affiner le rendu sont présentées ci-dessous.

III-B-1. smooth

La méthode smooth() permet d'activer le lissage des contours. Elle permet d'éviter l'effet d'escalier qui apparaît sur les lignes diagonales.

 
Sélectionnez
line(10, 0, 100, 90);  // Ligne sans lissage
 
//On active le lissage
smooth();
line(0, 10, 90, 100); // Ligne lissée
Image non disponible

III-B-2. strokeWeight

La méthode strokeWeight() permet de varier l'épaisseur d'une ligne ou d'un contour.

 
Sélectionnez
line(10, 0, 100, 90); // Ligne de 1 pixel d'épaisseur
 
strokeWeight(5); //On définit l'épaisseur à cinq pixels
line(0, 10, 90, 100); // Ligne de cinq pixels d'épaisseur
Image non disponible

III-B-3. strokeCap

La méthode strokeCap() permet de définir l'apparence des extrémités d'une ligne. Cette méthode n'est pas utile pour les formes. Elle peut avoir les valeurs SQUARE (extrémité carré), PROJECT (extrémité avec deux petits angles brisés) ou ROUND (extrémité arrondie). Par défaut c'est le mode ROUND qui est utilisé. Cette méthode ne fonctionne pas avec P3D ou OpenGL.

 
Sélectionnez
strokeWeight(10); // On définit l'épaisseur des traits à 10 pixels
strokeCap(ROUND); // extrémité arrondie
line(20, 40, 60, 80);
 
strokeCap(PROJECT); // extrémité avec deux petits angles brisés
line(20, 20, 80, 80);
 
strokeCap(SQUARE); // extrémité carré
line(40, 20, 80, 60);
Image non disponible

III-B-4. strokeJoin

La méthode strokeJoin() permet de modifier l'aspect des jointures. Elle peut avoir les valeurs MITER, BEVEL ou ROUND. Par défaut c'est le mode MITER qui est utilisé. Cette méthode ne fonctionne pas avec P3D ou OpenGL.

 
Sélectionnez
size(300, 100); // On modifie la taille du sketch
 
strokeWeight(10); // On définit l'épaisseur à 10 pixels
strokeJoin(MITER); // Jointure carré
rect(20, 20, 60, 60);
 
strokeJoin(BEVEL); // Jointure brisée
rect(120, 20, 60, 60);
 
strokeJoin(ROUND); // Jointure arrondie
rect(220, 20, 60, 60);
Image non disponible

III-C. La typographie

Ce chapitre va vous permettre de personnaliser l'usage des textes dans Processing en utilisant des polices de caractères alternatives.

III-C-1. La forme des mots

Si nous voulons dessiner avec une autre forme typographique que celle définie par défaut, il faut effectuer quelques étapes préalables :

  • Convertir une police de caractères en un format de fichier compatible avec Processing ;
  • importer ce fichier dans le code du programme (ce fichier comporte toutes les informations graphiques décrivant l'apparence de la police utilisée) ;
  • sélectionner cette police et l'activer dans notre programme ;
  • dessiner du texte dans notre sketch à l'aide des instructions appropriées pour que le résultat s'affiche dans la fenêtre de visualisation de Processing.

III-C-2. Importer une police de caractères

Pour dessiner du texte dans notre fenêtre de visualisation, il faut choisir tout d'abord son apparence, en indiquant sa police de caractères. Pour bien réussir cette étape, nous vous recommandons de sauvegarder d'abord votre sketch dans votre dossier de travail (voir chapitre Bases de Processing). Une fois notre sketch sauvegardé, nous allons sélectionner, dans le menu Tools, l'action Create Font…

Image non disponible

A priori nous devrions maintenant voir une fenêtre Create Font qui permet de convertir quasiment n'importe quelle police de caractère en une forme utilisable dans notre sketch. Cette police doit être installée au préalable dans notre ordinateur pour qu'elle apparaisse dans cette liste.

Image non disponible

Cette fenêtre est décomposée en quatre parties :

  • La liste des polices actuellement installées sur notre ordinateur,
  • Une prévisualisation de la police actuellement sélectionnée, affichée à la taille indiquée dans le prochain champ (la zone numérotée trois dans la copie d'écran ci-dessus),
  • À peu près la taille maximale à laquelle nous voulons dessiner cette police,
  • Le nom du fichier de cette police, une fois convertie dans le format natif de Processing (.vlw).

Vous avez peut-être noté qu'il existe également une case à cocher Smooth qui active/désactive l'antialiasing (fonction de lissage des polices pour éviter un effet de crénelage), ainsi qu'un bouton Characters… qui permet de préciser les caractères spéciaux qui doivent être inclus lors de la conversation de la police. Pour ne pas compliquer les choses, nous allons laisser ces deux options avec leurs valeurs par défaut.

Dans l'illustration ci-dessus nous avons sélectionné la police Georgia. C'est à partir du nom de cette police et de sa taille que Processing générera le fichier de la police à importer, ex. : « Georgia-Italic-48.vlw ». Notons enfin que l'extension « .vlw » associée à l'intitulé du fichier sera rajoutée à toutes les polices que nous importerons de cette manière. Si par curiosité vous vous intéressez à l'origine de cette extension, son nom fait référence sous la forme d'un acronyme au « Visual Language Workshop » (vlw) du MIT Media Lab. C'est ce laboratoire qui historiquement est à l'origine d'un certain nombre de principes et de travaux qui ont permis à Processing de voir le jour.

Si nous voulons savoir où Processing a sauvegardé notre police, il suffit de sélectionner, dans le menu Sketch, l'action Show Sketch Folder.

Cette action fera apparaître le dossier « data » dans lequel notre police a été sauvegardée. Son fichier s'appelle « Georgia-Italic-48.vlw ». C'est ce nom que nous devons retenir pour intégrer la police dans notre programme.

Image non disponible

III-C-3. Dessiner une phrase

Nous allons enfin dessiner avec notre police. Pour cela, il faut faire trois choses :

  • Importer le fichier Georgia-Italic-48.vlw dans une variable afin que notre programme connaisse le nom de la police utilisée et sache la dessiner lorsqu'il affichera du texte. Ce fichier contient en effet les informations décrivant la structure géométrique de la police pour pouvoir la reproduire ;
  • Sélectionner cette variable dans notre programme comme police active ;
  • Dessiner un caractère ou une phrase quelque part dans notre sketch à l'aide des instructions appropriées pour le voir ensuite s'afficher dans la fenêtre de visualisation de Processing.

En option, il est possible de choisir la taille à laquelle nous voulons dessiner avec notre police, mais comme nous avons déjà paramétré cet aspect lors de la création du fichier, il ne sera pas nécessaire de l'indiquer ici.

Voici le code complet d'un programme simple qui réunit toutes ces étapes pour dessiner une phrase dans la fenêtre de visualisation. Par tradition, nous allons faire nos premiers pas dans l'écriture en écrivant « Salut tout le monde ! ».

 
Sélectionnez
size(500,150);
 
PFont police;
police = loadFont("Georgia-Italic-48.vlw");
textFont(police,48);
 
text("Salut tout le monde !", 20, 75);

Tout d'abord, nous avons fixé la taille de notre fenêtre de visualisation (l'espace de dessin), comme dans quasiment n'importe quel programme Processing.

Ensuite, nous avons importé notre fichier dans une variable Processing (dénommée police). À quoi sert une variable ? Hé bien dans ce cas précis, il s'agit d'un nom interne à notre programme qui fait référence au fichier de la police Georgia-Italic-48.vlw que nous souhaitons utiliser. À chaque fois que nous écrirons par la suite le mot police dans notre programme, Processing comprendra qu'il s'agit de faire appel à la police Georgia Italic 48 contenue désormais dans ce mot.

Vous avez peut-être également noté un mot étrange en tout début de cette phrase, le mot PFont. Celui-ci indique à Processing le genre de la variable et lui permettra d'ouvrir assez de mémoire pour contenir l'ensemble des données de ce genre. Dans le cas de n'importe quelle variable, la syntaxe à utiliser est {type de la variable} {nom de la variable} = {les valeurs de la variable}.

Par exemple, si par un tour de force il était possible d'importer un petit chaton tout mignon dans Processing il suffirait d'écrire petitChaton mioumiou = loadPetitChaton("mioumiou.chat");  On écrit d'abord le type de la chose, le nom de la chose, et enfin on lui donne sa valeur. Ici, cette valeur est donnée par la fonction loadFont() qui va aller chercher la structure géométrique de la police dans le fichier et l'importera dans notre variable nommée « police ».

La suite de notre programme est probablement un peu plus intuitive. Nous sélectionnons la police avec laquelle nous voulons dessiner. Même s'il n'existe qu'une seule police actuellement dans notre programme, il faut néanmoins passer par cette étape. Notez que vous pouvez importer autant de polices que vous voulez et passer de l'un à l'autre, à l'image de ce qu'il est possible de faire avec les couleurs.

Dans cet exemple, nous avons indiqué la taille de la police juste pour vous montrer qu'il est possible de la changer en cours de route.

Enfin, nous dessinons une petite phrase et indiquons la position {x,y} où notre texte doit se dessiner. On obtient le résultat suivant :

Image non disponible

III-C-4. Point d'origine

Pour rendre plus clair le rapport entre la position {x,y} de notre message et sa forme typographique, nous avons également dessiné dans l'illustration ci-dessus une petite croix pour rendre plus explicite la façon dont Processing positionne l'écriture :

 
Sélectionnez
size(500,150);
 
PFont police;
police = loadFont("Georgia-Italic-48.vlw");
textFont(police);
 
text("Salut tout le monde !", 20, 75);
 
// indiquer la position d'origine du texte
stroke(255,0,0);
line(15,70,25,80);
line(15,80,25,70);

Tout comme les rectangles, qui peuvent se dessiner depuis leur point supérieur gauche, depuis leur centre, ou depuis ses quatre extrémités, l'écriture du texte peut également être positionnée à partir de plusieurs points d'origine. Par défaut, le texte s'écrit depuis la ligne de base du texte, c'est-à-dire le point en bas à gauche du texte, mais au-dessus des caractères descendants comme les lettres « y » ou « j ».

Vous pouvez changer la façon dont Processing alignera ce texte, en se servant de la fonction textAlign() :

 
Sélectionnez
size(500,250);
 
PFont police;
police = loadFont("SansSerif-24.vlw");
textFont(police,24);
 
line(250,0,250,500);
line(0,125,500,125);
 
textAlign(RIGHT,TOP);
text("right+top", 250, 125);
 
textAlign(RIGHT,BASELINE);
text("right+baseline", 250, 125);
 
textAlign(LEFT,CENTER);
text("left+center", 250, 125);
Image non disponible

III-D. Les transformations

Jusqu'à présent, nous avons dessiné des formes dans la fenêtre de notre application, en nous repérant toujours par rapport au coin supérieur gauche de la fenêtre.

Grâce aux transformations, il va être possible de déplacer cette origine, mais aussi de redéfinir l'orientation des axes et même de changer la graduation de ces axes (on parle de changement d'échelle).

Par défaut, lorsque l'on dessine une forme (dans notre exemple un rectangle), Processing définit le repère suivant :

Image non disponible
 
Sélectionnez
size(200, 200);
noStroke();
fill(0);
rect(0, 0, 100, 100);

III-D-1. Déplacer

Le changement de la position de l'origine se fait par la commande translate(). Nous pouvons nous déplacer sur l'axe x (« horizontalement ») et sur l'axe y (« verticalement ») et nous allons indiquer à translate() de « combien » nous voulons nous déplacer sur chacun des axes. Dans l'exemple suivant, nous déplaçons l'origine de notre repère de 50 pixels en x et de 50 pixels en y. Notons que translate() va seulement affecter les formes géométriques qui sont dessinées après cette instruction.

Image non disponible
 
Sélectionnez
size(200, 200);
noStroke();
fill(0);
translate(50, 50);
rect(0, 0, 100, 100);

Enchaîner les translate() permet d'accumuler les déplacements comme le montre l'exemple suivant.

Image non disponible
 
Sélectionnez
size(200,200);
 
// Noir
fill(0);
translate(20,20);
rect(0,0,40,40);
 
// Gris
fill(128);
translate(60,60);
rect(0,0,40,40);
 
// Blanc
fill(255);
translate(60,60);
rect(0,0,40,40);

III-D-2. Tourner

Nous avons pu déplacer l'origine du repère de dessin. Nous allons maintenant appliquer une rotation sur les axes de notre repère. Grâce à la commande rotate(), les axes x et y peuvent changer d'orientation. rotate() prend en paramètre un nombre qui va représenter l'angle de rotation, c'est-à-dire de « combien » nos axes vont tourner par rapport à notre fenêtre. Des valeurs positives indiquent une rotation dans le sens des aiguilles d'une montre.

Image non disponible

Deux systèmes de mesure existent pour mesurer un angle : les radians et les degrés. Par défaut, Processing travaille en radians, mais pour nous il est d'habitude plus facile de raisonner en degrés. Par exemple, tourner de 180 °, c'est faire un demi-tour.

Processing permet de passer de transformer une unité en une autre grâce aux fonctions radians() et degrees().

 
Sélectionnez
float d = degrees(PI/4); // transforme des radians en degrés
float r = radians(180.0); // transforme des degrés en radians

Illustrons la fonction rotate() par un exemple simple. Nous allons faire pivoter un carré autour de l'origine.

Image non disponible
 
Sélectionnez
size(200, 200);
noStroke();
fill(0);
rotate(PI/4);
rect(0, 0, 100, 100);

Comme pour translate(), rotate() se place avant les formes géométriques à dessiner. Il est possible de combiner ces changements d'orientation, qui vont s'accumuler.

Image non disponible
 
Sélectionnez
size(200,200);
smooth();
translate(width/2, height/2);
for (int i=0;i<360;i+=30){
  rotate(radians(30));
  quad(0, 0, 30, 15, 70, 60, 20, 60);
}

III-D-3. Mettre à l'échelle

La mise à l'échelle permet de redimensionner les objets par la commande scale(). Cette fonction permet d'agrandir ou de diminuer la taille des formes géométriques. Elle accepte un ou deux paramètres. Par exemple, scale(0.5) va diminuer de moitié la taille des formes géométriques tandis que scale(2.0) va la doubler, scale(1) n'a aucun effet.

L'écriture avec deux paramètres permet de découpler le redimensionnement en x et en y. Par exemple, scale(0.5, 2.0) va écraser la forme sur les x de moitié tandis que sur les y sa taille sera doublée.

Image non disponible
 
Sélectionnez
size(200,200);
scale(1.5);
rect(0,0,100,100);
Image non disponible
 
Sélectionnez
size(200,200);
scale(1.0,1.5);
rect(0,0,100,100);

Comme pour rotate() et translate(), l'enchainement de scale() permet d'accumuler les mises à l'échelle. Illustrons cette propriété par le sketch suivant, qui reprend l'idée des poupées russes en emboîtant des carrés par le jeu des scale() successifs.

Image non disponible
 
Sélectionnez
size(200,200);
noStroke();
 
// Noir
fill(0);
scale(1);
rect(0,0,200,200);
 
// Gris
fill(128);
scale(0.5);
rect(0,0,200,200);
 
// Blanc
fill(255);
scale(0.5);
rect(0,0,200,200);

III-D-4. L'ordre des transformations

Il est possible de combiner plusieurs types de transformations. Comme nous l'avons vu dans les exemples précédents, les transformations s'accumulent au fur et à mesure des appels successifs à translate(), rotate() ou scale() et chacune des transformations tient compte des transformations précédentes.

Lorsqu'on utilise plusieurs types de transformations, leur ordre d'écriture va être important. Lorsque vous êtes en voiture, « tourner à gauche » puis « continuer tout droit » est différent de « continuer tout droit » puis « tourner à gauche ». Vous n'arrivez pas forcément au même endroit en suivant successivement ces deux instructions. C'est la même chose pour les transformations dans Processing.

Illustrons ceci par un exemple en inversant un translate() et un rotate().

Image non disponible
 
Sélectionnez
size(200,200);
smooth();
fill(0);
 
translate(100,0);
rotate(PI/5);
rect(0,0,100,100);
Image non disponible
 
Sélectionnez
size(200,200);
smooth();
fill(0);
 
rotate(PI/5);
translate(100,0);
rect(0,0,100,100);

III-D-5. Isoler les transformations

Nous venons de voir que les transformations s'accumulaient au fur et à mesure de l'utilisation des commandes translate(), rotate() et scale(). Nous allons voir à présent comment sauvegarder les transformations à un moment donné et comment les restaurer ensuite, au cours d'une animation interactive faisant appel à la méthode draw().

Nous allons utiliser pour cela deux fonctions qui s'utilisent toujours par paire : pushMatrix() et popMatrix(). Nous verrons en fin de chapitre pourquoi ces deux fonctions portent un nom si bizarre.

Pour les deux exemples qui suivent, nous allons identifier les transformations suivantes :

  • À : origine en haut à gauche de la fenêtre.
  • B : origine au centre de l'écran.
  • C : origine au centre de l'écran, rotation de PI/4.
Image non disponible
 
Sélectionnez
size(200,200);
smooth();
rectMode(CENTER);
 
// Repère au centre de l'écran
translate(width/2,height/2);
 
// Sauvegarde de A
pushMatrix();
 
// Transformation B
rotate(PI/4);
 
// Dessin du carré noir
fill(0);
rect(0,0,120,120);
 
// Restauration A
// À ce point-là, notre repère revient au centre de l'écran
popMatrix();
 
// Dessin du carré blanc qui ne tient pas compte de la rotation
fill(255);
rect(0,0,50,50);

Il est possible d'imbriquer les sauvegardes de transformations, c'est-à-dire qu'à l'intérieur de n'importe quelle paire de pushMatrix()/popMatrix() nous pouvons rappeler ces fonctions pour sauver l'état de la transformation courante.

Reprenons l'exemple précédent en plaçant une paire pushMatrix()/popMatrix() qui encadre la première transformation translate(width/2, height/2).

Image non disponible
 
Sélectionnez
size(200,200);
smooth();
rectMode(CENTER);
noStroke();
 
// Sauvegarde de A
pushMatrix();
 
// Transformation B
translate(width/2,height/2);
 
// Sauvegarde de B
pushMatrix();
 
// Transformation C
rotate(PI/4);
 
// Dessin du carré noir
fill(0);
rect(0,0,120,120);
 
// Restauration de B
popMatrix();
 
// Dessin du carré blanc qui ne tient pas compte
// de la rotation rotate(PI/4)
fill(255);
rect(0,0,50,50);
 
// Restauration de A
popMatrix();
 
// Dessin du carré gris
fill(128);
rect(0,0,100,100);

III-D-6. Transformer en 3D

Toutes les transformations que nous venons d'aborder sont applicables en trois dimensions (3D). Processing permet de passer en 3D au moment de l'appel à size() :

 
Sélectionnez
size(300,300,P3D);

Dans ce mode, Processing définit un axe z qui pointe vers le fond de l'écran.

Image non disponible

Les transformations de déplacement et de mise à l'échelle vont s'écrire en intégrant un troisième paramètre. Par exemple, pour se déplacer au centre de l'écran le long de x et y puis dessiner les formes comme si elles étaient éloignées de nous, nous pourrions écrire la ligne de code suivante :

 
Sélectionnez
translate(width/2, height/2, -100);

Pour les rotations, nous disposons de trois fonctions : rotateX, rotateY et rotateZ qui permettent respectivement de tourner autour des axes x, y et z.

Processing intègre des fonctions de dessin de formes simples en 3D, notamment les cubes et les sphères. Nous allons créer un cube dont la rotation autour des axes x et y va être paramétré par la position de la souris.

Image non disponible
 
Sélectionnez
float rx = 0;
float ry = 0;
float z = 100;
 
void setup() {
  size(200,200,P3D);
}
 
void draw() {
  background(128);
  rx = map(mouseX, 0,width,-PI,PI);
  ry = map(mouseY, 0,height,-PI,PI);
 
  translate(width/2,height/2,z);
  rotateX(rx);
  rotateY(ry);
  box(30);
}

Dans ce sketch, nous avons introduit une nouvelle fonction map(), qui permet de transformer une valeur d'une plage de valeurs à une autre plage de valeurs. Voici un exemple simple pour expliquer ce concept :

 
Sélectionnez
float v = 100;
float m = map(v,0,200, 0,1); // m vaut 0.5

Dans cet exemple, map()va transformer la valeur 100 qui est dans l'intervalle [0;200] et calculer la valeur équivalente dans l'intervalle [0;1]. La valeur 0.5 est retournée dans m.

Dans notre sketch, cette fonction permet de transformer la valeur de mouseX  dans l'intervalle situé entre 0 et width en une valeur équivalente dans l'intervalle entre -PI et PI.

Les concepts de pushMatrix() et popMatrix() sont aussi applicables en 3D pour sauvegarder et restaurer les transformations. C'est le meilleur moyen pour dessiner des univers en 3D, contenant plusieurs objets en mouvement les uns par rapport aux autres sans avoir recours à des concepts mathématiques complexes.

Toutes les transformations dans Processing sont stockées dans un tableau de 16 nombres qui est appelé matrice ou matrix en anglais. Ces nombres sont directement modifiés par des appels aux fonctions de transformations. Si vous êtes curieux, vous pouvez imprimer ce tableau par la fonction printMatrix().


précédentsommairesuivant

Licence Creative Commons
Le contenu de cet article est rédigé par Flossmanuals et est mis à disposition selon les termes de la Licence Creative Commons Attribution 3.0 non transposé.
Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright © 2013 Developpez.com.