<html>

<script type="text/javascript" src="fileadmin/fileadmin_Palais/fichiersContribs/au-programme/expos-permanentes/Informatique-sciences-du-numerique/_images/ExperienceInfo/Processing/processing.js"></script>

<script type="application/javascript">

/*

* This code searches for all the <script type="application/processing" target="canvasid">

* in your page and loads each script in the target canvas with the proper id.

* It is useful to smooth the process of adding Processing code in your page and starting

* the Processing.js engine.

*/

if (window.addEventListener) {

window.addEventListener("load", function() {

var scripts = document.getElementsByTagName("script");

var canvasArray = Array.prototype.slice.call(document.getElementsByTagName("canvas"));

var canvas;

for (var i = 0, j = 0; i < scripts.length; i++) {

if (scripts[i].type == "application/processing") {

var src = scripts[i].getAttribute("target");

if (src && src.indexOf("#") > -1) {

canvas = document.getElementById(src.substr(src.indexOf("#") + 1));

if (canvas) {

new Processing(canvas, scripts[i].text);

for (var k = 0; k< canvasArray.length; k++)

{

if (canvasArray[k] === canvas) {

// remove the canvas from the array so we dont override it in the else

canvasArray.splice(k,1);

}

}

}

} else {

if (canvasArray.length >= j) {

new Processing(canvasArray[j], scripts[i].text);

}

j++;

}

}

}

}, false);

}

</script>

<script type="text/javascript">

function setRotation(id){

var pjs = Processing.getInstanceById(id);

var checkBox = document.getElementById("rota");

if (checkBox.checked == true){

pjs.setVitesseRotation(1);

} else {

pjs.setVitesseRotation(0);

}

}

function reStart(id) {

var pjs = Processing.getInstanceById(id);

var nbIterationChoice;

var typePerturbationChoice;

var pertChoice;

var radio1 = document.getElementsByName('iterInput');

var radio2 = document.getElementsByName('perType');

for (var i=0, len=radio1.length; i

if ( radio1[i].checked ) {

nbIterationChoice = radio1[i].value;

break;

}

}

for (var i=0, len=radio2.length; i

if ( radio2[i].checked ) {

typePerturbationChoice = radio2[i].value;

break;

}

}

pertChoice=document.getElementById('pertInput').value;

pjs.newStart(nbIterationChoice,pertChoice,typePerturbationChoice); }

</script>

<script type="application/processing" target="montains">

//Taille du tableau

int nbIteration;

//Taille du dessin

int longueur=700;

int largeur=700;

int hauteur=500;

int perturbationHauteur;

int typePerturbation;

//Plus grande hauteur d'une montagne

float higher;

//Rotation du dessin

float rotationX=PI/3;

float rotationY=0;

float rotationZ=0;

float vitesseRotation=0.0;

//Autre variable du dessin

boolean move=true;

int textu=0;

float[][] graine= new float[2][2];

float[][] tmpGraine= new float[2][2];

void setup(){

size(700,500,P3D);

newStart(3,100,1);

}

//Cette fonction permet de relancer le calcul dans le code javascript de la page web

//On ne peut pas le relancer avec setup() qui ne s'execute qu'une fois

