gKit2 light
Loading...
Searching...
No Matches
vertices.cpp
1
2#include <algorithm>
3#include <random>
4
5#include "mat.h"
6#include "mesh.h"
7#include "wavefront.h"
8#include "wavefront_fast.h"
9#include "gltf.h"
10
11#include "orbiter.h"
12#include "program.h"
13#include "uniforms.h"
14#include "texture.h"
15#include "draw.h"
16
17#include "app_time.h" // classe Application a deriver
18#include "app_camera.h"
19
20// oui c'est moche...
21#include "M2/meshoptimizer/meshoptimizer.h"
22#include "M2/meshoptimizer/indexanalyzer.cpp"
23#include "M2/meshoptimizer/vcacheoptimizer.cpp"
24#include "M2/meshoptimizer/vfetchoptimizer.cpp"
25
26
27void vcache( const Mesh& mesh )
28{
29 meshopt_VertexCacheStatistics stats= meshopt_analyzeVertexCache( mesh.indices().data(), mesh.indices().size(), mesh.positions().size(),
30 /* cache size */ 14, /* warp size */ 64, /* primgroup size*/ 128 ); // amd
31 //~ /* cache size */ 16, /* warp size */ 32, /* primgroup size*/ 32 ); // nvidia
32
33 printf("[vertex cache]\n");
34 printf(" transformed vertices %u\n", stats.vertices_transformed);
35 printf(" warps %u\n", stats.warps_executed);
36 printf(" acmr transformed vertices / triangle %f\n", stats.acmr);
37 printf(" atvr transformed vertices / vertex %f\n", stats.atvr);
38 printf("\n");
39 /* acmr : transformed vertices / triangle count; best case 0.5, worst case 3.0, optimum depends on topology */
40 /* atvr : transformed vertices / vertex count; best case 1.0, worst case 6.0, optimum is 1.0 (each vertex is transformed once) */
41}
42
43void vfetch( const Mesh& mesh )
44{
45 unsigned vertex_size= sizeof(vec3);
46 meshopt_VertexFetchStatistics stats= meshopt_analyzeVertexFetch( mesh.indices().data(), mesh.indices().size(), mesh.positions().size(), vertex_size );
47
48 printf("[vertex fetch]\n");
49 printf(" bytes %u, %uMB\n", stats.bytes_fetched, stats.bytes_fetched / 1024 / 1024);
50 printf(" overfetch %f\n", stats.overfetch);
51 printf("\n");
52}
53
54
55Mesh shuffle( const Mesh& data )
56{
57 struct triangle
58 {
59 unsigned a, b, c;
60 };
61
62 std::vector<triangle> triangles;
63 triangles.reserve(data.triangle_count());
64
65 std::vector<unsigned> indices= data.indices();
66 for(unsigned i= 0; i +2 < indices.size(); i+= 3)
67 {
68 triangle t= { indices[i], indices[i+1], indices[i+2] };
69 triangles.push_back( t );
70 }
71
72 std::random_device hwseed;
73 std::default_random_engine rng( hwseed() );
74 std::shuffle(triangles.begin(), triangles.end(), rng);
75
76 indices.resize(triangles.size() * 3);
77 for(unsigned i= 0; i < triangles.size(); i++)
78 {
79 triangle t= triangles[i];
80 indices[3*i]= t.a;
81 indices[3*i+1]= t.b;
82 indices[3*i+2]= t.c;
83 }
84
85 return Mesh( data.primitives(), data.positions(), indices );
86}
87
88
89Mesh optimize_vcache( const Mesh& mesh )
90{
91 std::vector<unsigned> indices( mesh.index_count() );
92 meshopt_optimizeVertexCache( indices.data(), mesh.indices().data(), mesh.indices().size(), mesh.positions().size() );
93
94 return Mesh( mesh.primitives(), mesh.positions(), indices );
95}
96
97Mesh optimize_vfetch( const Mesh& mesh )
98{
99 std::vector<vec3> positions( mesh.vertex_count() );
100 std::vector<unsigned> indices= mesh.indices();
101 meshopt_optimizeVertexFetch( positions.data(), indices.data(), indices.size(), mesh.positions().data(), mesh.positions().size(), sizeof(vec3) );
102
103 return Mesh( mesh.primitives(), positions, indices );
104}
105
106
107class TP : public AppTime
108{
109public:
110 // constructeur : donner les dimensions de l'image, et eventuellement la version d'openGL.
111 TP( const char *filename ) : AppTime(1024, 576, 4,4)
112 {
113 m_objet= read_indexed_mesh_fast(filename);
114 }
115
116 int init( )
117 {
118 if(m_objet.vertex_count() == 0)
119 return -1;
120
121 // conserve une copie de l'original...
122 m_objet_reference= m_objet;
123
124 // projection par defaut, adaptee a la fenetre
125 m_camera.projection(window_width(), window_height(), 45);
126
127 // placer la camera
128 Point pmin, pmax;
129 m_objet.bounds(pmin, pmax);
130 m_camera.lookat(pmin, pmax);
131
132 // creer le shader program, uniquement necessaire pour l'option 2, cf render()
133 m_program= read_program("gkit2_tutos/M2/vertex.glsl");
134 program_print_errors(m_program);
135
136 m_display_program= read_program("gkit2_tutos/M2/vertex_display.glsl");
137 program_print_errors(m_display_program);
138
139 // etat openGL par defaut
140 glClearColor(0.2, 0.2, 0.2, 1); // couleur par defaut de la fenetre
141
142 glClearDepth(1); // profondeur par defaut
143 glDepthFunc(GL_LEQUAL); // ztest, conserver l'intersection la plus proche de la camera
144 glEnable(GL_DEPTH_TEST); // activer le ztest
145 glEnable(GL_CULL_FACE);
146
147 glGenQueries(1, &m_query_vertex_shaders);
148
149 glGenBuffers(1, &m_buffer);
150 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
151 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(unsigned) * m_objet.vertex_count(), nullptr, GL_STREAM_DRAW);
152
153 // compte le nombre de triangles referencant chaque sommet
154 const std::vector<unsigned> &indices= m_objet.indices();
155 m_shared.resize( m_objet.vertex_count() );
156
157 for(unsigned i= 0; i < indices.size(); i++)
158 m_shared[ indices[i] ]++;
159
160 return 0; // ras, pas d'erreur
161 }
162
163 // destruction des objets de l'application
164 int quit( )
165 {
166 release_program(m_program);
167 m_objet.release();
168 return 0;
169 }
170
171 // dessiner une nouvelle image
172 int render( )
173 {
174 update_camera( m_camera ); // pour screenshot, temps gpu inclu...
175
176 //
177 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
178
179 static int optimize= 0;
180 static bool capture= true;
181 static const char *export_filename= "export.obj";
182
183 if(key_state('o'))
184 {
185 clear_key_state('o');
186 optimize= (optimize +1) % 4;
187
188 if(optimize == 0)
189 {
190 capture= true; // force une nouvelle capture
191 printf("reference...\n");
192 m_objet= m_objet_reference;
193 export_filename= "reference.obj";
194 }
195
196 if(optimize == 1)
197 {
198 capture= true; // force une nouvelle capture
199 printf("optimize...\n");
200 m_objet= optimize_vcache(m_objet_reference);
201 m_objet= optimize_vfetch(m_objet);
202 export_filename= "optimize.obj";
203 }
204
205 if(optimize == 2)
206 {
207 capture= true; // force une nouvelle capture
208 printf("shuffle...\n");
209 m_objet= shuffle(m_objet_reference);
210 export_filename= "shuffle.obj";
211 }
212
213 if(optimize == 3)
214 {
215 capture= false; // pas de capture !! on modifie directement le buffer
216 printf("shared...\n");
217 m_objet= m_objet_reference;
218
219 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer);
220 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(unsigned) * m_shared.size(), m_shared.data(), GL_STREAM_DRAW);
221 export_filename= "reference.obj";
222 }
223
224 // analyse l'objet
225 vcache(m_objet);
226 vfetch(m_objet);
227 }
228
229 // export
230 if(key_state('x'))
231 {
232 clear_key_state('x');
233 write_mesh(m_objet, export_filename);
234 }
235
236 if(key_state('r'))
237 {
238 capture= true; // force une nouvelle capture
239 clear_key_state('r');
240
241 // recharger le shader
242 reload_program(m_program);
243 program_print_errors(m_program);
244
245 reload_program(m_display_program);
246 program_print_errors(m_display_program);
247 }
248
249 static bool rotate= false;
250 if(key_state(' '))
251 {
252 clear_key_state(' ');
253 rotate= !rotate;
254 }
255
256 static Transform model= Identity();
257 if(rotate)
258 model= RotationY(global_time() / 40);
259
260 Transform view= m_camera.view();
261 Transform projection= m_camera.projection(window_width(), window_height(), 45);
262 Transform mv= view * model;
263 Transform mvp= projection * mv;
264
265 // capture les transformations
266 if(capture)
267 {
268 capture= false; // 1 seule fois
269
270 int zeros[4]= { 0, 0, 0, 0 };
271 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
272 glClearBufferData(GL_SHADER_STORAGE_BUFFER, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, zeros);
273
274 glBeginQuery(GL_VERTEX_SHADER_INVOCATIONS, m_query_vertex_shaders);
275
276 glUseProgram(m_program);
277 program_uniform(m_program, "mvpMatrix", mvp);
278
279 m_objet.draw(m_program);
280
281 glEndQuery(GL_VERTEX_SHADER_INVOCATIONS);
282
283 GLuint64 vertices= m_objet.vertex_count();
284 GLuint64 vertex_shaders= 0; glGetQueryObjectui64v(m_query_vertex_shaders, GL_QUERY_RESULT, &vertex_shaders);
285 printf("%lu transformed vertices / %lu vertex atvr %f\n", vertex_shaders, vertices, float(vertex_shaders) / float(vertices));
286
287 glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
288 glClear(GL_COLOR_BUFFER_BIT);
289 }
290
291 // affiche la capture / nombre de sommets transformes
292 {
293 glUseProgram(m_display_program);
294 program_uniform(m_display_program, "mvpMatrix", mvp);
295 program_uniform(m_display_program, "mvMatrix", mv);
296
297 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
298
299 m_objet.draw( m_display_program);
300 }
301
302 return 1;
303 }
304
305protected:
306 Transform m_model;
307 Orbiter m_camera;
308 Mesh m_objet;
309 Mesh m_objet_reference;
310
311 std::vector<unsigned> m_shared;
312
313 GLuint m_program;
314 GLuint m_display_program;
315 GLuint m_buffer;
316
317 GLuint m_query_vertices;
318 GLuint m_query_vertex_shaders;
319 GLuint m_query_fragment_shaders;
320};
321
322
323int main( int argc, char **argv )
324{
325 const char *filename= "data/bigguy.obj";
326 //~ const char *filename= "bunny.obj";
327
328 if(argc > 1)
329 filename= argv[1];
330
331 TP tp( filename );
332 tp.run();
333
334 return 0;
335}
AppTime(const int width, const int height, const int major=3, const int minor=3)
constructeur, dimensions de la fenetre et version d'openGL.
Definition app_time.cpp:8
representation d'un objet / maillage.
Definition mesh.h:121
representation de la camera, type orbiter, placee sur une sphere autour du centre de l'objet.
Definition orbiter.h:17
Definition alpha.cpp:58
int render()
a deriver pour afficher les objets. renvoie 1 pour continuer, 0 pour fermer l'application.
Definition vertices.cpp:172
int quit()
a deriver pour detruire les objets openGL. renvoie -1 pour indiquer une erreur, 0 sinon.
Definition vertices.cpp:164
int init()
a deriver pour creer les objets openGL. renvoie -1 pour indiquer une erreur, 0 sinon.
Definition vertices.cpp:116
scene glTF.
int window_height()
renvoie la hauteur de la fenetre de l'application.
Definition window.cpp:27
void clear_key_state(const SDL_Keycode key)
desactive une touche du clavier.
Definition window.cpp:69
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
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:63
int window_width()
renvoie la largeur de la fenetre de l'application.
Definition window.cpp:23
float global_time()
renvoie le temps ecoule depuis le lancement de l'application, en millisecondes.
Definition window.cpp:145
Transform Identity()
construit la transformation identite.
Definition mat.cpp:187
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_indexed_mesh_fast(const char *filename)
charge un fichier wavefront .obj et renvoie un mesh compose de triangles indexes. utiliser glDrawElem...
int write_mesh(const Mesh &mesh, const char *filename, const char *materials_filename)
enregistre un mesh dans un fichier .obj.
int capture(const char *prefix)
Definition texture.cpp:205
GLuint read_program(const char *filename, const char *definitions)
Definition program.cpp:214
int program_print_errors(const GLuint program, const char *filename)
affiche les erreurs de compilation.
Definition program.cpp:459
int release_program(const GLuint program)
Definition program.cpp:238
MeshData vertices(MeshData &data)
construit les sommets. prepare l'affichage openGL, avec glDrawArrays().
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
vecteur generique, utilitaire.
Definition vec.h:169