gKit2 light
tuto_framebuffer.cpp
Go to the documentation of this file.
1 
3 
4 #include "vec.h"
5 #include "mat.h"
6 
7 #include "mesh.h"
8 #include "wavefront.h"
9 #include "texture.h"
10 
11 #include "program.h"
12 #include "uniforms.h"
13 
14 #include "orbiter.h"
15 #include "app.h" // classe Application a deriver
16 
17 
18 class TPFramebuffer : public App
19 {
20 public:
21  // constructeur : donner les dimensions de l'image, et eventuellement la version d'openGL.
22  TPFramebuffer( ) : App(1024, 640) {}
23 
24  int init( )
25  {
26  m_framebuffer_width= 512;
27  m_framebuffer_height= 512;
28 
29  // etape 1 : creer une texture couleur...
30  glGenTextures(1, &m_color_buffer);
31  glBindTexture(GL_TEXTURE_2D, m_color_buffer);
32 
33  glTexImage2D(GL_TEXTURE_2D, 0,
34  GL_RGBA, m_framebuffer_width, m_framebuffer_height, 0,
35  GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
36 
37  // ... et tous ses mipmaps
38  glGenerateMipmap(GL_TEXTURE_2D);
39 
40  // et son sampler
41  glGenSamplers(1, &color_sampler);
42 
43  glSamplerParameteri(color_sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
44  glSamplerParameteri(color_sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
45  glSamplerParameteri(color_sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
46  glSamplerParameteri(color_sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
47 
48  // etape 1 : creer aussi une texture depth, sinon pas de zbuffer...
49  glGenTextures(1, &m_depth_buffer);
50  glBindTexture(GL_TEXTURE_2D, m_depth_buffer);
51 
52  glTexImage2D(GL_TEXTURE_2D, 0,
53  GL_DEPTH_COMPONENT, m_framebuffer_width, m_framebuffer_height, 0,
54  GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
55 
56  // etape 2 : creer et configurer un framebuffer object
57  glGenFramebuffers(1, &m_framebuffer);
58  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_framebuffer);
59  glFramebufferTexture(GL_DRAW_FRAMEBUFFER, /* attachment */ GL_COLOR_ATTACHMENT0, /* texture */ m_color_buffer, /* mipmap level */ 0);
60  glFramebufferTexture(GL_DRAW_FRAMEBUFFER, /* attachment */ GL_DEPTH_ATTACHMENT, /* texture */ m_depth_buffer, /* mipmap level */ 0);
61 
62  // le fragment shader ne declare qu'une seule sortie, indice 0
63  GLenum buffers[]= { GL_COLOR_ATTACHMENT0 };
64  glDrawBuffers(1, buffers);
65 
66  // nettoyage
67  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
68 
69  // charge un mesh
70  Mesh mesh= read_mesh("data/cube.obj");
71  if(mesh == Mesh::error()) return -1;
72 
73  Point pmin, pmax;
74  mesh.bounds(pmin, pmax);
75  m_camera.lookat(pmin, pmax);
76  m_framebuffer_camera.lookat(pmin, pmax);
77 
78  m_vertex_count= mesh.vertex_count();
79 
80  m_color_texture= read_texture(0, "data/debug2x2red.png");
81 
82  // cree les buffers et le vao
83  glGenVertexArrays(1, &m_vao);
84  glBindVertexArray(m_vao);
85 
86  // buffer : positions + texcoords + normals
87  glGenBuffers(1, &m_buffer);
88  glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
89 
90  size_t size= mesh.vertex_buffer_size() + mesh.texcoord_buffer_size() + mesh.normal_buffer_size();
91  glBufferData(GL_ARRAY_BUFFER, size, nullptr, GL_STATIC_DRAW);
92 
93  // transfere les positions des sommets
94  size_t offset= 0;
95  size= mesh.vertex_buffer_size();
96  glBufferSubData(GL_ARRAY_BUFFER, offset, size, mesh.vertex_buffer());
97  // configure l'attribut 0, vec3 position
98  glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, /* stride */ 0, (const GLvoid *) offset);
99  glEnableVertexAttribArray(0);
100 
101  // transfere les texcoords des sommets
102  offset= offset + size;
103  size= mesh.texcoord_buffer_size();
104  glBufferSubData(GL_ARRAY_BUFFER, offset, size, mesh.texcoord_buffer());
105  // configure l'attribut 1, vec2 texcoord
106  glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, /* stride */ 0, (const GLvoid *) offset);
107  glEnableVertexAttribArray(1);
108 
109  // transfere les normales des sommets
110  offset= offset + size;
111  size= mesh.normal_buffer_size();
112  glBufferSubData(GL_ARRAY_BUFFER, offset, size, mesh.normal_buffer());
113  // configure l'attribut 2, vec3 normal
114  glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, /* stride */ 0, (const GLvoid *) offset);
115  glEnableVertexAttribArray(2);
116 
117  //
118  mesh.release();
119  glBindVertexArray(0);
120  glBindBuffer(GL_ARRAY_BUFFER, 0);
121 
122  // shaders
123  m_texture_program= read_program("tutos/texcoords.glsl");
124  program_print_errors(m_texture_program);
125 
126  // etat openGL par defaut
127  glClearColor(0.2f, 0.2f, 0.2f, 1.f); // couleur par defaut de la fenetre
128 
129  glClearDepthf(1.f); // profondeur par defaut
130  glDepthFunc(GL_LESS); // ztest, conserver l'intersection la plus proche de la camera
131  glEnable(GL_DEPTH_TEST); // activer le ztest
132 
133  return 0; // ras, pas d'erreur
134  }
135 
136  // destruction des objets de l'application
137  int quit( )
138  {
139  glDeleteTextures(1, &m_color_buffer);
140  glDeleteTextures(1, &m_depth_buffer);
141  glDeleteFramebuffers(1, &m_framebuffer);
142  glDeleteSamplers(1, &color_sampler);
143 
144  release_program(m_texture_program);
145  glDeleteTextures(1, &m_color_texture);
146  glDeleteVertexArrays(1, &m_vao);
147  glDeleteBuffers(1, &m_buffer);
148  return 0;
149  }
150 
151  int update( const float time, const float delta )
152  {
153  m_model= RotationY(time / 20);
154  return 0;
155  }
156 
157  // dessiner une nouvelle image
158  int render( )
159  {
160  // deplace la camera
161  int mx, my;
162  unsigned int mb= SDL_GetRelativeMouseState(&mx, &my);
163  if(mb & SDL_BUTTON(1)) // le bouton gauche est enfonce
164  m_camera.rotation(mx, my);
165  else if(mb & SDL_BUTTON(3)) // le bouton droit est enfonce
166  m_camera.move(mx);
167  else if(mb & SDL_BUTTON(2)) // le bouton du milieu est enfonce
168  m_camera.translation((float) mx / (float) window_width(), (float) my / (float) window_height());
169 
170  {
171  /* passe 1 : dessiner dans le framebuffer
172  */
173 
174  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_framebuffer);
175  glViewport(0, 0, m_framebuffer_width, m_framebuffer_height);
176  glClearColor(1, 1, 0, 1);
177  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
178 
179  // draw "classique"
180  glBindVertexArray(m_vao);
181  glUseProgram(m_texture_program);
182 
183  Transform m= m_model;
184  Transform v= m_framebuffer_camera.view();
185  Transform p= m_framebuffer_camera.projection(m_framebuffer_width, m_framebuffer_height, 45);
186  Transform mvp= p * v * m;
187  Transform mv= v * m;
188 
189  program_uniform(m_texture_program, "mvpMatrix", mvp);
190  program_uniform(m_texture_program, "mvMatrix", mv);
191  program_uniform(m_texture_program, "normalMatrix", mv.normal());
192  program_use_texture(m_texture_program, "color_texture", 0, m_color_texture, 0);
193 
194  glDrawArrays(GL_TRIANGLES, 0, m_vertex_count);
195  }
196 
197  if(key_state(' '))
198  {
199  /* montrer le resultat de la passe 1
200  copie le framebuffer sur la fenetre
201  */
202 
203  glBindFramebuffer(GL_READ_FRAMEBUFFER, m_framebuffer);
204  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
205  glViewport(0, 0, window_width(), window_height());
206  glClearColor(0, 0, 0, 1);
207  glClear(GL_COLOR_BUFFER_BIT);
208 
209  glBlitFramebuffer(
210  0, 0, m_framebuffer_width, m_framebuffer_height, // rectangle origine dans READ_FRAMEBUFFER
211  0, 0, m_framebuffer_width, m_framebuffer_height, // rectangle destination dans DRAW_FRAMEBUFFER
212  GL_COLOR_BUFFER_BIT, GL_LINEAR); // ne copier que la couleur (+ interpoler)
213  }
214  else
215  {
216  /* passe 2 : utiliser la texture du framebuffer
217  */
218 
219  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
220  glViewport(0, 0, window_width(), window_height());
221  glClearColor(0.2f, 0.2f, 0.2f, 1.f); // couleur par defaut de la fenetre
222  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
223 
224  // draw "classique"
225  glBindVertexArray(m_vao);
226  glUseProgram(m_texture_program);
227 
228  Transform m= m_model;
229  Transform v= m_camera.view();
230  Transform p= m_camera.projection(window_width(), window_height(), 45);
231  Transform mvp= p * v * m;
232  Transform mv= v * m;
233 
234  program_uniform(m_texture_program, "mvpMatrix", mvp);
235  program_uniform(m_texture_program, "mvMatrix", mv);
236  program_uniform(m_texture_program, "normalMatrix", mv.normal());
237 
238  // utilise la texture attachee au framebuffer
239  program_uniform(m_texture_program, "color_texture", 0); // utilise la texture configuree sur l'unite 0
240 
241  // configure l'unite 0
242  glActiveTexture(GL_TEXTURE0);
243  glBindTexture(GL_TEXTURE_2D, m_color_buffer);
244  glBindSampler(0, color_sampler);
245 
246  // SOIT :
247  // bloque le filtrage de la texture pour n'utiliser que le mipmap 0
248  //~ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
249 
250  // OU :
251  // recalcule les mipmaps de la texture... ils sont necessaires pour afficher le cube texture,
252  // pourquoi ? un draw dans un framebuffer ne modifie que le mipmap 0, pas les autres, donc il faut les recalculer...
253  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, miplevels(m_framebuffer_width, m_framebuffer_height));
254  glGenerateMipmap(GL_TEXTURE_2D);
255 
256  // go
257  glDrawArrays(GL_TRIANGLES, 0, m_vertex_count);
258  }
259 
260  return 1;
261  }
262 
263 protected:
264  Transform m_model;
265  Orbiter m_camera;
266  Orbiter m_framebuffer_camera;
267 
268  GLuint m_vao;
269  GLuint m_buffer;
270  GLuint m_texture_program;
271  int m_vertex_count;
272 
273  GLuint m_color_texture;
274  GLuint color_sampler;
275 
276  GLuint m_color_buffer;
277  GLuint m_depth_buffer;
278  GLuint m_framebuffer;
279  int m_framebuffer_width;
280  int m_framebuffer_height;
281 };
282 
283 
284 int main( int argc, char **argv )
285 {
286  TPFramebuffer tp;
287  tp.run();
288 
289  return 0;
290 }
291 
classe application.
Definition: app.h:20
App(const int width, const int height, const int major=3, const int minor=3, const int samples=0)
constructeur, dimensions de la fenetre et version d'openGL.
Definition: app.cpp:11
int run()
execution de l'application.
Definition: app.cpp:36
representation d'un objet / maillage.
Definition: mesh.h:112
std::size_t texcoord_buffer_size() const
renvoie la taille (en octets) du texcoord buffer.
Definition: mesh.h:308
static Mesh & error()
Definition: mesh.h:348
const float * vertex_buffer() const
renvoie l'adresse de la position du premier sommet. permet de construire les vertex buffers openGL....
Definition: mesh.h:296
void bounds(Point &pmin, Point &pmax) const
renvoie min et max les coordonnees des extremites des positions des sommets de l'objet (boite engloba...
Definition: mesh.cpp:501
std::size_t vertex_buffer_size() const
renvoie la longueur (en octets) du vertex buffer.
Definition: mesh.h:298
const float * texcoord_buffer() const
renvoie l'adresse des coordonnees de textures du premier sommet. par convention, c'est un vec2,...
Definition: mesh.h:306
int vertex_count() const
renvoie le nombre de sommets.
Definition: mesh.h:291
void release()
detruit les objets openGL.
Definition: mesh.cpp:62
std::size_t normal_buffer_size() const
renvoie la longueur (en octets) du normal buffer.
Definition: mesh.h:303
const float * normal_buffer() const
renvoie l'adresse de la normale du premier sommet. par convention, la normale est un vec3,...
Definition: mesh.h:301
representation de la camera, type orbiter, placee sur une sphere autour du centre de l'objet.
Definition: orbiter.h:17
void lookat(const Point &center, const float size)
observe le point center a une distance size.
Definition: orbiter.cpp:7
void move(const float z)
rapproche / eloigne la camera du centre.
Definition: orbiter.cpp:33
Transform projection(const int width, const int height, const float fov)
fixe la projection reglee pour une image d'aspect width / height, et une demi ouverture de fov degres...
Definition: orbiter.cpp:47
void translation(const float x, const float y)
deplace le centre / le point observe.
Definition: orbiter.cpp:27
void rotation(const float x, const float y)
change le point de vue / la direction d'observation.
Definition: orbiter.cpp:21
Transform view() const
renvoie la transformation vue.
Definition: orbiter.cpp:40
int render()
a deriver pour afficher les objets. renvoie 1 pour continuer, 0 pour fermer l'application.
int update(const float time, const float delta)
a deriver et redefinir pour animer les objets en fonction du temps.
int init()
a deriver pour creer les objets openGL. renvoie -1 pour indiquer une erreur, 0 sinon.
int quit()
a deriver pour detruire les objets openGL. renvoie -1 pour indiquer une erreur, 0 sinon.
int window_height()
renvoie la hauteur de la fenetre de l'application.
Definition: window.cpp:29
int key_state(const SDL_Keycode key)
renvoie l'etat d'une touche du clavier. cf la doc SDL2 pour les codes.
Definition: window.cpp:42
int window_width()
renvoie la largeur de la fenetre de l'application.
Definition: window.cpp:25
Transform RotationY(const float a)
renvoie la matrice representation une rotation de a degree autour de l'axe Y.
Definition: mat.cpp:242
Mesh read_mesh(const char *filename)
charge un fichier wavefront .obj et renvoie un mesh compose de triangles non indexes....
Definition: wavefront.cpp:14
GLuint read_program(const char *filename, const char *definitions)
Definition: program.cpp:204
void program_uniform(const GLuint program, const char *uniform, const std::vector< unsigned > &v)
affecte un tableau de valeurs a un uniform du shader program.
Definition: uniforms.cpp:94
int program_print_errors(const GLuint program)
affiche les erreurs de compilation.
Definition: program.cpp:432
int release_program(const GLuint program)
detruit les shaders et le program.
Definition: program.cpp:211
void program_use_texture(const GLuint program, const char *uniform, const int unit, const GLuint texture, const GLuint sampler)
configure le pipeline et le shader program pour utiliser une texture, et des parametres de filtrage,...
Definition: uniforms.cpp:198
GLuint read_texture(const int unit, const char *filename, const GLenum texel_type)
Definition: texture.cpp:154
int miplevels(const int width, const int height)
renvoie le nombre de mipmap d'une image width x height.
Definition: texture.cpp:10
MeshBuffer buffers(const MeshData &data)
construction a partir des donnees d'un maillage.
Definition: mesh_buffer.cpp:48
representation d'un point 3d.
Definition: vec.h:21
representation d'une transformation, une matrice 4x4, organisee par ligne / row major.
Definition: mat.h:21
Transform normal() const
renvoie la transformation a appliquer aux normales d'un objet transforme par la matrice m.
Definition: mat.cpp:181