void newStart(int setnbIteration, int setPerturbationHauteur, int setTypePerturbation){

higher=0;

nbIteration=setnbIteration;

typePerturbation=setTypePerturbation;

perturbationHauteur=setPerturbationHauteur;

graine= new float[2][2];

//Initialisation graine

graine[0][0]=random(hauteur);

graine[0][1]=random(hauteur);

graine[1][0]=random(hauteur);

graine[1][1]=random(hauteur);

//Croissance de la graine

for(int i=0;i<=nbIteration;i++){

diamant();

carre();

};

//Getting highest montain

for(int i=0;i<=graine.length-1;i++){

for(int j=1;j<=graine[i].length-1;j++){

if(higher

};

};

}

//Comment perturber chaque noeud

float choixPerturbation(int i, int j){

float tmp=0.0;

if(typePerturbation==1){tmp=random(-perturbationHauteur,perturbationHauteur);}else{tmp=random(-perturbationHauteur/(graine.length-1),perturbationHauteur/(graine.length-1));}

return tmp;

}

//Diamant

void diamant(){

//Ajouter une valeur 0 entre chaque colonne

for(int i=0;i<=graine.length-1;i++){

for(int j=1;j<=graine[i].length-1;j=j+2){

graine[i]=(float[]) splice(graine[i],0.0,j);

}

};

float[][] tmpGraineNew= new float[graine[0].length][2*(graine.length-1)+1];

for(int i=1;i<=graine.length-1;i++){

float [][] tmpLigne=new float[1][graine[0].length];

for(int k=0;k<=tmpLigne[0].length-1;k++){

tmpLigne[0][k]=0.0;

}

//Introduction d'une valeur alleatoire au centre d'un carre

for(int j=1;j<=tmpLigne[0].length-2;j=j+2){

tmpLigne[0][j]=(graine[i-1][j-1]+graine[i-1][j+1]+graine[i][j-1]+graine[i][j+1])/4+choixPerturbation(i,j);

}

tmpGraineNew[2*i-2]=graine[i-1];

tmpGraineNew[2*i-1]=tmpLigne[0];

}

tmpGraineNew[tmpGraineNew.length-1]=graine[graine.length-1];

graine=tmpGraineNew;

}

//Carre

void carre(){

for(int i=0;i<=graine.length-1;i++){

for(int j=0;j<=graine[i].length-1;j++){

if(graine[i][j]==0.0){

//si ligne paire, si ligne impaire

//Premiere ligne

if(i==0)

{

graine[i][j]=(graine[i][j-1]+graine[i][j+1]+graine[i+1][j])/3+choixPerturbation(i,j);

}

else

{

//Dernière ligne

if(i==graine.length-1)

{

graine[i][j]=(graine[i][j-1]+graine[i][j+1]+graine[i-1][j])/3+choixPerturbation(i,j);

}

else

{

//Premiere colonne

if(j==0)

{

graine[i][j]=(graine[i-1][j]+graine[i+1][j]+graine[i][j+1])/3+choixPerturbation(i,j);

}

else

{

//Derniere colonne

if(j==graine[i].length-1)

{

graine[i][j]=(graine[i-1][j]+graine[i+1][j]+graine[i][j-1])/3+choixPerturbation(i,j);

}

else

//Cases pas sur les bords

{

graine[i][j]=(graine[i-1][j]+graine[i+1][j]+graine[i][j-1]+graine[i][j+1])/4+choixPerturbation(i,j);

}

}

}

}

}

}

}

}

void setVitesseRotation(int choix){

if(choix==0){vitesseRotation=0;}

else{vitesseRotation=0.01;}

}

void draw(){

stroke(0);

strokeWeight(1);

if(move){

float largeurCarreau=largeur/(graine[0].length-1);

float longueurCarreau=longueur/(graine.length-1);

background(0,0,200);

translate(largeur/2,longueur/3,-higher/2);

rotationZ=(rotationZ+vitesseRotation);

rotateX(rotationX);

rotateZ(rotationZ);

smooth();

for(int i=0;i<=graine.length-2;i++){

for(int j=0;j<=graine[0].length-2;j++){

//Pour chaque carré, on dessine 2 triangles pour déformer la surface

beginShape();

//Couleur

fill(255);

//Texture

vertex(j*largeurCarreau-largeur/2,i*longueurCarreau-longueur/2,graine[i][j]-hauteur/2);

vertex((j+1)*largeurCarreau-largeur/2,i*longueurCarreau-longueur/2,graine[i][j+1]-hauteur/2);

vertex(j*largeurCarreau-largeur/2,(i+1)*longueurCarreau-longueur/2,graine[i+1][j]-hauteur/2);

endShape(CLOSE);

beginShape();

vertex((j+1)*largeurCarreau-largeur/2,i*longueurCarreau-longueur/2,graine[i][j+1]-hauteur/2);

vertex((j+1)*largeurCarreau-largeur/2,(i+1)*longueurCarreau-longueur/2,graine[i+1][j+1]-hauteur/2);

vertex(j*largeurCarreau-largeur/2,(i+1)*longueurCarreau-longueur/2,graine[i+1][j]-hauteur/2);

endShape(CLOSE);

};

//Carreaux sur le côté droit

beginShape();

vertex((graine[0].length-1)*largeurCarreau-largeur/2,i*longueurCarreau-longueur/2,graine[i][graine[0].length-1]-hauteur/2);

vertex((graine[0].length-1)*largeurCarreau-largeur/2,(i+1)*longueurCarreau-longueur/2,graine[i+1][graine[0].length-1]-hauteur/2);

vertex((graine[0].length-2)*largeurCarreau-largeur/2,(i+1)*longueurCarreau-longueur/2,graine[i+1][graine[0].length-2]-hauteur/2);

endShape(CLOSE);

};

}

}

</script>

Une montagne réalisée à l'aide de l'algorithme du diamant-carré (itérations=4, perturbations=400, lissé).

Si les textures des montagnes dans les jeux vidéos peuvent être créées par des artistes, ce ne sont généralement pas le cas de leurs formes qui peuvent être générées par des algorithmes. En effet, pensez aux jeux où le terrain n'a pas de limite, il faut bien trouver une méthode, un moyen automatique de créer les montagnes sans fins des paysages que vous traversez. Il faut également que cet algorithme crée des montagnes réalistes, naturelles. Le plus simple d'entre eux est celui du diamant-carré. Comment fonctionne t-il ? Une explication pas à pas ci-dessous !

Etape 1: On commence par créer un tableau avec quatre nombres pris au hasard. On a pris ci-dessous des nombres entiers pour que ce soit plus simple mais bien sûr on peut prendre n'importe quel réel avec un signe + ou - ! On obtient ainsi un carré de 2x2.

215168
38453

Etape 2: On insère de nouvelles lignes et colonnes entre les nombres pour obtenir, ici, un carré de 3x3

215 168
   
384 53

Etape 3: On va calculer le nombre pour la case vide au centre du carré. Pour cela, on fait la moyenne des nombres qui l'entourent, soit (215+168+384+53)/4=205, et on la perturbe en ajoutant un nombre pris au hasard dans un intervalle, par exemple [-100,100], comme -10. On obtient ainsi la valeur 205-10=195. Les nombres du tableau ci-dessous forment désormais une croix, comme un diamant !

215 168
 195 
384 53

Etape 4: on recommence à faire des carrés de nombres à partir de notre diamant en calculant de la même manière qu'indiqué ci-dessus les nombres pour les cases vides: on fait la moyenne des nombres entourant chaque case vide et on la perturbe. Par exemple pour la case sur la gauche, (215+195+384)/3=264.667, On perturbe un peu avec un nombre pris au hasard dans l'intervalle plus haut pour obtenir 289.

215232168
289195118
38424253

Etapes suivantes: On a désormais un tableau constitué de quatre carrés de quatre nombres et on recommence à partir de l'étape 2, en insérant de nouvelles lignes et colonnes vides entre les nombres que l'on va remplir en refaisant les étapes 3 et 4. On obtient ainsi, à force de répétition, un tableau de nombres de plus en plus grand.

Attribuons maintenant ces nombres aux nœuds d'un quadrillage. Ils désignent alors la hauteur du nœud dans l'espace. Comme par 3 points dans l'espace, il ne peut passer qu'un unique plan, en reliant tous les ensembles de trois nœuds côte à côte par des droites, on obtient ainsi une surface déformée qui ressemble à une montagne pavée de triangles comme dans la simulation ci-dessous.

En faire des montagnes

La simulation ci-dessous est une application de l'algorithme du diamant-carré. Vous pouvez ainsi tester la création de montagnes en appuyant sur le bouton "Redessiner". La case "rotation" permet ou pas de faire tourner le paysage. Certains paramètres sont modifiables et permettent ainsi de mieux comprendre l'algorithme.

  • Nombre d'itérations: nombre de fois où l'algorithme du diamant-carré est répété. Plus il est grand, plus le tableau de nombres est grand et plus le paysage est vaste.
  • Amplitude des perturbations: décide à quel point vous allez perturber les moyennes calculées dans le tableau. Plus elles seront perturbées , plus le paysage aura des pics marqués.
  • Type de perturbations: le choix "Escarpé" fait que la perturbation sera choisie dans un intervalle de nombres [-Amplitude,+Amplitude] comme expliqué plus haut avec [-100,100]. Le paysage sera donc fait de nombreux sommets bien marqués, comme le sont les jeunes montagnes. Mais on peut aussi choisir un paysage plus lisse, comme le sont les vieilles montagnes érodées par le temps, pour un rendu très différent avec moins de pics. Dans ce dernier cas, on peut choisir de prendre une perturbation dans un intervalle de nombres qui se modifie à chaque répétition de l'algorithme comme [-Amplitude,+Amplitude]/(Taille du tableau à la nième répétition).

<canvas id="montains"></canvas>

<button type="button" onclick="reStart('montains')">Redessiner</button>

<input type="checkbox" id="rota" onclick="setRotation('montains')">

Rotation
 

nombre d'itérations

<input type="radio" id="un" name="iterInput" value="1">

1

<input type="radio" id="deux" name="iterInput" value="2">

2

<input type="radio" id="trois" name="iterInput" value="3" checked>

3

<input type="radio" id="quatre" name="iterInput" value="4">

4

Amplitude des perturbations:

<input type="textfield" value="100" id="pertInput" size="2" maxlength="3">

Type de perturbations:

<input type="radio" id="esc" name="perType" value="1" checked>

Escarpé

<input type="radio" id="lis" name="perType" value="2">

Lissé

Le code

Vous trouverez ci-dessous le code correspondant à l'algorithme du diamant-carré dans le langage Processing
 

<input type="button" value="Télécharger" onclick="window.location='fileadmin/fileadmin_Palais/fichiersContribs/au-programme/expos-permanentes/Informatique-sciences-du-numerique/_images/ExperienceInfo/MontagneDiamCarr/DiamantCarreOriginal.zip';">

</html>