====== KINECT/MULTITOUCH ====== * Porteur du projet : Audrey Herd-Smith, Morgane Guillaume * Date : 04/2015 * Fichiers du code de base: {{:wiki:projets:gaite:kinect_multi_hotpoint_commentee.zip|}} ===== Description du projet ===== Comment joindre le son et son acteur avec l'espace ? L'installation proposée permet de créer un univers graphique scénique et visuel tout en offrant une grande liberté d'intervention sur la musique. Elle s'adapte au titre Love Like a Sunset de Phoenix. Ce morceau, comme une accumulation sonore, renvoie au voyage. Un résultat abstrait se présente suite aux expériences graphiques opérées sur des visuels de paysages (montagne). Ils permettent une superposition des traits et aplats crées, renvoyant à la manipulation possible des samples de Phoenix. Chque sample correspond à un module (volume pyramidale) et s'active au paysage d'une main en dessous. Ces zones de réactivité sont générées par la Kinect et le programme sous Processing. ===== Matériaux ===== Kinect avec connection USB pour PC/MAC + vidéoprojecteur ===== Tutoriel d'installation de la kinect ===== Librairies nécessaires pour Kinect: * OPENNI (PC) * SDK Kinect: driver (PC) * SimpleOpenNI Fichier d'installation : {{:wiki:projets:gaite:installation_kinect.zip|}} ===== Photos ===== {{:wiki:projets:gaite:01.jpg?200|}} {{:wiki:projets:gaite:02.jpg?200|}} {{:wiki:projets:gaite:03.jpg?200|}} {{:wiki:projets:gaite:05.jpg?200|}} {{:wiki:projets:gaite:04.jpg?200|}} {{:wiki:projets:gaite:vid-20150203-wa0000.mp4|}} ==== code processing (mise à jour 09 Avril 2015)==== Attention : deux onglets // LIBRAIRIES import processing.opengl.*; // librairie qui initialise la 3D import SimpleOpenNI.*; // librairie de la kinect import ddf.minim.*; // librairie de son // VARIABLES GLOBALES SimpleOpenNI kinect; float rotation = 0; Minim minim; // Déclaration d'un TABLEAU dynamique "ArrayList" contenant les objets de type "AudioPlayer" (les sons) ( qui sont associés aux cubes/hotpoint) ArrayList playList; // Déclaration d'un TABLEAU dynamique "ArrayList" contenant les objets de type "Hotpoint" (cubes spatiaux) ArrayList trigers; int nbHotpoint = 8 ; // nombre de hotpoints (cubes spatiaux) // Déclaration d'un TABLEAU dynamique "ArrayList" de PVector ( de vecteurs) contenant les positions des cubes spatiaux ArrayList trigerPos; // Déclaration d'un TABLEAU dynamique "ArrayList" d' IMAGES ArrayList images; // DEFINTION DE LA POSITION exact des hotpoints (cubes spatiaux) dans l'espace sachant que 1000 pixels = 1m //IRCAM (devant CS) float posX3 = -750, posY3 = 000, posZ3 = 2100; //CS (tout au fond gauche) float posX13 = -550, posY13 = 000, posZ13 = 2500; //Reich(tout au fond droite) float posX30 = 550, posY30 = 000, posZ30 = 2600; //Oiseau (devant reich) float posX32 = 750, posY32 = 000, posZ32 = 2200; //Guit float posX35 = -500, posY35 = 000, posZ35 = 1800; //AC float posX36 = 200, posY36 = 000, posZ36 = 1300; //Nu float posX38 = 500, posY38 = 000, posZ38 = 1800; //HH float posX54 = -200, posY54 = 000, posZ54 = 1300; ////////////////////////////////////////////SETUP void setup() { size(2048, 1100, OPENGL); //taille ecran de la salle : 2048*1100 // ECRAN ORDI PORTABLE MORGANE 2048*745 kinect = new SimpleOpenNI(this); // instancie la librairie SimpleOpenNi kinect.enableDepth(); // permet la profondeur minim = new Minim(this); // CREATION DE LA LISTE (Arraylist) DE SONS (playList) initialement vide playList = new ArrayList(); // REMPLISSAGE DE LA LISTE (par importation de sons dans la playlist) //IRCAM playList.add(minim.loadFile("IRCAM3.mp3")); //CS playList.add(minim.loadFile("CS1.mp3")); //reich playList.add(minim.loadFile("Reich.mp3")); //Oiseau playList.add(minim.loadFile("GtrOiseaux2.mp3")); //Guit playList.add(minim.loadFile("GuitC.mp3")); //AC playList.add(minim.loadFile("AC.mp3")); //Nu playList.add(minim.loadFile("Nu1.mp3")); //HH playList.add(minim.loadFile("HH3.mp3")); // CREATION DE LA LISTE (Arraylist) DE POSITIONS (PVector) des Hotpoints (cubes sapatiux) initialement vide trigerPos = new ArrayList(); // REMPLISSAGE DE LA LISTE //ircam trigerPos.add( new PVector(posX3,posY3,posZ3)); //CS trigerPos.add( new PVector(posX13,posY13,posZ13)); //Reich trigerPos.add( new PVector(posX30,posY30,posZ30)); //Oiseau trigerPos.add( new PVector(posX32,posY32,posZ32)); //Guit trigerPos.add( new PVector(posX35,posY35,posZ35)); //AC trigerPos.add( new PVector(posX36,posY36,posZ36)); //Nu trigerPos.add( new PVector(posX38,posY38,posZ38)); //HH trigerPos.add( new PVector(posX54,posY54,posZ54)); // CREATION DE LA LISTE (Arraylist) D'IMAGES initialement vide images = new ArrayList(); // REMPLISSAGE DE LA LISTE d'images //ircam images.add(loadImage("araignee.png")); //CS images.add(loadImage("gris1.png")); //Reich images.add(loadImage("gris2.png")); //Oiseau images.add(loadImage("gris3.png")); //Guit images.add(loadImage("mont1.png")); //AC images.add(loadImage("gris0.png")); //Nu images.add(loadImage("mont2.png")); //HH images.add(loadImage("vert.png")); // CREATION DE LA LISTE (Arraylist) HOTPOINTS (Cube spatiaux) "trigers" initialement vide -----> verifier que c'est bien la liste des hotpoints trigers = new ArrayList(nbHotpoint); // INITIALISATION DE LA LISTE DES HOTPOINTS (cubes spatiaux): on crée tous les hotPoints de la liste - on utilise le consructeur 2 for (int i = 0; i < nbHotpoint; i++) { trigers.add( new Hotpoint(trigerPos.get(i), //ajout des données de positions aux hotpoints 100, 100,100, //dimension des hotpoints(/cubes spatiaux) (largeur, hauteur, profondeur) playList.get(i) , // position du cube // largeur,hauteur,profondeur // son associé images.get(i))) ; } } /////////////////////////////////////FIN SETUP //////////////////////////////////// DRAW void draw() { background(#FFFFFF); // fond de la fenêtre kinect.update(); // mise à jour des données de la kinect translate(width/2, height/2,-200); // permet de placer la représentation dans l'esapce // LE DERNIER NOMBRE INDIQUE LA PROFONDEUR Z DE LA REPRESENTAION rotateX(radians(180));// determine le placement la représentation et permet une rotation //translate(0, 0, 1400); // detemine le placement de la représentation sur l'axe des y //rotateY(radians(map(mouseX, 0, width, -180, 180))); // determine les valeur du mouvement de la rotation exercer avec la souris //translate(0, 0, -1500); // determine l'échelle de la représentation dans l'axe des z (profondeur) stroke(#000055); // couleur des lignes de l'environnement (les gens qui se mettent en face de la kinect, le mur au fond ...) strokeWeight(0); //épaisseur traits de l'environnement PVector[] depthPoints = kinect.depthMapRealWorld(); // création du tableau de vecteur depthPoints : ce sont les points de l'environement, ils sont donnés par la kinect avec la méthode propre à elle qui s'appelle depthMapRealWorld for (int i = 0; i < depthPoints.length; i+=10) { // boucle permettant de créer tout de 10 en 10 les points detecté par la kinect par depthPoint PVector currentPoint = depthPoints[i]; // créer les vecteurs du tableau des points(en cours d'analyse) depthPoint qui s'appelera currentPoint for (Hotpoint HP : trigers) { HP.check(currentPoint); } point(currentPoint.x, currentPoint.y, currentPoint.z); //points qui determinent/visualisent l'environnement (le/les corps, les objets, les murs ...) } for (Hotpoint HP : trigers) { // pour tous les Hotpoint de la liste "trigers" if(HP.sound.isPlaying()){ HP.apparaitre(); } if (HP.isHit()) {// On effectue les actions suivantes uniquement si le cube (Hotpoint) concerné // est touché dans la boucle draw() actuelle et n'était pas touché dans la boucle draw() précédente //i.e. ssi currentlyHit() == true (le cube est en train d'être touché dans la boucle draw() actuelle) et wasJustHit==false (le cube n'était pas touchée dans la boucle draw() précédente) // si la musique ne joue pas alors on lance la musique en boucle if( !HP.sound.isPlaying()){ HP.sound.play(); HP.sound.loop(); HP.apparaitre(); } else { // sinon, si la musique joue, on l'arrête et on rembobine la bande HP.sound.pause(); HP.sound.rewind(); } }// tant que le cube est touché, on laisse jouer la musique car on ne rentre pas dans le test if(HP.isHit())... //dessine le hotPoint (cube) coloré avec une transparence plus ou moins importante en fonction du porcentage d'inclusion HP.draw();//execution de méthode draw issue de la class hotpoint (création des hotpoints) : HP.clear(); // garde en mémoire si le hotPoint est touché ou non pour la boucle draw() suivante // cette action fixe la valeur de l'attrubut wasJustHit: } } ///////////////////////////////////////////////FIN DRAW Second onglet : //création d'une classe créant les cubes interactifs class Hotpoint { PVector center; color fillColor; color strokeColor; float profondeur; // profondeur du carré float largeur; //largeur du carré float hauteur; //hauteur du carré float pointsIncluded; int maxPoints; boolean wasJustHit; int threshold; // seuil AudioPlayer sound; PImage visuel; int Imgx,Imgy; float x=-900; float y=-500; ////////////////////////////////////////// CONSTRUCTEUR Hotpoint(PVector pos, float larg, float haut, float prof, AudioPlayer s,PImage v ) { //constructeur de Hotpoint, déterminé par la position dans l'espace du cube (x,y,z) et la taille du cube (x,y,z) center = pos; //création du vecteur attribut de Hotpoint, c'est la position dans l'espace. Il commence au centre du cube pointsIncluded = 0; // les points de profondeur vont être analyser, commencer à zéro maxPoints = 1000; threshold = 0; // threshold = seuil largeur=larg; profondeur=prof; hauteur=haut; fillColor = strokeColor = color(random(255), random(255), random(255)); //on commence avec une valeur aléatoire, qui sera redéfinie par setColor // MUSIQUE associée au Hotpoint (cubes spatiaux) lorsqu'il est touché sound = s ; // IMAGE associée au Hotpoint (cubes spatiaux) lorsqu'il est touché visuel = v ; } ////////////////////////////////////METHODES void setThreshold( int newThreshold ){ // changer la valeur du seuil avec celle écrit entre parenthèse lorsque la méthode est appelée threshold = newThreshold; } void setMaxPoints(int newMaxPoints) { // changer la valeur maximum de points maxPoints = newMaxPoints; } void setColor(float red, float blue, float green){ // changer la couleur des cubes avec les variable red, blue, green fillColor = strokeColor = color(red, blue, green); // les contours et la surface est de la même couleur } boolean check(PVector point) { //création de la méthode vrai/faux (booléenne) appelé check, elle intervient sur le vecteur point boolean result = false; //par défaut le résultat est négatif if (point.x > center.x - largeur/2 && point.x < center.x + largeur/2) { //si la valeur en x du point analysé (c'est un point de profondeur définie dans la fenêtre programme principale) // n'est pas comprise entre la première valeur x du cube et la dernière //(si l'abscisse de point est inférieure à l'abscisse du centre du cube Moins la moitié de la largeur du cube (= la fin du cube en x) // ET si l'abscisse de point est inférieure à l'abscisse du centre du cube Plus la moitié de la largeur du cube (= le début du cube en x) if (point.y > center.y - hauteur/2 && point.y < center.y + hauteur/2) { //de même que pour x vérifier avec y if (point.z > center.z - profondeur/2 && point.z < center.z + profondeur/2) { //de même que pour x vérifier avec z result = true; // si le point de profondeur analysé est compris dans les valeurs x,y et z du cube, alors changer la variable result en vrai pointsIncluded++; //incrémenter pointIncluded de 1 } } } return result; // réécrir le result, le résultat booléin. } void apparaitre() { x=x+random(-3,3); //cepermet de faire bouger l'image y=y+random(-3,3); image(visuel,x,y); // x et y sont définis dans les attributs // image(visuel,-900 ,-500); } // void draw spécifique à la classe Hotpoint void draw() { pushMatrix(); // créer un cube avec un style qui lui est propre //placer le cube selon PVector center translate(center.x, center.y, center.z); // remplir le cube de couleur définie par fillColor, mais changer Alpha selon le pourcentage percentIncluded, // il dépend de la présence ou non d'un point de profondeur depthPoint dans le cube fill(red(fillColor), blue(fillColor), green(fillColor), 255 * percentIncluded()); //définir les contours selon les couleurs définies précédemment, toujours les laisser apparente (alpha = 255) stroke(red(strokeColor), blue(strokeColor), green(strokeColor), 255); // dessiner le cube selon size, une taille définie précedemment, box s'écrit aussi box(w,h,l) box(largeur,hauteur, profondeur); // Determiner la largeur, la taille et la profondeur de la box popMatrix(); //fin de la démarquation de style } float percentIncluded() { //création de la valeur de pourcentage //map permet de changer le nom pointsIncluded return map(pointsIncluded, 0, maxPoints, 0, 1); // return permet de remplacer la valeur de pointIncluded dans le reste du code, il sera utilisé plus haut pour définir l'alpha du cube } boolean currentlyHit() { return pointsIncluded > threshold; // vérification : les points de la main inclus dans l'objet sont supérieur à ceux du seuil de l'objet (threshold), vrai ou faux ? (décrit par la boolean) } boolean isHit() { return currentlyHit() && !wasJustHit; // vérification si le cube est touché ou non } void clear() { wasJustHit = currentlyHit(); // quand la main rentre dans l'objet, si la vérification : les points de la main inclus dans l'objet sont supérieur à ceux du seuil de l'objet (threshold), pointsIncluded = 0; // alors, les points de la mains inclus dans l'objet sont remis à 0 } } ==== Fichier audio pour faire tourner le code ==== Télécharger les fichiers audios suivants, et les placer dans le dossier "data" de votre "sketch folder" : * IRCAM3.mp3 * CS1.mp3 * Reich.mp3 * GtrOiseaux2.mp3 * GuitC.mp3 * AC.mp3 * Nu1.mp3 * HH3.mp3 ------------------------------- A COMPLETER !!!!!!