Chapitre 1 : Introduction - Programmation 3D



Documents pareils
TPs Architecture des ordinateurs DUT Informatique - M4104c SUJETS. R. Raffin Aix-Marseille Université romain.raffin-at-univ-amu.fr

M2-Images. Rendu Temps Réel - OpenGL 4 et compute shaders. J.C. Iehl. December 18, 2013

Chapitre 3 : Repères et positionnement 3D

GPGPU. Cours de MII 2

TP : Gestion d une image au format PGM

Synthèse d'images I. Venceslas BIRI IGM Université de Marne La

Développement mobile MIDP 2.0 Mobile 3D Graphics API (M3G) JSR 184. Frédéric BERTIN

TP1 : Initiation à Java et Eclipse

Modélisation de la vision humaine

Rendu temps réel de mer et de nuages

TP1. Outils Java Eléments de correction

1 Introduction et installation

Introduction à la Programmation Parallèle: MPI

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP

TP n 2 Concepts de la programmation Objets Master 1 mention IL, semestre 2 Le type Abstrait Pile

Programmation en Java IUT GEII (MC-II1) 1

TD : Codage des images

EPREUVE OPTIONNELLE d INFORMATIQUE CORRIGE

Chapitre II : Infographie et bibliothèques graphiques

4. Utilisation d un SGBD : le langage SQL. 5. Normalisation

Licence Bio Informatique Année Premiers pas. Exercice 1 Hello World parce qu il faut bien commencer par quelque chose...

Comment intégrer des images dans un texte

Gnuplot. Chapitre Lancer Gnuplot. 3.2 Options des graphes

DE L ALGORITHME AU PROGRAMME INTRO AU LANGAGE C 51

RIE LE RENDU THEO. 2 e trim ÉTAPE DE FINITION BOÎTE DE DIALOGUE. remarques

Gestion d identités PSL Exploitation IdP Authentic

INTRODUCTION A JAVA. Fichier en langage machine Exécutable

Une bibliothèque de templates pour CUDA

ARDUINO DOSSIER RESSOURCE POUR LA CLASSE

Manuel d utilisation 26 juin Tâche à effectuer : écrire un algorithme 2

IRL : Simulation distribuée pour les systèmes embarqués

GL BE FLYER. Chef de projet de l équipe : SCIONICO Pierre

.. CSS. Damien Nouvel. Damien Nouvel (Inalco) CSS 1 / 15

LES GRANDES ETAPES DE CREATION D UN WEB DESIGN

Cours d introduction à l informatique. Partie 2 : Comment écrire un algorithme? Qu est-ce qu une variable? Expressions et instructions

PROJET DE MODELISATION CASERNE SERGEANT BLANDAN

Créer et partager des fichiers

Cours 1: Java et les objets

INTRODUCTION AU CMS MODX

Utilisation de l éditeur.

Pour les futurs développeurs Sommaire

Module.NET 3 Les Assemblys.NET

Introduction à la programmation Travaux pratiques: séance d introduction INFO0201-1

Développer des Applications Internet Riches (RIA) avec les API d ArcGIS Server. Sébastien Boutard Thomas David

ContactForm et ContactFormLight - Gestionnaires de formulaire pour Prestashop Edité par ARETMIC S.A.

Développement d un moteur de jeu vidéo pour la console Nintendo Wii U et portage d un jeu

Vers du matériel libre

Dans l Unité 3, nous avons parlé de la

TP Blender n 2 : Importation d un modèle SketchUp et animation

L analyse d images regroupe plusieurs disciplines que l on classe en deux catégories :

Systèmes d Exploitation - ENSIN6U3. Aix-Marseille Université

SOFI Gestion+ Version 5.4. Echanges de données informatiques Spicers Sofi gestion+ Groupements. SOFI Informatique. Actualisé le

Bases Java - Eclipse / Netbeans

Bases de programmation. Cours 5. Structurer les données

Introduction à MATLAB R

Cours de numérisation sur Epson Perfection

Couplage d une base de données documentaire à une visualisation interactive 3D sur l Internet

Plan du cours Cours théoriques. 29 septembre 2014

Cours intensif Java. 1er cours: de C à Java. Enrica DUCHI LIAFA, Paris 7. Septembre Enrica.Duchi@liafa.jussieu.fr

Centre CPGE TSI - Safi 2010/2011. Algorithmique et programmation :

RAPPORT AUDIT SEO. Élaboré à l'attention de : Monsieur Greber Élaboré par : Cédric Peinado

1. Structure d un programme C. 2. Commentaire: /*..texte */ On utilise aussi le commentaire du C++ qui est valable pour C: 3.

Traitement numérique de l'image. Raphaël Isdant

Création de maquette web

Cours d initiation à la programmation en C++ Johann Cuenin

Tutorial pour l installation et l utilisation de CREO et de Windchill

as Architecture des Systèmes d Information

Mise en oeuvre TSM 6.1

Installation et prise en main

Cours Base de données relationnelles. M. Boughanem, IUP STRI

Guide de réalisation d une campagne marketing

