gKit2 light
tuto4GL_normals.cpp
Go to the documentation of this file.
1 
7 #include "window.h"
8 #include "vec.h"
9 #include "mat.h"
10 
11 #include "program.h"
12 #include "uniforms.h"
13 
14 #include "orbiter.h"
15 #include "mesh.h"
16 #include "wavefront.h"
17 
18 #include <stdio.h>
19 
20 // shader program
21 GLuint program;
22 
23 // vertex array object
24 GLuint vao;
25 GLuint vertex_buffer;
26 GLuint normal_buffer;
27 unsigned int vertex_count;
28 
29 // camera
30 Orbiter camera;
31 
32 
33 int init( )
34 {
35  // compile un shader program
36  program= read_program("tutos/tuto4GL_normals.glsl");
37  program_print_errors(program);
38 
39  // charge un objet
40  Mesh mesh= read_mesh("data/bigguy.obj");
41  vertex_count= mesh.vertex_count();
42 
43  // camera
44  Point pmin, pmax;
45  mesh.bounds(pmin, pmax);
46 
47  camera.lookat(pmin, pmax);
48 
49  glGenBuffers(1, &vertex_buffer);
50  glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
51 
52  // dimensionne le buffer actif sur array_buffer, l'alloue et l'initialise avec les positions des sommets de l'objet
53  glBufferData(GL_ARRAY_BUFFER,
54  /* length */ mesh.vertex_buffer_size(),
55  /* data */ mesh.vertex_buffer(),
56  /* usage */ GL_STATIC_DRAW);
57  // GL_STATIC_DRAW decrit l'utilisation du contenu du buffer. dans ce cas, utilisation par draw, sans modifications
58 
59  // on recommence avec les normales
60  glGenBuffers(1, &normal_buffer);
61  glBindBuffer(GL_ARRAY_BUFFER, normal_buffer);
62  glBufferData(GL_ARRAY_BUFFER, mesh.normal_buffer_size(), mesh.normal_buffer(), GL_STATIC_DRAW);
63 
64 /* attention: c'est normal_buffer qui est selectionne maintenant sur array_buffer, plus vertex_buffer...
65  */
66 
67  // creation d'un vertex array object
68  glGenVertexArrays(1, &vao);
69  glBindVertexArray(vao);
70 
71  // recuperer l'identifiant de l'attribut : cf in vec3 position; dans le vertex shader
72  GLint attribute= glGetAttribLocation(program, "position");
73  if(attribute < 0)
74  return -1;
75 
76  // re-selectionne vertex buffer pour configurer les positions
77  glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
78  // format et organisation des donnees dans le vertex buffer selectionne sur array_buffer,
79  glVertexAttribPointer(attribute, 3, GL_FLOAT, GL_FALSE, /* stride */ 0, /* offset */ 0);
80  glEnableVertexAttribArray(attribute);
81 
82  // on recommence pour les normales
83  attribute= glGetAttribLocation(program, "normal");
84  if(attribute < 0)
85  return -1;
86 
87  // re-selectionne normal_buffer pour configurer les normales
88  glBindBuffer(GL_ARRAY_BUFFER, normal_buffer);
89  glVertexAttribPointer(attribute, 3, GL_FLOAT, GL_FALSE, /* stride */ 0, /* offset */ 0); // in vec3 normal;
90  glEnableVertexAttribArray(attribute);
91 
92 /* autre solution pour le meme resultat :
93 
94  #include "buffer.h"
95 
96  GLuint vao= make_vertex_format();
97 
98  vertex_buffer= make_vertex_buffer(vao, glGetAttribLocation(program, "position"), 3, GL_FLOAT, mesh.vertex_buffer_size(), mesh.vertex_buffer());
99  normal_buffer= make_vertex_buffer(vao, glGetAttribLocation(program, "normal"), 3, GL_FLOAT, mesh.normal_buffer_size(), mesh.normal_buffer());
100  */
101 
102 
103 /* creer 2 buffers pour ranger les positions et les normales est arbitraire, on peut tres bien ne creer qu'un seul buffer,
104  par contre, la description du format / de l'organisation sera differente...
105  ce sont les parametres stride et offset de glVertexAttribPointer() qui permettent d'organiser les donnees librement,
106  ils permettent d'iterer sur les donnees, offset definit le premier element et stride permet de passer au suivant.
107 
108  exemple 1: un seul buffer, toutes les positions, puis toutes les normales
109 
110  PPPPPPPPNNNNNNNN
111 
112  offset(position)= 0;
113  stride(position)= 0; // par definition stride(position) == sizeof(vec3)
114 
115  offset(normal)= sizeof(vec3) * size(positions);
116  stride(normal)= 0; // ou sizeof(vec3)
117 
118  exemple 2: un seul buffer, alterner les donnees, position + normale sommet 0, position + normale sommet 1, etc.
119 
120  PNPNPNPNPNPNPN
121 
122  offset(position)= 0;
123  stride(position)= sizeof(vec3) + sizeof(vec3); // la prochaine position se trouve apres la normale du sommet
124 
125  offset(normal)= sizeof(vec3); // la premiere normale se trouve apres la premiere position
126  stride(normal)= sizeof(vec3) + sizeof(vec3);
127 
128  exemple 3: et pour normale suivie de position ?
129 
130  NPNPNPNPNPNPNPNP
131 
132  */
133 
134  // nettoyage
135  glBindVertexArray(0);
136  glBindBuffer(GL_ARRAY_BUFFER, 0);
137 
138  // etat par defaut openGL
139  glClearColor(0.2f, 0.2f, 0.2f, 1);
140  glClearDepthf(1);
141 
142  glDepthFunc(GL_LESS);
143  glEnable(GL_DEPTH_TEST);
144 
145  glEnable(GL_CULL_FACE);
146  // glViewport(0, 0, window_width(), window_height()) // deja fait dans run( )
147  return 0;
148 }
149 
150 int quit( )
151 {
152  release_program(program);
153  glDeleteBuffers(1, &vertex_buffer);
154  glDeleteVertexArrays(1, &vao);
155  return 0;
156 }
157 
158 int draw( )
159 {
160  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
161 
162  // todo recuperez les mouvements de la souris pour deplacer la camera, cf tutos/tuto6.cpp
163  // recupere les mouvements de la souris, utilise directement SDL2
164  int mx, my;
165  unsigned int mb= SDL_GetRelativeMouseState(&mx, &my);
166 
167  // deplace la camera
168  if(mb & SDL_BUTTON(1)) // le bouton gauche est enfonce
169  // tourne autour de l'objet
170  camera.rotation(mx, my);
171 
172  else if(mb & SDL_BUTTON(3)) // le bouton droit est enfonce
173  // approche / eloigne l'objet
174  camera.move(mx);
175 
176  else if(mb & SDL_BUTTON(2)) // le bouton du milieu est enfonce
177  // deplace le point de rotation
178  camera.translation((float) mx / (float) window_width(), (float) my / (float) window_height());
179 
180 
181 /* configuration minimale du pipeline
182  vertex array
183  shader program
184  uniforms du shader program
185  */
186  glBindVertexArray(vao);
187 
188  glUseProgram(program);
189 
190  // recupere le point de vue et la projection de la camera
191  Transform model= Identity();
192  Transform view= camera.view();
193  Transform projection= camera.projection(window_width(), window_height(), 45);
194 
195  // compose les matrices pour passer du repere local de l'objet au repere projectif
196  Transform mvp= projection * view * model;
197  Transform mv= view * model;
198 
199  GLuint location;
200  location= glGetUniformLocation(program, "mvpMatrix");
201  glUniformMatrix4fv(location, 1, GL_TRUE, mvp.buffer());
202 
203  // les normales ne subissent pas tout a fait la meme transformation que les sommets
204  program_uniform(program, "mvMatrix", mv.normal());
205 
206  program_uniform(program, "color", vec3(1, 0.5, 0.));
207 
208  glDrawArrays(GL_TRIANGLES, 0, vertex_count);
209 
210  // nettoyage
211  glUseProgram(0);
212  glBindVertexArray(0);
213  return 1;
214 }
215 
216 
217 int main( int argc, char **argv )
218 {
219  // etape 1 : creer la fenetre
220  Window window= create_window(1024, 640);
221  if(window == NULL)
222  return 1; // erreur lors de la creation de la fenetre ou de l'init de sdl2
223 
224  // etape 2 : creer un contexte opengl pour pouvoir dessiner
225  Context context= create_context(window);
226  if(context == NULL)
227  return 1; // erreur lors de la creation du contexte opengl
228 
229  // etape 3 : creation des objets
230  if(init() < 0)
231  {
232  printf("[error] init failed.\n");
233  return 1;
234  }
235 
236  // etape 4 : affichage de l'application, tant que la fenetre n'est pas fermee. ou que draw() ne renvoie pas 0
237  run(window, draw);
238 
239  // etape 5 : nettoyage
240  quit();
241  release_context(context);
242  release_window(window);
243  return 0;
244 }
Context create_context(Window window, const int major, const int minor)
cree et configure un contexte opengl
Definition: window.cpp:252
const float * normal_buffer() const
renvoie l'adresse de la normale du premier sommet. par convention, la normale est un vec3...
Definition: mesh.h:200
representation de la camera, type orbiter, placee sur une sphere autour du centre de l'objet...
Definition: orbiter.h:16
const float * vertex_buffer() const
renvoie l'adresse de la position du premier sommet. permet de construire les vertex buffers openGL...
Definition: mesh.h:195
void bounds(Point &pmin, Point &pmax)
renvoie min et max les coordonnees des extremites des positions des sommets de l'objet (boite engloba...
Definition: mesh.cpp:153
vecteur generique, utilitaire.
Definition: vec.h:104
Transform normal() const
renvoie la transformation a appliquer aux normales d'un objet transforme par la matrice m...
Definition: mat.cpp:97
std::size_t normal_buffer_size() const
renvoie la longueur (en octets) du normal buffer.
Definition: mesh.h:202
representation d'un objet / maillage.
Definition: mesh.h:88
void move(const float z)
rapproche / eloigne la camera du centre.
Definition: orbiter.cpp:33
Transform Identity()
construit la transformation identite.
Definition: mat.cpp:103
std::size_t vertex_buffer_size() const
renvoie la longueur (en octets) du vertex buffer.
Definition: mesh.h:197
void program_uniform(const GLuint program, const char *uniform, const unsigned int v)
affecte une valeur a un uniform du shader program. uint.
Definition: uniforms.cpp:68
void draw(Mesh &m, const Transform &model, const Transform &view, const Transform &projection, const GLuint texture)
applique une texture a la surface de l'objet. ne fonctionne que si les coordonnees de textures sont f...
Definition: draw.cpp:6
Transform view() const
renvoie la transformation vue.
Definition: orbiter.cpp:40
int window_width()
renvoie la largeur de la fenetre de l'application.
Definition: window.cpp:14
Transform projection(const float width, const float height, const float fov) const
renvoie la projection reglee pour une image d'aspect width / height, et une ouverture de fov degres...
Definition: orbiter.cpp:47
int program_print_errors(const GLuint program)
affiche les erreurs de compilation.
Definition: program.cpp:330
void lookat(const Point &center, const float size)
observe le point center a une distance size.
Definition: orbiter.cpp:7
Window create_window(const int w, const int h)
creation d'une fenetre pour l'application.
Definition: window.cpp:186
GLuint read_program(const char *filename, const char *definitions)
Definition: program.cpp:150
const float * buffer() const
renvoie l'adresse de la premiere valeur de la matrice.
Definition: mat.h:44
void translation(const float x, const float y)
deplace le centre / le point observe.
Definition: orbiter.cpp:27
void printf(Text &text, const int px, const int py, const char *format,...)
affiche un texte a la position x, y. meme utilisation que printf().
Definition: text.cpp:140
void rotation(const float x, const float y)
change le point de vue / la direction d'observation.
Definition: orbiter.cpp:21
int window_height()
renvoie la hauteur de la fenetre de l'application.
Definition: window.cpp:18
representation d'une transformation, une matrice 4x4, organisee par ligne / row major.
Definition: mat.h:20
int release_program(const GLuint program)
detruit les shaders et le program.
Definition: program.cpp:157
void release_context(Context context)
detruit le contexte openGL.
Definition: window.cpp:306
representation d'un point 3d.
Definition: vec.h:19
int vertex_count() const
renvoie le nombre de sommets.
Definition: mesh.h:190
void release_window(Window window)
destruction de la fenetre.
Definition: window.cpp:222
int run(Window window, int(*draw)(void))
fonction principale. gestion des evenements et appel de la fonction draw de l'application.
Mesh read_mesh(const char *filename)
charge un fichier wavefront .obj et renvoie un mesh compose de triangles non indexes. utiliser glDrawArrays pour l'afficher. a detruire avec Mesh::release( ).
Definition: wavefront.cpp:8