Les Étincelles du Palais de la découverte
La médiation scientifique
Découvrez le futur Palais
<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);
pjs.setVitesseRotation(0);
function reStart(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;
pertChoice=document.getElementById('pertInput').value;
pjs.newStart(nbIterationChoice,pertChoice,typePerturbationChoice); }
<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 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 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);
//Premiere colonne
if(j==0)
graine[i][j]=(graine[i-1][j]+graine[i+1][j]+graine[i][j+1])/3+choixPerturbation(i,j);
//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);
//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);
vertex((j+1)*largeurCarreau-largeur/2,(i+1)*longueurCarreau-longueur/2,graine[i+1][j+1]-hauteur/2);
//Carreaux sur le côté droit
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);
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.
Etape 2: On insère de nouvelles lignes et colonnes entre les nombres pour obtenir, ici, un carré de 3x3
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 !
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.
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.
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.
<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é
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>