TEPZZ A_T EP A1 (19) (11) EP A1 (12) DEMANDE DE BREVET EUROPEEN. (51) Int Cl.: G07F 7/08 ( ) G06K 19/077 (2006.

Plan du cours. Historique du langage Nouveautés de Java 7

TP1 : Initiation à Java et Eclipse

µrv : Realité Virtuelle

UE Programmation Impérative Licence 2ème Année

Tutoriel QSOS. Version /02/2013

Structurer ses données : les tableaux. Introduction à la programmation

Création et Gestion des tables

Initiation à linfographie

Compte Rendu d intégration d application

Introduction à CUDA.

Modélisation PHP Orientée Objet pour les Projets Modèle MVC (Modèle Vue Contrôleur) Mini Framework

Cours IV Mise en orbite

LPP SAINT JOSEPH BELFORT MODE OPERATOIRE ACTIVINSPIRE. Bonne utilisation à toutes et tous! UTILISATION DES TBI LE LOGICIEL ACTIVINSPIRE

Initiation à html et à la création d'un site web

Prénom : Matricule : Sigle et titre du cours Groupe Trimestre INF1101 Algorithmes et structures de données Tous H2004. Loc Jeudi 29/4/2004

But du papier : Paramétrer WSUS pour récupérer les mises à jour et administrer le serveur WSUS

Analyse de la vidéo. Chapitre La modélisation pour le suivi d objet. 10 mars Chapitre La modélisation d objet 1 / 57

Utilisation du logiciel ImageJ gratuit

Savoir lire une carte, se situer et s orienter en randonnée

Présentation du module Base de données spatio-temporelles

TP 1. Prise en main du langage Python

Sillage Météo. Notion de sillage

Conception des systèmes répartis

Cours d Algorithmique et de Langage C v 3.0

Rendu HDR et illumination par image

Manuel de formation Spaceman 1 ère journée

Transcription:

Chapitre 1 : Introduction - Programmation 3D Modélisation 3D et Synthèse Fabrice Aubert fabrice.aubert@lifl.fr IEEA - Master Info 2014-2015 F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 1 / 60

1 Objectifs de M3DS F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 2 / 60

Fondations d une application 3D Modélisation 3D : représentation et construction informatique des objets 3D (forme, position). Visualisation 3D : rendu projectif et par lancer de rayons, éclairage, texture. Interaction 3D : navigation/sélection/manipulation. Animation 3D : représentation et algorithme du mouvement. Programmation 3D : développement/réalisation. On commencera par de la programmation 3D (comment tracer?). F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 3 / 60

Orientation du cours Approche "bas-niveau" du développement 3D pour acquérir les fondements : Eléments algébriques : coordonnées, repères, produit scalaire,... (application informatique) Représentations et algorithmes fondamentaux : modèles 3D, élimination parties cachées,... Librairie de programmation 3D : OpenGL. Nous n utiliserons pas d outils "haut-niveau" : Pas d infographie : 3D Studio Max, Blender, Maya, Rhino 3D,... Pas de Conception Assistée par Ordinateur (CAO) : SolidWorks, SolidEdge, CATIA,... Pas d utilisation de frameworks de développement 3D : Unity3D, jmonkeyengine, Ogre3D, Open SceneGraph, Unreal Engine,... F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 4 / 60

Environnement TPs C++ 11 OpenGL (> 3.0) Qt Basé sur des squelettes à compléter F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 5 / 60

2 Introduction à OpenGL F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 6 / 60

OpenGL tracer des triangles... API de rendu 3D dédiée aux cartes graphiques. 2 librairies majeures sur desktop : OpenGL et Direct3D déclinaison sur mobile : OpenGL ES déclinaison pour le web : WebGL Spécifications définies par le consortium http ://www.khronos.org/ Site officiel : http ://www.opengl.org/ F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 7 / 60

Tutoriels OpenGL http ://www.arcsynthesis.org/gltut/ http ://www.opengl-tutorial.org/ http ://ogldev.atspace.co.uk/ F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 8 / 60

Mise en place Initialisation d un contexte OpenGL par le serveur graphique (Windows, X11, etc). Opération très bas-niveau les frameworks GUI "usuels" (Qt, GTK+, wxwidgets,...) proposent de gérer une fenêtre/widget OpenGL. ou passer par une librairie dédiée (exemple : freeglut). les squelettes des tps utilisent le framework Qt (ouverture de la fenêtre OpenGL, etc, assuré par les squelettes). F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 9 / 60

Squelette des TP Mise en oeuvre usuelle (événementiel ; démarche similaire dans tous les frameworks) : GLApplication : : GLApplication ( ) { / / constructeur => initialisation des données de l application... void GLApplication : : i n i t i a l i z e ( ) { / / appelée 1 seule fois à l initialisation du contexte OpenGL / / => i n i t i a l i s a t i o n s concernant OpenGL glclearcolor ( 1, 1, 1, 1 ) ; / /... void GLApplication : : r e s i z e ( i n t width, i n t height ) { / / appelée à chaque dimensionnement du widget OpenGL / / ( i n c l u s l ouverture de la fenê t r e ) / / => r églages l i és à l a t a i l l e de l a fenê t r e glviewport (0,0, width, height ) ; / /... void GLApplication : : update ( ) { / / appelée t o utes l e s 20ms (60Hz ) / / => mettre à jour les données de l application / / avant l a f f i c h a g e de l a prochaine image ( animation ) / /... void GLApplication : : draw ( ) { / / appelée après chaque update / / => tracer toute l image g l C l e a r (GL_COLOR_BUFFER_BIT ) ; / /... F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 10 / 60

Premier exemple Se familiariser avec le vocabulaire technique de la prog3d Vertex Buffer Object (VBO) Vertex Array Object (VAO) Program Shader (Vertex Shader et Fragment Shader). Commandes de tracé. Suite du chapitre : très technique! (CTD = principes/étapes/commentaires nécessaires ; TP = mise en pratique du code)??? ====================== F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 11 / 60

Sommets des triangles On doit définir la position des 6 sommets des triangles (sommet = vertex en anglais). Les coordonnées (x,y,z) en OpenGL sont normalisées : NDC = Normalized Device Coordinates x (horizontal), y (vertical) et z (profondeur) sont comprises dans [ 1, 1] GLApplication. cpp : GLApplication. h : GLApplication : : GLApplication ( ) { class GLApplication { _positiondata ={... 0.8,0.0, 0.3, / / vertex 0 / / f i r s t t r i a n g l e GLApplication ( ) ; 0.3, 0.7, 0.3, / / vertex 1... 0.0,0.9, 0.3, / / vertex 2 private : 0.4, 0.5,0.4, / / vertex 3 / / second t r i a n g l e std : : vector <float > _positiondata ; 0. 9, 0. 4, 0. 4, / / vertex 4... 0.8, 0.9,0.4 / / vertex 5 ; F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 12 / 60

Copie sur le serveur OpenGL OpenGL manipule/trace des données qui sont dans sa propre mémoire (serveur OpenGL). Il faut donc copier les données de l application cliente dans la mémoire OpenGL. Utilisation des Vertex Buffer Objects (VBO). VBO = zone mémoire OpenGL identifiée par un entier. GLApplication. h : class GLApplication {... GLApplication ( ) ; void initvbo ( ) ;... private : std : : vector <float > _positiondata ; GLuint _ positionbuffer ; / / un i d e n t i f i a n t pour un VBO... Copie des données _positiondata dans le VBO _positionbuffer (cf signification des instructions dans transparent suivant) : GLApplication. cpp : void GLApplication : : initvbo ( ) { glgenbuffers (1,& _positionbuffer ) ; g l B in d B u f fe r (GL_ARRAY_BUFFER, _p o s i t i o n B u f f e r ) ; glbufferdata (GL_ARRAY_BUFFER, _positiondata. size () s i z e o f ( f l o a t ), _positiondata. data ( ),GL_STATIC_DRAW ) ; F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 13 / 60

VBO : Vertex Buffer Object GLApplication. cpp : void GLApplication : : initvbo ( ) { glgenbuffers (1,& _positionbuffer ) ; g l Bi n d B u f fe r (GL_ARRAY_BUFFER, _p o s i t i o n B u f f e r ) ; glbufferdata (GL_ARRAY_BUFFER, _positiondata. size () s i z e o f ( f l o a t ), _positiondata. data ( ),GL_STATIC_DRAW ) ; glgenbuffers : génère un nouvel identifiant (c est un entier) pour une zone mémoire OpenGL (un buffer). L identifiant _positionbuffer est encore appelé handle ou référence. glbindbuffer : indique quel est le VBO courant actif. Après ce bind, toutes les instructions qui concernent ARRAY_BUFFER concerneront le VBO _positionbuffer (indirection). glbufferdata : recopie les données clientes (contenues dans _positiondata) dans le buffer OpenGL référencé par ARRAY_BUFFER (ici l identifiant _positionbuffer). Syntaxe : void glbufferdata(glenum target, GLsizeiptr size, const GLvoid data, GLenum usage); Remarque : le contenu des VBO n a aucune interprétation particulière pour OpenGL! (ce sont des octets). F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 14 / 60

Commande de tracé void GLApplication : : draw ( ) { g l C l e a r (GL_COLOR_BUFFER_BIT ) ;... gldrawarrays (GL_TRIANGLES, 0, 6 ) ;... Tracer des triangles en prenant 6 sommets (0 = début = à partir du premier sommet). Cela ne suffit pas! Il faut préciser avant gldrawarrays où prendre les données des sommets et comment "afficher". F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 15 / 60

Pipeline OpenGL (principe) Etapes successives (= pipeline) lors du gldrawarrays : Idem pour les triangles suivants. F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 16 / 60

Shaders Ce sont des programmes qu il faut donner à OpenGL (sources, compilation, linkage). Langage : GLSL (GL Shading Language). Proche du C. Très orienté 3D (types prédéfinis, fonctions). Exemple de vertex shader simple (exécuté pour chaque sommet) : # version 130 in vec3 position ; / / attribut (x, y, z ) void main ( ) { gl_position=vec4 ( position, 1. 0 ) ; attribut = données d entrées pour chaque sommet. Il faudra indiquer à OpenGL comment alimenter cet attribut (i.e. où aller chercher ces données). gl_position = variable prédéfinie obligatoirement à affecter (objectif obligatoire du vertex shader = donner la position du sommet). vec4 = 4 coordonnées?? gl_position=vec4(x,y,z,w) : coordonnées homogènes (décrites plus tard). Pour l instant (on précisera au chapitre suivant) on prend w = 1.0 ; les coordonnées (x, y, z) de gl_position sont à donner en NDC (Normalized Device Coordinates). F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 17 / 60

Fragment shader Exemple de fragment shader simple (exécuté pour chaque pixel affiché) : # version 130 out vec4 fragcolor ; / / s o r t i e = données du p i x e l void main ( ) { fragcolor=vec4 ( 1, 0, 0, 1 ) ; / / rouge, vert, bleu, alpha obligatoire de donner au minimum une sortie (fragcolor ici) qui sera la couleur du pixel. remarque : toutes les données associées à un pixel sont regroupées sous le nom de fragment. F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 18 / 60

Shaders en OpenGL Il faut : Créer un identifiant pour un program shader : un program shader regroupera un vertex shader et un fragment shader. Créer les identifiants pour le fragment et le vertex shader. Affecter les codes sources à ces identifiants. Compiler le fragment et le vertex shader. Linker le program shader. F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 19 / 60

Shaders en OpenGL void GLApplication : : initprogramshader ( ) { s t r i n g vertexsource = " # version 130\n " " in vec3 position ; " / / " traditionnellement " : attribut " position " appelé " vertex " " void main ( ) { " " gl_position=vec4 ( position, 1. 0 ) ; " " " ; s t r i n g fragmentsource = " # version 130\n " " out vec4 fragcolor ; " " void main ( ) { " " fragcolor=vec4 ( 1, 0, 0, 1 ) ; " " " ; _program=glcreateprogram ( ) ; / / membre GLuint _program ; GLuint vertexshader=glcreateshader (GL_VERTEX_SHADER ) ; GLuint fragmentshader=glcreateshader (GL_FRAGMENT_SHADER) ; glattachshader ( _program, vertexshader ) ; glattachshader ( _program, fragmentshader ) ; const char source ; source=vertexsource. c _s t r ( ) ; glshadersource ( vertexshader,1,&source,null ) ; source=fragmentsource. c _str ( ) ; glshadersource ( fragmentshader,1,&source,null ) ; glcompileshader ( vertexshader ) ; glcompileshader ( fragmentshader ) ; glbindattriblocation ( _program,0, " position " ) ; gllinkprogram ( _program ) ; glbindattriblocation?? l attribut position du vertex shader sera identifié par le numéro 0 (sera utilisé pour alimenter les valeurs de cet attribut position). F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 20 / 60

Tracé OpenGL void GLApplication : : draw ( ) { / / appelée après chaque update / / => tracer toute l image g l C l e a r (GL_COLOR_BUFFER_BIT ) ; gluseprogram ( _program ) ;... gldrawarrays (GL_TRIANGLES, 0, 6 ) ; gluseprogram ( 0 ) ;... On a indiqué avec quel programme shader il faut tracer les triangles. gluseprogram(0)?? précaution pour d éventuels effets de bord ("normalement" inutile). Cela ne suffit toujours pas! Il faut préciser comment alimenter les attributs du vertex shader (i.e. sur cet exemple, indiquer où se trouvent les valeurs de l attribut position). F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 21 / 60

Vertex Array Objects (VAO) Le rôle d un VAO est d indiquer quelles seront les valeurs des attributs du vertex shader actif lors du tracé : il fait le lien entre les buffers et les attributs des shaders. VAO = indiquer pour chaque attribut du Vertex Shader quel VBO sera utilisé. Un même VAO peut être appliqué à différents shaders (et le même shader à différents VAO). Comme la très grande majorité des "Objects" OpenGL, il faut : générer un identifiant de VAO, puis faire un bind pour le rendre actif et travailler dessus : void GLApplication : : initvao ( ) { glgenvertexarrays (1,& _vao ) ; glbindvertexarray ( _vao ) ; g l Bi n d B u f fe r (GL_ARRAY_BUFFER, _p o s i t i o n B u f f e r ) ; g l V e r t e x A t t r i b P o i n t e r ( 0,3,GL_FLOAT, GL_FALSE, 0, 0 ) ; glenablevertexattribarray ( 0 ) ; glbindvertexarray ( 0 ) ; / / par pr é caution ( e f f e t de bord ) glvertexattribpointer : associe l attribut numéro 0 du shader qui sera actif lors du tracé (sur notre exemple il s agit la variable position : cf glbindattriblocation de l initialisation du shader) au buffer ARRAY_BUFFER. Les données d un buffer n ont aucune interprétation : il faut donc préciser combien de composantes il faut prendre et de quel type pour l attribut 0 (ici 3 float (x, y, z) pour chaque sommet). GL_FALSE, 0, 0 : paramètres vus plus tard en TP. glenablevertexattribarray(0) : indique que l attribut numéro 0 du shader actif lors du tracé doit être alimenté par un ARRAY_BUFFER (par défaut, ils sont aliméntés par des valeurs constantes). F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 22 / 60

Tracé OpenGL void GLApplication : : i n i t i a l i z e ( ) { / / appelée 1 seule fois à l initialisation du contexte / / => i n i t i a l i s a t i o n s OpenGL glclearcolor ( 1, 1, 1, 1 ) ; initprogramshader ( ) ; initvbo ( ) ; initvao ( ) ; void GLApplication : : draw ( ) { / / appelée après chaque update / / => tracer toute l image g l C l e a r (GL_COLOR_BUFFER_BIT ) ; gluseprogram ( _program ) ; glbindvertexarray ( _vao ) ; gldrawarrays (GL_TRIANGLES, 0, 6 ) ; gluseprogram ( 0 ) ; glbindvertexarray ( 0 ) ; F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 23 / 60

Résumé Les données sont gérées par l application (sur cet exemple, le tableau des coordonnées des triangles). Généralement les données (i.e. les modèles) sont plus complexes qu un simple tableau : prévoir une phase de copie/transformation dans un tableau pour pouvoir ensuite copier dans les buffers OpenGL. Démarche : Initialiser : Program Shader (inclut un Vertex Shader et un Fragment Shader) : compiler/linker les shaders (souvent fait une fois pour toute à l initialisation). VBO : copier les données de l application (positions, couleurs, etc des sommets) dans des buffers OpenGL (peut être dynamique avec une mise à jour de ces buffers). VAO : indiquer quel VBO alimentera chaque attribut des shaders (généralement fait une fois pour toute à l initialisation). Pour tracer : Activer un Shader (inclut un Vertex et un Fragment Shaders) Activer un VAO (associe pour chaque attribut du Vertex Shader un VBO) Faire un (ou plusieurs) gldraw (parcourt les VBO dans l ordre : 3 premiers sommets = premier triangle ; 3 sommets suivans = second triangle ; etc). F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 24 / 60

Résumé "Lourd"? la démarche devient rapidement systématique (quasi du copier-coller pour chaque VAO, VBO et aisé à abstraire ; 2/3 shaders pour une application simple). beaucoup de framework allègent la gestion des shaders (lecture du code source depuis des fichiers, puis compilation/link en une méthode), des VBO, et des VAO (avec, souvent, le risque de réduire leur richesse/liberté). comprendre l intérêt : lors d un gldrawarrays(gl_triangles,0,1500000) le cpu ne fait rien (tout est assuré par la carte graphique). souplesse de programmation des vertex/fragment shaders. https ://www.shadertoy.com/ F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 25 / 60

3 Paramétrisation des shaders (uniform) F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 26 / 60

Objectif Changer la couleur dans le fragment shader? (pas très dynamique...) # version 130 out vec4 fragcolor ; / / s o r t i e = données du p i x e l void main ( ) { fragcolor=vec4 ( 0, 1, 0, 1 ) ; / / rouge, vert, bleu, alpha F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 27 / 60

Uniform Fragment shader : # version 130 uniform vec4 color ; out vec4 fragcolor ; void main ( ) { fragcolor=color ; on affecte la couleur depuis l application : void GLApplication : : draw ( ) { g l C l e a r (GL_COLOR_BUFFER_BIT ) ; gluseprogram ( _program ) ; GLint locationcolor=glgetuniformlocation ( _program, " color " ) ; gluniform4f ( l o c a t i o n C o l o r, 0, 1, 0, 1 ) ; / / t o u t e valeur c a l c u l ée ou non glbindvertexarray ( _vao ) ; gldrawarrays (GL_TRIANGLES, 0, 6 ) ; gluseprogram ( 0 ) ; glbindvertexarray ( 0 ) ; Un uniform reste constant pendant tout le gldrawarrays (mais peut, bien sûr, être modifié entre 2 gldrawarrays par l application...) F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 28 / 60

4 Communication vertex/fragment shaders (varying) F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 29 / 60

Objectif Il y a un attribut supplémentaire à chaque sommet (une couleur en plus de la position). En chaque pixel la couleur est interpolée (i.e. "moyenne pondérée"). F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 30 / 60

Vertex/Fragment Vertex : # version 130 in vec3 position ; / / attribut (x, y, z ) in vec4 color ; / / attribut ( r, v,b,a ) out vec4 fcolor ; / / varying : out pour vertex, in pour fragment void main ( ) { fcolor = color ; gl_position=vec4 ( position, 1. 0 ) ; Fragment : # version 130 in vec4 fcolor ; / / c a l c u l ée par i n t e r p o l a t i o n des valeurs a f f e c t ées / / dans l e v e r t e x shader ( varying ) out vec4 fragcolor ; void main ( ) { fragcolor=fcolor ; fcolor est affecté dans le vertex shader (exécuté pour chaque sommet du triangle tracé). fcolor est "récupéré" dans le fragment shader (exécuté pour chaque pixel du triangle tracé) : la valeur récupérée est calculée par interpolation par OpenGL. C est la "moyenne pondérée" (selon la position du pixel) des 3 fcolor calculés aux sommets du triangle. F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 31 / 60

Interpolation Bien comprendre le processus : la couleur fcolor est affectée uniquement aux sommets par le vertex shader (pour un triangle = 3 valeurs). lors de la rasterization (remplissage pixel par pixel), chaque fragment (triangle de 500 pixels = 500 exécutions du fragment shader) récupère une valeur fcolor calculée (par interpolation). ces variables calculées entre le vertex shader (avec out) et le fragment shader (avec in) sont souvent appelées varying (ancienne syntaxe). F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 32 / 60

Interpolation linéaire M = (1 λ)v 0 + λv 1 (avec λ [0,1]) Interpoler linéairement la valeur f entre V 0 et V 1 signifie qu on considère que f varie linéairement entre V 0 et V 1 (la variation est constante entre f(v 0 ) et f(v 1 )). f(m) = (1 λ)f(v 0 ) + λf(v 1 ) Remarque : calcul de λ connaissant V 0, V 1 et M? F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 33 / 60

Interpolation bilinéaire (triangle) Interpolation linéaire sur [V2 V 0 ] : M 1 = (1 λ 1 )V 2 + λ 1 V 0 f(m 1 ) = (1 λ 1 )f(v 2 ) + λ 1 f(v 0 ) Interpolation linéaire sur [V2 V 1 ] : M 2 = (1 λ 2 )V 2 + λ 2 V 1 f(m 2 ) = (1 λ 2 )f(v 2 ) + λ 2 f(v 1 ) Interpolation linéaire sur [M1,M 2 ] : M = (1 λ)m 1 + λm 2 f(m) = (1 λ)f(m 1 ) + λf(m 2 ) Remarques : «en dessous»de V0, il faut poursuivre le calcul sur M 1 avec les sommets V 0 et V 1. Toute valeur varying sera calculée ainsi avant l exécution d un fragment shader (dans le principe ; le calcul exact est à nuancer avec la correction de perspective qui sera vue plus tard). Appliquée à la couleur, cette interpolation est appelée interpolation de Gouraud (ou «lissage»de Gouraud = Gouraud Shading). F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 34 / 60

Couleurs des sommets dans VBO Il faut spécifier la couleur en chaque sommet (en plus des coordonnées) : GLApplication : : GLApplication ( ) { _positiondata ={ 0.8,0.0, 0.3, / / vertex 0 / / f i r s t triangle 0.3, 0.7, 0.3, / / v e r t e x 1 0.0,0.9, 0.3, / / v e r t e x 2 0.4, 0.5,0.4, / / v e r t e x 3 / / second t r i a n g l e 0. 9, 0. 4, 0. 4, / / v e r t e x 4 0.8, 0.9,0.4 / / v e r t e x 5 ; _colordata = { 1. 0, 0. 0, 0. 0, 1. 0, / / color 0 / / f i r s t triangle 0. 0, 1. 0, 0. 0, 1. 0, / / c o l o r 1 0. 0, 0. 0, 1. 0, 1. 0, / / c o l o r 2 0. 5, 0. 8, 0. 2, 1. 0, / / c o l o r 3 / / second t r i a n g l e 0. 8, 0. 1, 0. 0, 1. 0, 0. 1, 0. 7, 0. 8, 1. 0 ; void GLApplication : : initvbo ( ) { glgenbuffers (1,& _positionbuffer ) ; g l Bi n d B u f fe r (GL_ARRAY_BUFFER, _p o s i t i o n B u f f e r ) ; glbufferdata (GL_ARRAY_BUFFER, _positiondata. size () s i z e o f ( f l o a t ), _positiondata. data ( ),GL_STATIC_DRAW ) ; glgenbuffers (1,& _colorbuffer ) ; g l Bi n d B u f fe r (GL_ARRAY_BUFFER, _c o l o r B u f f e r ) ; glbufferdata (GL_ARRAY_BUFFER, _colordata. size () s i z e o f ( f l o a t ), _colordata. data ( ),GL_STATIC_DRAW ) ; F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 35 / 60

Modifications VAO Ne pas oublier de faire la correspondance numéro d attribut/nom de l attribut lors de l initialisation du program shader : void GLApplication : : initprogramshader ( ) { / /... read, compile, l i n k shader / /... glbindattriblocation ( _program,0, " position " ) ; glbindattriblocation ( _program,1, " couleur " ) ; gllinkprogram ( _program ) ; Faire la correspondance numéro d attribut/vbo dans le VAO : void GLApplication : : initvao ( ) { glgenvertexarrays (1,& _vao ) ; glbindvertexarray ( _vao ) ; / / p o s i t i o n = a t t r i b u t e 0 g l B in d B u f fe r (GL_ARRAY_BUFFER, _p o s i t i o n B u f f e r ) ; g l V e r t e x A t t r i b P o i n t e r ( 0, 3,GL_FLOAT, GL_FALSE, 0, 0 ) ; / / c o l o r = a t t r i b u t e 1 g l B in d B u f fe r (GL_ARRAY_BUFFER, _c o l o r B u f f e r ) ; g l V e r t e x A t t r i b P o i n t e r ( 1, 4,GL_FLOAT, GL_FALSE, 0, 0 ) ; glenablevertexattribarray ( 0 ) ; glenablevertexattribarray ( 1 ) ; glbindvertexarray ( 0 ) ; F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 36 / 60

Exercice On souhaite : Plusieurs solutions (2 gldraw avec uniform, 1 gldraw avec attributs). F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 37 / 60

Exercice On dispose de : _positiondata = {V0,V1,V2,V3,V4,V5,V6,V7 ; (pseudo code : comprendre un tableau de f l o a t {x0, y0, z0, x1, y1, z1,... etc ). On souhaite : Remarque : ordre des sommets et un sommet en commun. F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 38 / 60

Indexed Face Set On peut donner d une part les sommets, et d autre part comment ils sont reliés pour former les triangles (en donnant la succession des indices des sommets). GLApplication : : GLApplication ( ) {... _indexdata = { 2, 0, 5, 1, 4, 3, 7, 3, 6 ; / / i n d i c e s des sommets ( i n d i r e c t i o n dans l e s b u f f e r s )... void GLApplication : : initvbo ( ) { / /... c f initvbo pr écédent glgenbuffers (1,& _indexbuffer ) ; / / A t t e n t i o n à l a c i b l e du Bind et de l a copie!!! g l Bi n d B u f fe r (GL_ELEMENT_ARRAY_BUFFER, _indexbuffer ) ; glbufferdata (GL_ELEMENT_ARRAY_BUFFER, _indexdata. size () sizeof ( unsigned int ), _indexdata. data ( ),GL_STATIC_DRAW ) ; void GLApplication : : initvao ( ) { glgenvertexarrays (1,& _vao ) ; glbindvertexarray ( _vao ) ; / /... c f VAO pr écédent / / A t t e n t i o n à l a c i b l e g l Bi n d B u f fe r (GL_ELEMENT_ARRAY_BUFFER, _indexbuffer ) ; glbindvertexarray ( 0 ) ; void GLApplication : : draw ( ) { / /... c f draw pr écédent glbindvertexarray ( _vao ) ; / / 9 indices à prendre ( i.e. 9 r é f érences à des sommets = 3 t r i a n g l e s ) gldrawelements (GL_TRIANGLES,9,GL_UNSIGNED_INT, 0 ) ; / /... F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 39 / 60

Exercice On souhaite : gldrawarrays(gl_triangle_strip,...) On souhaite : F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 40 / 60

Exercice anneau on peut ("bien sûr") faire gldrawelements avec GL_TRIANGLE_STRIP. _positiondata ={V0,V1,V2,V3,V4,V5,V6,V7 ; _elementdata = { 0, 1, 2, 3, 4, 5, 6, 7, 0, 1 ;... gldrawelements (GL_TRIANGLE_STRIP,10,GL_UNSIGNED_INT, 0 ) ;... Est-ce qu il faut préférer la redondance des sommets à la fin (gldrawarrays(gl_triangle_strip,...) ou faire un index (gldrawelements(gl_triangle_strip,...))?? Le GL_TRIANGLE_STRIP peut demander un gros effort d organisation des triangles (ordre des sommets, découpage, etc) : pas si souvent utilisé que ça en pratique. F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 41 / 60

Exercice F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 42 / 60

Exercice (tracé avec glpolygonmode(gl_front_and_back,gl_fill)) _positiondata. c l e a r ( ) ; _positiondata. push_back (0.0); _positiondata. push_back (0.0); _positiondata. push_back (0.0); i n t nbslice =100; f l o a t steptheta =2.0 3.14159/ nbslice ; f l o a t t h e t a =0.0; double x, y, z =0; for ( i n t i =0; i <nbslice ; i ++) { x=0.5 cos ( theta ) ; y=0.5 s i n ( t h e t a ) ; _positiondata. push_back (x ) ; _positiondata. push_back (y ) ; _positiondata. push_back (z ) ; t h e t a +=steptheta ; _positiondata. push_back (0.5); _positiondata. push_back (0.0); _positiondata. push_back (0.0); (tracé avec glpolygonmode(gl_front_and_back,gl_line)) F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 43 / 60

Sommet = tous ses attributs _positiondata ={ V0, V1, V2, V3 ; _colordata= { rouge, vert, rouge, bleu ; / / pseudo code _indexdata = { 0, 1, 2, 0, 2, 3 ;... gldrawelements (GL_TRIANGLES,6,GL_UNSIGNED_INT, 0 ) ; Remarque : non tracé en GL_TRIANGLE_STRIP pour comparer à l illustration suivante. _positiondata ={ V0, V1, V2, V3, V4, V5 ; _colordata= { rouge, vert, rouge, bleu, vert, bleu ; / / pseudo code _indexdata = { 0, 1, 2, 4, 5, 3 ;... gldrawelements (GL_TRIANGLES,6,GL_UNSIGNED_INT, 0 ) ; V4 = V0 et V5 = V2 : V0 et V2 doivent être dupliqués car ils n ont pas la même couleur (il n y a qu un seul ELEMENT_ARRAY_BUFFER : chaque indice concerne tous les attributs). 1 sommet = tous ses attributs F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 44 / 60

5 Texture F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 45 / 60

Résultat F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 46 / 60

Texture Texture = "données" (ici une image : chaque élément est un triplet (rouge,vert,bleu)) Chaque élément = texel (analogie avec pixel). Les texels sont localisés par des coordonnées (s, t) normalisées ( [0, 1]). F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 47 / 60

Coordonnées de textures _positiondata ={ 0.8,0.0, 0.3, / / vertex 0 / / f i r s t t r i a n g l e 0.3, 0.7, 0.3, / / vertex 1 0.0,0.9, 0.3, / / vertex 2 0.4, 0.5,0.4, / / vertex 3 / / second t r i a n g l e 0. 9, 0. 4, 0. 4, / / vertex 4 0.8, 0.9,0.4 / / vertex 5 ; _texcoorddata ={ 0. 2, 0. 3, / / texcoord f o r V0 0. 6, 0. 2, / / texcoord f o r V1 0. 1, 0. 9, / / texcoord f o r V2 0. 7, 0. 7, / / texcoord f o r V3 0. 9, 0. 1, / / texcoord f o r V4 0. 9, 0. 7 / / texcoord f o r V5 ; A chaque sommet on indique les coordonnées de texture (attribut). Pour ce résultat : les coordonnées de texture seront interpolées lors de la rasterization (varying). on affecte la couleur du pixel (fragment shader) avec la couleur du texel qui se trouve à ces coordonnées de texture. F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 48 / 60

Texture Object void GLApplication : : inittexture ( ) { / / load image ( image loader l i b r a r y r e q u i r ed... ) QImage img ; img. load ( ".. / media / lagoon. jpg " ) ; img=img. converttoformat (QImage : : Format_ARGB32 ). mirrored ( ) ; / / Qt Image (0,0) is left top => mirrored / / t e x t u r e Object ( t a r g e t GL_TEXTURE_2D) glgentextures (1,& _textureid ) ; glbindtexture (GL_TEXTURE_2D, _textureid ) ; glteximage2d (GL_TEXTURE_2D,0,GL_RGBA, img. width ( ), img. height ( ),0,GL_BGRA,GL_UNSIGNED_BYTE, img. b i t s ( ) ) ; gltexparameterf (GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR ) ; gltexparameterf (GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR ) ; gltexparameterf (GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT ) ; gltexparameterf (GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT ) ; F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 49 / 60

VBO/VAO Idem que les positions, couleurs,... void GLApplication : : i n i t B u f f e r ( ) {... glgenbuffers (1,& _texcoordbuffer ) ; g l Bi n d B u f fe r (GL_ARRAY_BUFFER, _texcoordbuffer ) ; glbufferdata (GL_ARRAY_BUFFER, _texcoorddata. size () sizeof ( f l o a t ), _texcoorddata. data ( ),GL_STATIC_DRAW ) ;... void GLApplication : : initvao ( ) { glgenvertexarrays (1,& _vao ) ; glbindvertexarray ( _vao ) ; / / p o s i t i o n = a t t r i b u t e 0 g l Bi n d B u f fe r (GL_ARRAY_BUFFER, _p o s i t i o n B u f f e r ) ; g l V e r t e x A t t r i b P o i n t e r ( 0,3,GL_FLOAT, GL_FALSE, 0, 0 ) ; / / texcoord = a t t r i b u t e 1 g l Bi n d B u f fe r (GL_ARRAY_BUFFER, _texcoordbuffer ) ; g l V e r t e x A t t r i b P o i n t e r ( 1,2,GL_FLOAT, GL_FALSE, 0, 0 ) ; glenablevertexattribarray ( 0 ) ; glenablevertexattribarray ( 1 ) ; glbindvertexarray ( 0 ) ; F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 50 / 60

Shaders Coordonnées de textures aux sommets = attributs (comme les autres données aux sommets) La texture elle-même (l ensemble des texels) = uniform de type sampler2d Vertex shader : # version 130 in vec3 position ; / / attribut (x, y, z ) in vec2 texcoord ; / / attribut (s, t ) out vec2 ftexcoord ; / / out pour vertex, in pour fragment void main ( ) { ftexcoord = texcoord ; gl_position=vec4 ( position, 1. 0 ) ; Fragment : # version 130 uniform sampler2d texunit ; in vec2 ftexcoord ; out vec4 fragcolor ; void main ( ) { fragcolor=texture2d ( texunit, ftexcoord ) ; F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 51 / 60

Unité de texture # version 130 uniform sampler2d texunit ; in vec2 ftexcoord ; out vec4 fragcolor ; void main ( ) { fragcolor=texture2d ( texunit, ftexcoord ) ; Attention : texunit ne sera pas affecté avec un identifiant de texture (i.e. _textureid dans l exemple) mais avec une unité de texture (i.e. nombre entre 0 et 7). Il faut donc préciser quelle identifiant de texture est affectée à l unité de texture souhaitée. void GLApplication : : draw ( ) { / / appelée après chaque update / / => tracer toute l image g l C l e a r (GL_COLOR_BUFFER_BIT ) ; gluseprogram ( _program ) ; glactivetexture (GL_TEXTURE0 ) ; glbindtexture (GL_TEXTURE_2D, _textureid ) ; i n t locationtexunit=glgetuniformlocation ( _program. id ( ), " texunit " ) ; gluniform1i ( locationtexunit, 0 ) ; glbindvertexarray ( _vao ) ; gldrawarrays (GL_TRIANGLES, 0, 6 ) ; gluseprogram ( 0 ) ; glbindvertexarray ( 0 ) ; F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 52 / 60

6 Normalized Device Coordinates et Window Coordinates F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 53 / 60

Volume de visualisation Les coordonnées (x, y, z) des sommets visibles sont dans [ 1, 1] : définit le volume de visualisation en Normalized Device Coordinates (NDC). Des sommets extérieurs à ce volume provoquent une opération de clipping par OpenGL (découpage des triangles). _positiondata ={ 1.3,0.0, 0.3, / / v e r t e x 0 / / f i r s t t r i a n g l e 0.3, 0.7, 0.3, / / v e r t e x 1 0.0,0.9, 0.3, / / v e r t e x 2 0.4, 0.5,0.4, / / v e r t e x 3 / / second t r i a n g l e 1. 5, 0. 4, 0. 4, / / v e r t e x 4 0.8, 1.3,0.4 / / v e r t e x 5 ; F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 54 / 60

Clipping _positiondata ={ 1.3,0.0, 0.3, / / vertex 0 / / f i r s t t r i a n g l e 0.3, 0.7, 0.3, / / vertex 1 0.0,0.9, 1.3, / / vertex 2 0.4, 0.5,0.4, / / vertex 3 / / second t r i a n g l e 1. 5, 0. 4, 0. 4, / / vertex 4 0.8, 1.3,0.4 / / vertex 5 ; F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 55 / 60

Viewport et Window Coordinates Lors de la rasterization (tracé pixel par pixel) sur la fenêtre graphique, OpenGL trace des pixels dont les coordonnées doivent être connues en coordonnées de la fenêtre graphique (par exemple reporter sur une fenêtre graphique de 256x512 pixels) : C est le rôle du glviewport(xv,yv,width,height). Par exemple, pour glviewport(10,20,256,512), reporte x NDC [ 1,1],y NDC [ 1,1] dans x window [10,266],y window [20,532]. Les coordonnées pixels (i.e. transformation par le viewport) sont appelées Window Coordinates. Remarque : le z NDC [ 1,1] subit également un report pour obtenir z window dans [0,1] (indépendant du viewport). z window est généralement appelé depth (profondeur) et nous verrons son utilisation dans le chapitre suivant. x window = (1 + x NDC ) width 2 + xv y window = (1 + y NDC ) height 2 + yv z window = (1 + z NDC )/2.0 Remarque : les window coordinates sont accessibles dans le fragment shader par la variable prédéfinie gl_fragcoord (gl_fragcoord.z contenant la profondeur). F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 56 / 60

7 Quelques remarques pour finir... F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 57 / 60

Copie buffer Si la valeur des attributs est dynamique (modifications de la position des sommets par exemple), on utilisera glsubbufferdata pour mettre à jour les buffers (glbufferdata détruit/réalloue à chaque appel). F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 58 / 60

Buffer entrelacé Buffer entrelacé : / / c l i e n t data _ a l l D a t a ={ 1,1,0, 1,0,0,1, 1, 1,0, 0,1,0,1, 1,1,0, 0,0,1,1, 1, 1,0, 1, 1, 0, 1 ; / / i n i t b u f f e r glgenbuffers (1,& _allbuffer ) ; g l B in d B u f fe r (GL_ARRAY_BUFFER, _a l l B u f f e r ) ; glbufferdata (GL_ARRAY_BUFFER, _alldata. size () s i z e o f ( f l o a t ), _alldata. data ( ),GL_STATIC_DRAW ) ; / / vao g l B in d B u f fe r (GL_ARRAY_BUFFER, _a l l B u f f e r ) ; glvertexattribpointer (0,3,GL_FLOAT,GL_FALSE, sizeof ( f l o a t ) 7,0); glvertexattribpointer (1,4,GL_FLOAT,GL_FALSE, sizeof ( float ) 7,(void )(3 sizeof ( float ) ) ) ; F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 59 / 60

Primitives de tracé GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP, GL_POINTS (+ versions _ADJACENCY, GL_PATCHES). F. Aubert (MS2) M3DS/ 1 - Introduction - Programmation 3D 2014-2015 60 / 60