-
-
Notifications
You must be signed in to change notification settings - Fork 100
/
book.html
5993 lines (5812 loc) · 568 KB
/
book.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.14: http://docutils.sourceforge.net/" />
<title>Python & OpenGL for Scientific Visualization</title>
<meta content="An open-source book about Python and OpenGL for Scientific Visualization based on experience, practice and descriptive examples" name="description" />
<link rel="stylesheet" href="book.css" type="text/css" />
</head>
<body>
<div class="document" id="python-opengl-for-scientific-visualization">
<h1 class="title">Python & OpenGL for Scientific Visualization</h1>
<h2 class="subtitle" id="copyright-c-2018-nicolas-p-rougier-nicolas-rougier-inria-fr">Copyright (c) 2018 - Nicolas P. Rougier <<a class="reference external" href="mailto:Nicolas.Rougier%40inria.fr">Nicolas<span>.</span>Rougier<span>@</span>inria<span>.</span>fr</a>></h2>
<div class="title-logos docutils container">
<img alt="images/cc.large.png" src="images/cc.large.png" style="width: 32px;" />
<img alt="images/by.large.png" src="images/by.large.png" style="width: 32px;" />
<img alt="images/sa.large.png" src="images/sa.large.png" style="width: 32px;" />
<img alt="images/nc.large.png" src="images/nc.large.png" style="width: 32px;" />
<div class="line-block">
<div class="line">Latest version - October 2019</div>
<div class="line"><a class="reference external" href="http://www.labri.fr/perso/nrougier/python-opengl">www.labri.fr/perso/nrougier/python-opengl</a></div>
</div>
</div>
<img alt="images/teaser.png" class="teaser" src="images/teaser.png" />
<div class="line-block">
<div class="line"><br /></div>
</div>
<div class="book-abstract docutils container">
<strong>Python and OpenGL</strong> have a long but complicated story. It used to be
really easy to program something using the fixed-pipeline and libraries such
as Pyglet but things have became more difficult with the introduction of the
dynamic graphic pipeline in 2004. The goal of this book is to reconcile
Python programmers with OpenGL, providing both an introduction to modern
OpenGL and a set of basic and advanced techniques in order to achieve both
fast, scalable & beautiful scientific visualizations. The book uses the GLES
2.0 API which is the most simple API for accessing the programmable graphic
pipeline. It does not cover up-to-date OpenGL techniques but it is
sufficient to achieve great visualisation. In fact, modern OpenGL allows to
control pretty much everything in the pipeline and the goal of this book is
to explain several techniques dedicated to scientific visualisation such as
isolines, markers, colormaps, arbitrary transformations but there are
actually many more techniques to be discovered and explained in this
open-access book. And of course, everything will be fast and beautiful.</div>
<div class="book-colophon docutils container">
<div class="line-block">
<div class="line">Copyright (c) 2018 by Nicolas P. Rougier</div>
<div class="line">This work is licensed under a Creative Commons</div>
<div class="line">Attribution-Non Commercial-Share Alike 4.0 International License</div>
<div class="line">First published online in 2018, Bordeaux, France</div>
<div class="line">ISBN: X-XXXXX-XXX-X</div>
</div>
</div>
<div class="line-block">
<div class="line"><br /></div>
<div class="line"><br /></div>
<div class="line"><br /></div>
</div>
<div class="sidebar">
<p class="first sidebar-title"><a class="reference external" href="#python-opengl-for-scientific-visualization">Python & OpenGL</a>
<span class="subtitle">for Scientific Visualization</span>
<span class="small">by Nicolas P. Rougier, 2018</span></p>
<div class="contents local last topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#preface" id="id55">Preface</a><ul>
<li><a class="reference internal" href="#about-the-author" id="id56">About the author</a></li>
<li><a class="reference internal" href="#about-this-book" id="id57">About this book</a></li>
<li><a class="reference internal" href="#license" id="id58">License</a></li>
</ul>
</li>
<li><a class="reference internal" href="#introduction" id="id59">Introduction</a><ul>
<li><a class="reference internal" href="#a-bit-of-history" id="id60">A bit of history</a></li>
<li><a class="reference internal" href="#modern-opengl" id="id61">Modern OpenGL</a></li>
<li><a class="reference internal" href="#state-of-the-union" id="id62">State of the union</a></li>
</ul>
</li>
<li><a class="reference internal" href="#quickstart" id="id63">Quickstart</a><ul>
<li><a class="reference internal" href="#preliminaries" id="id64">Preliminaries</a></li>
<li><a class="reference internal" href="#the-hard-way" id="id65">The hard way</a></li>
<li><a class="reference internal" href="#the-easy-way" id="id66">The easy way</a></li>
<li><a class="reference internal" href="#exercises" id="id67">Exercises</a></li>
</ul>
</li>
<li><a class="reference internal" href="#basic-mathematics" id="id68">Basic Mathematics</a><ul>
<li><a class="reference internal" href="#id12" id="id69">Projective Geometry</a></li>
<li><a class="reference internal" href="#transformations" id="id70">Transformations</a></li>
<li><a class="reference internal" href="#id14" id="id71">Projections</a></li>
</ul>
</li>
<li><a class="reference internal" href="#rendering-a-cube" id="id72">Rendering a cube</a><ul>
<li><a class="reference internal" href="#object-creation" id="id73">Object creation</a></li>
<li><a class="reference internal" href="#scene-setup" id="id74">Scene setup</a></li>
<li><a class="reference internal" href="#actual-rendering" id="id75">Actual rendering</a></li>
<li><a class="reference internal" href="#variations" id="id76">Variations</a></li>
<li><a class="reference internal" href="#id16" id="id77">Exercises</a></li>
</ul>
</li>
<li><a class="reference internal" href="#anti-grain-geometry" id="id78">Anti-grain geometry</a><ul>
<li><a class="reference internal" href="#antialiasing" id="id79">Antialiasing</a></li>
<li><a class="reference internal" href="#signed-distance-fields" id="id80">Signed distance fields</a></li>
<li><a class="reference internal" href="#distance-based-anti-aliasing" id="id81">Distance based anti-aliasing</a></li>
</ul>
</li>
<li><a class="reference internal" href="#rendering-points" id="id82">Rendering points</a><ul>
<li><a class="reference internal" href="#dots-discs-circles" id="id83">Dots, discs, circles</a></li>
<li><a class="reference internal" href="#ellipses" id="id84">Ellipses</a></li>
<li><a class="reference internal" href="#spheres" id="id85">Spheres</a></li>
<li><a class="reference internal" href="#id28" id="id86">Exercises</a></li>
</ul>
</li>
<li><a class="reference internal" href="#rendering-markers" id="id87">Rendering markers</a><ul>
<li><a class="reference internal" href="#constructive-solid-geometry" id="id88">Constructive Solid Geometry</a></li>
<li><a class="reference internal" href="#markers" id="id89">Markers</a></li>
<li><a class="reference internal" href="#arrows" id="id90">Arrows</a></li>
<li><a class="reference internal" href="#texture-based" id="id91">Texture based</a></li>
<li><a class="reference internal" href="#id37" id="id92">Exercises</a></li>
</ul>
</li>
<li><a class="reference internal" href="#rendering-lines" id="id93">Rendering lines</a><ul>
<li><a class="reference internal" href="#raw-lines" id="id94">Raw Lines</a></li>
<li><a class="reference internal" href="#segments" id="id95">Segments</a></li>
<li><a class="reference internal" href="#lines" id="id96">Lines</a></li>
<li><a class="reference internal" href="#patterns" id="id97">Patterns</a></li>
<li><a class="reference internal" href="#d-lines" id="id98">3D lines</a></li>
<li><a class="reference internal" href="#id44" id="id99">Exercises</a></li>
</ul>
</li>
<li><a class="reference internal" href="#rendering-polygons" id="id100">Rendering polygons</a><ul>
<li><a class="reference internal" href="#id46" id="id101">Triangulation</a></li>
<li><a class="reference internal" href="#fill-rule" id="id102">Fill rule</a></li>
<li><a class="reference internal" href="#id48" id="id103">Exercises</a></li>
</ul>
</li>
<li><a class="reference internal" href="#rendering-a-mesh" id="id104">Rendering a mesh</a></li>
<li><a class="reference internal" href="#rendering-text" id="id105">Rendering text</a></li>
<li><a class="reference internal" href="#framebuffer" id="id106">Framebuffer</a></li>
<li><a class="reference internal" href="#special-techniques" id="id107">Special techniques</a></li>
<li><a class="reference internal" href="#conclusion" id="id108">Conclusion</a></li>
<li><a class="reference internal" href="#glsl-references" id="id109">GLSL References</a><ul>
<li><a class="reference internal" href="#types" id="id110">Types</a></li>
<li><a class="reference internal" href="#qualifiers" id="id111">Qualifiers</a></li>
<li><a class="reference internal" href="#built-in-variables" id="id112">Built-in variables</a></li>
<li><a class="reference internal" href="#built-in-constants" id="id113">Built-in constants</a></li>
<li><a class="reference internal" href="#built-in-functions" id="id114">Built-in functions</a></li>
</ul>
</li>
<li><a class="reference internal" href="#bibliography" id="id115">Bibliography</a><ul>
<li><a class="reference internal" href="#people" id="id116">People</a></li>
<li><a class="reference internal" href="#tutorials" id="id117">Tutorials</a></li>
<li><a class="reference internal" href="#articles" id="id118">Articles</a></li>
<li><a class="reference internal" href="#books" id="id119">Books</a></li>
</ul>
</li>
</ul>
</div>
</div>
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<div class="section" id="preface">
<h1><a class="toc-backref" href="#contents">Preface</a></h1>
<div class="contents toc chapter-01 local topic" id="id1">
<p class="topic-title first">.</p>
<ul class="simple">
<li><a class="reference internal" href="#about-the-author" id="id120">About the author</a></li>
<li><a class="reference internal" href="#about-this-book" id="id121">About this book</a><ul>
<li><a class="reference internal" href="#prerequisites" id="id122">Prerequisites</a></li>
<li><a class="reference internal" href="#conventions" id="id123">Conventions</a></li>
<li><a class="reference internal" href="#how-to-contribute" id="id124">How to contribute</a></li>
<li><a class="reference internal" href="#publishing" id="id125">Publishing</a></li>
</ul>
</li>
<li><a class="reference internal" href="#license" id="id126">License</a><ul>
<li><a class="reference internal" href="#book" id="id127">Book</a></li>
<li><a class="reference internal" href="#code" id="id128">Code</a></li>
</ul>
</li>
</ul>
</div>
<p>This book is open-access (i.e. it's free to read at <a class="reference external" href="http://www.labri.fr/perso/nrougier/python-opengl">this address</a>) because I believe
knowledge should be free. However, if you think the book is worth a few
dollars, you can give me a few euros (<a class="reference external" href="https://www.paypal.me/NicolasPRougier/5">5€</a> or <a class="reference external" href="https://www.paypal.me/NicolasPRougier/10">10€</a>). This money will help me to
travel to Python conferences and to write other books as well. If you don't
have money, it's fine. Just enjoy the book and spread the word about it. The
teaser image above comes from the <a class="reference external" href="http://www.labri.fr/perso/nrougier/artwork/index.html">artwork section</a> of my website. It has
been made some years ago using the <a class="reference external" href="http://www.povray.org">Povray</a>
(Persistence of Vision) raytracer. I like it very much because it is a kind of
résumé of my <a class="reference external" href="http://www.labri.fr/perso/nrougier/research/index.html">research</a>.</p>
<div class="section" id="about-the-author">
<h2><a class="toc-backref" href="#id1">About the author</a></h2>
<p>I am a full-time research scientist at <a class="reference external" href="http://www.inria.fr/en">Inria</a> which is the French national
institute for research in computer science and control. This is a public
scientific and technological establishment (EPST) under the double supervision
of the Research & Education Ministry, and the Ministry of Economy Finance and
Industry. I'm working within the <a class="reference external" href="http://www.inria.fr/en/teams/mnemosyne">Mnemosyne</a> project which lies at the frontier
between integrative and computational neuroscience in association with the
<a class="reference external" href="http://www.imn-bordeaux.org/en/">Institute of Neurodegenerative Diseases</a>, the Bordeaux laboratory for
research in computer science (<a class="reference external" href="https://www.labri.fr/">LaBRI</a>), the <a class="reference external" href="http://www.u-bordeaux.com/">University of Bordeaux</a> and the
national center for scientific research (<a class="reference external" href="http://www.cnrs.fr/index.php">CNRS</a>).</p>
<p>I've been using Python for more than 15 years and numpy for more than 10 years
for modeling in neuroscience, machine learning and for advanced visualization
(OpenGL). I'm the author of several online resources and tutorials (Matplotlib,
numpy, OpenGL) and I've been teaching Python, numpy and scientific
visualization at the University of Bordeaux and in various conferences and
schools worldwide (SciPy, EuroScipy, etc). I'm also the author of the popular
article <a class="reference external" href="http://dx.doi.org/10.1371/journal.pcbi.1003833">Ten Simple Rules for Better Figures</a> , a popular <a class="reference external" href="http://www.labri.fr/perso/nrougier/teaching/matplotlib/matplotlib.html">matplotlib
tutorial</a> and an open access book <a class="reference external" href="http://www.labri.fr/perso/nrougier/from-python-to-numpy/">From Python To Numpy</a>.</p>
</div>
<div class="section" id="about-this-book">
<h2><a class="toc-backref" href="#id1">About this book</a></h2>
<p>This book has been written in <a class="reference external" href="http://docutils.sourceforge.net/rst.html">restructured text</a> format and generated using a <a class="reference external" href="rst2html.py">customized
version</a> of the docutils rst2html.py command line (available from
the <a class="reference external" href="http://docutils.sourceforge.net/">docutils</a> python package) and a custom <a class="reference external" href="book-template.txt">template</a>.</p>
<p>If you want to rebuild the html output, from the top directory, type:</p>
<pre class="code literal-block">
$ ./rst2html.py --link-stylesheet \
--cloak-email-addresses \
--toc-top-backlinks \
--stylesheet book.css \
--stylesheet-dirs . \
book.rst book.html
</pre>
<p>Or you use the provided <a class="reference external" href="make.sh">make.sh</a> shell script.</p>
<p>The sources are available from <a class="reference external" href="https://github.com/rougier/python-opengl">https://github.com/rougier/python-opengl</a>.</p>
<p>Last point, I wrote the book in a kind of modern <a class="reference external" href="https://en.wikipedia.org/wiki/Jack_Kerouac">Kerouac</a>'s style such that you can
download it once and continue reading it offline. Initial loading may be
slow though.</p>
<div class="section" id="prerequisites">
<h3><a class="toc-backref" href="#id1">Prerequisites</a></h3>
<p>This is not a Python nor a NumpPy beginner guide and you should have an
intermediate level in both Python and NumPy. No prior knowledge of OpenGL is
necessary because I'll explain everything.</p>
</div>
<div class="section" id="conventions">
<h3><a class="toc-backref" href="#id1">Conventions</a></h3>
<p>I will use usual naming conventions. If not stated explicitly, each script
should import numpy, scipy and glumpy as:</p>
<pre class="code python literal-block">
<span class="keyword namespace">import</span> <span class="name namespace">numpy</span> <span class="keyword namespace">as</span> <span class="name namespace">np</span>
</pre>
<p>We'll use up-to-date versions (at the date of writing, i.e. August, 2017) of the
different packages:</p>
<table border="1" class="docutils">
<colgroup>
<col width="55%" />
<col width="45%" />
</colgroup>
<thead valign="bottom">
<tr><th class="head">Packages</th>
<th class="head">Version</th>
</tr>
</thead>
<tbody valign="top">
<tr><td>Python</td>
<td>3.6.0</td>
</tr>
<tr><td>Numpy</td>
<td>1.12.0</td>
</tr>
<tr><td>Scipy</td>
<td>0.18.1</td>
</tr>
<tr><td>Cython</td>
<td>0.25.2</td>
</tr>
<tr><td>Triangle</td>
<td>20170106</td>
</tr>
<tr><td>Glumpy</td>
<td>1.0.6</td>
</tr>
</tbody>
</table>
</div>
<div class="section" id="how-to-contribute">
<h3><a class="toc-backref" href="#id1">How to contribute</a></h3>
<p>If you want to contribute to this book, you can:</p>
<ul class="simple">
<li>Report issues (<a class="reference external" href="https://github.com/rougier/python-opengl/issues">https://github.com/rougier/python-opengl/issues</a>)</li>
<li>Suggest improvements (<a class="reference external" href="https://github.com/rougier/python-opengl/pulls">https://github.com/rougier/python-opengl/pulls</a>)</li>
<li>Correct English (<a class="reference external" href="https://github.com/rougier/python-opengl/issues">https://github.com/rougier/python-opengl/issues</a>)</li>
<li>Star the project (<a class="reference external" href="https://github.com/rougier/python-opengl">https://github.com/rougier/python-opengl</a>)</li>
<li>Suggest a more responsive design for the HTML Book</li>
<li>Spread the word about this book (Reddit, Hacker News, etc.)</li>
</ul>
</div>
<div class="section" id="publishing">
<h3><a class="toc-backref" href="#id1">Publishing</a></h3>
<p>If you're an editor interested in publishing this book, you can <a class="reference external" href="mailto:Nicolas.Rougier%40inria.fr">contact me</a> if you agree to have this version and all
subsequent versions open access (i.e. online at <a class="reference external" href="http://www.labri.fr/perso/nrougier/python-opengl">this address</a>), you know how to deal
with <a class="reference external" href="http://docutils.sourceforge.net/rst.html">restructured text</a> (Word is
not an option), you provide a real added-value as well as supporting services,
and more importantly, you have a truly amazing latex book template (and be
warned that I'm a bit picky about typography & design: <a class="reference external" href="https://www.edwardtufte.com/tufte/">Edward Tufte</a> is my hero). Still here?</p>
</div>
</div>
<div class="section" id="license">
<h2><a class="toc-backref" href="#id1">License</a></h2>
<div class="section" id="book">
<h3><a class="toc-backref" href="#id1">Book</a></h3>
<p>This work is licensed under a <a class="reference external" href="https://creativecommons.org/licenses/by-nc-sa/4.0/">Creative Commons Attribution-Non Commercial-Share
Alike 4.0 International License</a>. You are free to:</p>
<ul class="simple">
<li><strong>Share</strong> — copy and redistribute the material in any medium or format</li>
<li><strong>Adapt</strong> — remix, transform, and build upon the material</li>
</ul>
<p>The licensor cannot revoke these freedoms as long as you follow the license terms.</p>
<p>Under the following terms:</p>
<ul class="simple">
<li><strong>Attribution</strong> — You must give appropriate credit, provide a link to the
license, and indicate if changes were made. You may do so in any reasonable
manner, but not in any way that suggests the licensor endorses you or your
use.</li>
<li><strong>NonCommercial</strong> — You may not use the material for commercial purposes.</li>
<li><strong>ShareAlike</strong> — If you remix, transform, or build upon the material, you
must distribute your contributions under the same license as the original.</li>
</ul>
</div>
<div class="section" id="code">
<h3><a class="toc-backref" href="#id1">Code</a></h3>
<p>The code is licensed under the <a class="reference external" href="LICENSE-code.txt">OSI-approved BSD 2-Clause License</a>.</p>
<!-- - - - Links - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
</div>
</div>
</div>
<div class="section" id="introduction">
<h1><a class="toc-backref" href="#contents">Introduction</a></h1>
<div class="contents toc chapter-02 local topic" id="id5">
<p class="topic-title first">.</p>
<ul class="simple">
<li><a class="reference internal" href="#a-bit-of-history" id="id129">A bit of history</a></li>
<li><a class="reference internal" href="#modern-opengl" id="id130">Modern OpenGL</a><ul>
<li><a class="reference internal" href="#the-graphic-pipeline" id="id131">The graphic pipeline</a></li>
<li><a class="reference internal" href="#buffers" id="id132">Buffers</a></li>
<li><a class="reference internal" href="#variables" id="id133">Variables</a></li>
</ul>
</li>
<li><a class="reference internal" href="#state-of-the-union" id="id134">State of the union</a><ul>
<li><a class="reference internal" href="#bindings" id="id135">Bindings</a></li>
<li><a class="reference internal" href="#engines" id="id136">Engines</a></li>
<li><a class="reference internal" href="#libraries" id="id137">Libraries</a></li>
</ul>
</li>
</ul>
</div>
<p>Before diving into OpenGL programming, it is important to have a look at the
whole GL landscape because it is actually quite complex and you can easily lose
yourself between the different actors, terms and definitions. The teaser image
above shows the face of a character from the Wolfenstein game, one from 1992
and the other from 2015. You can see that computer graphics has evolved a lot
in 25 years.</p>
<div class="section" id="a-bit-of-history">
<h2><a class="toc-backref" href="#id5">A bit of history</a></h2>
<p>OpenGL is 25 years old! Since the first release in 1992, a lot has happened
(and is still happening actually, with the newly released <a class="reference external" href="https://en.wikipedia.org/wiki/Vulkan_(API)">Vulkan</a> API and the
4.6 GL release) and consequently, before diving into the book, it is important
to understand OpenGL API evolution over the years. If the first API (1.xx) has
not changed too much in the first twelve years, a big change occurred in 2004
with the introduction of the dynamic pipeline (OpenGL 2.x), i.e. the use of
shaders that allow to have direct access to the GPU. Before this version,
OpenGL was using a fixed pipeline that made it easy to rapidly prototype some
ideas. It was simple but not very powerful because the user had not much
control over the graphic pipeline. This is the reason why it has been
<a class="reference external" href="https://khronos.org/registry/OpenGL/specs/gl/glspec30.pdf#page=421">deprecated</a> more than ten years ago and you don't want to use it today. Problem
is that there are a lot of tutorials online that still use this fixed pipeline
and because most of them were written before modern GL, they're not even aware
(and cannot) that they use a deprecated API.</p>
<p>How to know if a tutorial address the fixed pipeline ? It's relatively
easy. It'll contain GL commands such as:</p>
<pre class="code neutral literal-block">
glVertex, glColor, glLight, glMaterial, glBegin, glEnd, glMatrix,
glMatrixMode, glLoadIdentity, glPushMatrix, glPopMatrix, glRect,
glPolygonMode, glBitmap, glAphaFunc, glNewList, glDisplayList,
glPushAttrib, glPopAttrib, glVertexPointer, glColorPointer,
glTexCoordPointer, glNormalPointer, glRotate, glTranslate, glScale,
glMatrixMode, glCall,
</pre>
<p>If you see any of them in a tutorial, run away because it it's most certainly a
tutorial that address the fixed pipeline and you don't want to read it because
what you will learn is already useless. If you look at the GL history below,
you'll realize that the "modern" GL API is already 13 years old while the fixed
pipeline has been deprecated more than 10 years ago.</p>
<pre class="code neutral literal-block">
1 2 Modern 2
9 0 OpenGL 0 Vulkan
9 0 ↓ 1 ↓
2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7
─────────────────────────────────────┬───────────────────────────────────┬────
OpenGL 3.3
4.0
3.1
1.2 1.4 2.0 3.2 4.2 4.4
1.0 1.1 1.3 1.5 2.1 3.0 4.1 4.3 4.5 4.6
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┬╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
Fixed pipeline ╎ Programmable pipeline
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┴╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
GLES ╭─────╮ 3.2
1.0 │ 2.0 │ 3.0 3.1
╰─────╯
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
GLSL 4.0 4.3 4.5 4.6
1.3 4.1 4.4
1.4 4.2
1.1 1.2 1.5
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
WebGL 1.0 2.0
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
Vulkan 1.0
──────────────────────────────────────────────────────────────────────────────
</pre>
<p>From <a class="reference external" href="https://www.khronos.org/opengl/wiki/History_of_OpenGL">OpenGL wiki</a>: <em>In 1992, Mark Segal and Kurt Akeley authored the OpenGL
1.0 specification which formalized a graphics API and made cross platform 3rd
party implementation and support viable. In 2004, OpenGL 2.0 incorporated the
significant addition of the OpenGL Shading Language (also called GLSL), a C
like language with which the transformation and fragment shading stages of the
pipeline can be programmed. In 2008, OpenGL 3.0 added the concept of
deprecation: marking certain features as subject to removal in later versions.</em></p>
<dl class="docutils">
<dt><a class="reference external" href="https://en.wikipedia.org/wiki/OpenGL">Open Graphics Library</a> (OpenGL)</dt>
<dd>OpenGL is a cross-language, cross-platform application programming interface
(API) for rendering 2D and 3D vector graphics. The API is typically used to
interact with a graphics processing unit (GPU), to achieve
hardware-accelerated rendering.</dd>
<dt><a class="reference external" href="https://en.wikipedia.org/wiki/OpenGL_ES`">OpenGL for Embedded Systems</a> (OpenGL ES or GLES)</dt>
<dd>GLES is a subset of the OpenGL computer graphics rendering application
programming interface (API) for rendering 2D and 3D computer graphics such as
those used by video games, typically hardware-accelerated using a graphics
processing unit (GPU).</dd>
<dt><a class="reference external" href="https://en.wikipedia.org/wiki/OpenGL_Shading_Language">OpenGL Shading Language</a> (GLSL)</dt>
<dd>GLSL is a high-level shading language with a syntax based on the C
programming language. It was created by the OpenGL ARB (OpenGL Architecture
Review Board) to give developers more direct control of the graphics pipeline</dd>
<dt><a class="reference external" href="https://en.wikipedia.org/wiki/WebGL">Web Graphics Library</a> (WebGL)</dt>
<dd>WebGL is a JavaScript API for rendering 3D graphics within any compatible web
browser without the use of plug-ins. WebGL is integrated completely into all
the web standards of the browser allowing GPU accelerated usage of physics
and image processing and effects as part of the web page canvas.</dd>
<dt><a class="reference external" href="https://en.wikipedia.org/wiki/Vulkan_(API)">Vulkan</a> (VK)</dt>
<dd>Vulkan is a low-overhead, cross-platform 3D graphics and compute API first
announced at GDC 2015 by the Khronos Group. Like OpenGL, Vulkan targets
high-performance realtime 3D graphics applications such as video games and
interactive media across all platforms, and can offer higher performance and
more balanced CPU/GPU usage, much like Direct3D 12 and Mantle.</dd>
</dl>
<p>For this book, we'll use the GLES 2.0 API that allows to use the modern GL API
while staying relatively simple. For comparison, have a look at the table
below that gives the number of functions and constants for each version of the
GL API. Note that once you'll master the GLES 2.0, it's only a matter of
reading the documentation to take advantage of more advanced version because
the core concepts remain the same (which is not the case for the new Vulkan
API).</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">The number of functions and constants have been computed using the
<a class="reference external" href="code/chapter-02/registry.py">code/chapter-02/registry.py</a> program that parses the <a class="reference external" href="https://github.com/KhronosGroup/OpenGL-Registry/blob/master/xml/gl.xml">gl.xml</a> file that
defines the OpenGL and OpenGL API Registry</p>
</div>
<table border="1" class="docutils">
<colgroup>
<col width="14%" />
<col width="15%" />
<col width="15%" />
<col width="5%" />
<col width="20%" />
<col width="15%" />
<col width="15%" />
</colgroup>
<thead valign="bottom">
<tr><th class="head">Version</th>
<th class="head">Constants</th>
<th class="head">Functions</th>
<th class="head"> </th>
<th class="head">Version</th>
<th class="head">Constants</th>
<th class="head">Functions</th>
</tr>
</thead>
<tbody valign="top">
<tr><td>GL 1.0</td>
<td>0</td>
<td>306</td>
<td> </td>
<td>GL 3.2</td>
<td>800</td>
<td>316</td>
</tr>
<tr><td>GL 1.1</td>
<td>528</td>
<td>336</td>
<td> </td>
<td>GL 3.3</td>
<td>816</td>
<td>344</td>
</tr>
<tr><td>GL 1.2</td>
<td>569</td>
<td>340</td>
<td> </td>
<td>GL 4.0</td>
<td>894</td>
<td>390</td>
</tr>
<tr><td>GL 1.3</td>
<td>665</td>
<td>386</td>
<td> </td>
<td>GL 4.1</td>
<td>929</td>
<td>478</td>
</tr>
<tr><td>GL 1.4</td>
<td>713</td>
<td>433</td>
<td> </td>
<td>GL 4.2</td>
<td>1041</td>
<td>490</td>
</tr>
<tr><td>GL 1.5</td>
<td>763</td>
<td>452</td>
<td> </td>
<td>GL 4.3</td>
<td>1302</td>
<td>534</td>
</tr>
<tr><td>GL 2.0</td>
<td>847</td>
<td>545</td>
<td> </td>
<td>GL 4.4</td>
<td>1321</td>
<td>543</td>
</tr>
<tr><td>GL 2.1</td>
<td>870</td>
<td>551</td>
<td> </td>
<td>GL 4.5</td>
<td>1343</td>
<td>653</td>
</tr>
<tr><td>GL 3.0</td>
<td>1104</td>
<td>635</td>
<td> </td>
<td>GLES 1.0</td>
<td>333</td>
<td>106</td>
</tr>
<tr><td>GL 3.1</td>
<td>1165</td>
<td>647</td>
<td> </td>
<td><strong>GLES 2.0</strong></td>
<td><strong>301</strong></td>
<td><strong>142</strong></td>
</tr>
</tbody>
</table>
</div>
<div class="section" id="modern-opengl">
<h2><a class="toc-backref" href="#id5">Modern OpenGL</a></h2>
<div class="section" id="the-graphic-pipeline">
<h3><a class="toc-backref" href="#id5">The graphic pipeline</a></h3>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">The shader language is called glsl. There are many versions that goes from 1.0
to 1.5 and subsequent version get the number of OpenGL version. Last version
is 4.6 (June 2017).</p>
</div>
<p>If you want to understand modern OpenGL, you have to understand the graphic
pipeline and shaders. Shaders are pieces of program (using a C-like language)
that are built onto the GPU and executed during the rendering
pipeline. Depending on the nature of the shaders (there are many types
depending on the version of OpenGL you're using), they will act at different
stage of the rendering pipeline. To simplify this tutorial, we'll use only
<strong>vertex</strong> and <strong>fragment</strong> shaders as shown below:</p>
<img alt="images/chapter-02/gl-pipeline.png" src="images/chapter-02/gl-pipeline.png" style="width: 100%;" />
<p>A vertex shader acts on vertices and is supposed to output the vertex
<strong>position</strong> (<code>gl_Position</code>) on the viewport (i.e. screen). A fragment shader
acts at the fragment level and is supposed to output the <strong>color</strong>
(<code>gl_FragColor</code>) of the fragment. Hence, a minimal vertex shader is:</p>
<pre class="code glsl literal-block">
<span class="keyword type">void</span> <span class="name">main</span><span class="punctuation">()</span>
<span class="punctuation">{</span>
<span class="name builtin">gl_Position</span> <span class="operator">=</span> <span class="keyword type">vec4</span><span class="punctuation">(</span><span class="literal number float">0.0</span><span class="punctuation">,</span><span class="literal number float">0.0</span><span class="punctuation">,</span><span class="literal number float">0.0</span><span class="punctuation">,</span><span class="literal number float">1.0</span><span class="punctuation">);</span>
<span class="punctuation">}</span>
</pre>
<p>while a minimal fragment shader would be:</p>
<pre class="code glsl literal-block">
<span class="keyword type">void</span> <span class="name">main</span><span class="punctuation">()</span>
<span class="punctuation">{</span>
<span class="name builtin">gl_FragColor</span> <span class="operator">=</span> <span class="keyword type">vec4</span><span class="punctuation">(</span><span class="literal number float">0.0</span><span class="punctuation">,</span><span class="literal number float">0.0</span><span class="punctuation">,</span><span class="literal number float">0.0</span><span class="punctuation">,</span><span class="literal number float">1.0</span><span class="punctuation">);</span>
<span class="punctuation">}</span>
</pre>
<p>These two shaders are not very useful because the first shader will always
output the null vertex (<code>gl_Position</code> is a special variable) while the second
will only output the black color for any fragment (<code>gl_FragColor</code> is also a
special variable). We'll see later how to make them to do more useful things.</p>
<p>One question remains: when are those shaders executed exactly ? The vertex
shader is executed for each vertex that is given to the rendering pipeline
(we'll see excatly what that means later) and the fragment shader is
executed on each fragment (= pixel) that is generated after the vertex
stage. For example, in the simple figure above, the vertex would be called 3
times, once for each vertex (1,2 and 3) while the fragment shader would be
executed 21 times, once for each fragment.</p>
</div>
<div class="section" id="buffers">
<h3><a class="toc-backref" href="#id5">Buffers</a></h3>
<p>The next question is thus where do those vertices comes from ? The idea of
modern GL is that vertices are stored on the CPU and need to be uploaded to
the GPU before rendering. The way to do that is to build buffers on the CPU
and to send these buffers onto the GPU. If your data does not change, no need
to upload them again. That is the big difference with the previous fixed
pipeline where data were uploaded at each rendering call (only display lists
were built into GPU memory).</p>
<p>But what is the structure of a vertex ? OpenGL does not assume anything about
your vertex structure and you're free to use as much information you may need
for each vertex. The only condition is that all vertices from a buffer have the
same structure (possibly with different content). This, again, is a big
difference with the fixed pipeline where OpenGL was doing a lot of complex
rendering stuff for you (projections, lighting, normals, etc.) with an implicit
fixed vertex structure. The good news is that you're now free to do anything
you want, but the bad news is that you have to program just about everything.</p>
<p>Let's take a simple example of a vertex structure where we want each vertex to
hold a position and a color. The easiest way to do that in python is to use a
structured array using <a class="reference external" href="http://www.numpy.org">numpy</a>:</p>
<pre class="code python literal-block">
<span class="name">data</span> <span class="operator">=</span> <span class="name">np</span><span class="operator">.</span><span class="name">zeros</span><span class="punctuation">(</span><span class="literal number integer">4</span><span class="punctuation">,</span> <span class="name">dtype</span> <span class="operator">=</span> <span class="punctuation">[</span> <span class="punctuation">(</span><span class="literal string double">"position"</span><span class="punctuation">,</span> <span class="name">np</span><span class="operator">.</span><span class="name">float32</span><span class="punctuation">,</span> <span class="literal number integer">3</span><span class="punctuation">),</span>
<span class="punctuation">(</span><span class="literal string double">"color"</span><span class="punctuation">,</span> <span class="name">np</span><span class="operator">.</span><span class="name">float32</span><span class="punctuation">,</span> <span class="literal number integer">4</span><span class="punctuation">)]</span> <span class="punctuation">)</span>
</pre>
<p>We just created a CPU buffer with 4 vertices, each of them having a
<code>position</code> (3 floats for x,y,z coordinates) and a <code>color</code> (4 floats for
red, blue, green and alpha channels). Note that we explicitly chose to have 3
coordinates for <code>position</code> but we may have chosen to have only 2 if were to
work in two-dimensions. Same holds true for <code>color</code>. We could have used
only 3 channels (r,g,b) if we did not want to use transparency. This would save
some bytes for each vertex. Of course, for 4 vertices, this does not really
matter but you have to realize it <strong>will matter</strong> if your data size grows up to
one or ten million vertices.</p>
</div>
<div class="section" id="variables">
<h3><a class="toc-backref" href="#id5">Variables</a></h3>
<p>Now, we need to explain to our shaders what to do with these buffers and how to
connect them together. So, let's consider again a CPU buffer of 4 vertices
using 2 floats for position and 4 floats for color:</p>
<pre class="code python literal-block">
<span class="name">data</span> <span class="operator">=</span> <span class="name">np</span><span class="operator">.</span><span class="name">zeros</span><span class="punctuation">(</span><span class="literal number integer">4</span><span class="punctuation">,</span> <span class="name">dtype</span> <span class="operator">=</span> <span class="punctuation">[</span> <span class="punctuation">(</span><span class="literal string double">"position"</span><span class="punctuation">,</span> <span class="name">np</span><span class="operator">.</span><span class="name">float32</span><span class="punctuation">,</span> <span class="literal number integer">2</span><span class="punctuation">),</span>
<span class="punctuation">(</span><span class="literal string double">"color"</span><span class="punctuation">,</span> <span class="name">np</span><span class="operator">.</span><span class="name">float32</span><span class="punctuation">,</span> <span class="literal number integer">4</span><span class="punctuation">)]</span> <span class="punctuation">)</span>
</pre>
<p>We need to tell the vertex shader that it will have to handle vertices where a
position is a tuple of 2 floats and color is a tuple of 4 floats. This is
precisely what <strong>attributes</strong> are meant for. Let us change slightly our previous
vertex shader:</p>
<pre class="code glsl literal-block">
<span class="keyword">attribute</span> <span class="keyword type">vec2</span> <span class="name">position</span><span class="punctuation">;</span>
<span class="keyword">attribute</span> <span class="keyword type">vec4</span> <span class="name">color</span><span class="punctuation">;</span>
<span class="keyword type">void</span> <span class="name">main</span><span class="punctuation">()</span>
<span class="punctuation">{</span>
<span class="name builtin">gl_Position</span> <span class="operator">=</span> <span class="keyword type">vec4</span><span class="punctuation">(</span><span class="name">position</span><span class="punctuation">,</span> <span class="literal number float">0.0</span><span class="punctuation">,</span> <span class="literal number float">1.0</span><span class="punctuation">);</span>
<span class="punctuation">}</span>
</pre>
<p>This vertex shader now expects a vertex to possess 2 attributes, one named
<code>position</code> and one named <code>color</code> with specified types (vec2 means tuple of
2 floats and vec4 means tuple of 4 floats). It is important to note that even
if we labeled the first attribute <code>position</code>, this attribute is not yet bound
to the actual <code>position</code> in the numpy array. We'll need to do it explicitly
at some point in our program and there is no magic that will bind the numpy
array field to the right attribute, you'll have to do it yourself, but we'll
see that later.</p>
<p>The second type of information we can feed the vertex shader is the <strong>uniform</strong>
that may be considered as constant value (across all the vertices). Let's say
for example we want to scale all the vertices by a constant factor <code>scale</code>,
we would thus write:</p>
<pre class="code glsl literal-block">
<span class="keyword">uniform</span> <span class="keyword type">float</span> <span class="name">scale</span><span class="punctuation">;</span>
<span class="keyword">attribute</span> <span class="keyword type">vec2</span> <span class="name">position</span><span class="punctuation">;</span>
<span class="keyword">attribute</span> <span class="keyword type">vec4</span> <span class="name">color</span><span class="punctuation">;</span>
<span class="keyword type">void</span> <span class="name">main</span><span class="punctuation">()</span>
<span class="punctuation">{</span>
<span class="name builtin">gl_Position</span> <span class="operator">=</span> <span class="keyword type">vec4</span><span class="punctuation">(</span><span class="name">position</span><span class="operator">*</span><span class="name">scale</span><span class="punctuation">,</span> <span class="literal number float">0.0</span><span class="punctuation">,</span> <span class="literal number float">1.0</span><span class="punctuation">);</span>
<span class="punctuation">}</span>
</pre>
<p>Last type is the varying type that is used to pass information between the
vertex stage and the fragment stage. So let us suppose (again) we want to pass
the vertex color to the fragment shader, we now write:</p>
<pre class="code glsl literal-block">
<span class="keyword">uniform</span> <span class="keyword type">float</span> <span class="name">scale</span><span class="punctuation">;</span>
<span class="keyword">attribute</span> <span class="keyword type">vec2</span> <span class="name">position</span><span class="punctuation">;</span>
<span class="keyword">attribute</span> <span class="keyword type">vec4</span> <span class="name">color</span><span class="punctuation">;</span>
<span class="keyword">varying</span> <span class="keyword type">vec4</span> <span class="name">v_color</span><span class="punctuation">;</span>
<span class="keyword type">void</span> <span class="name">main</span><span class="punctuation">()</span>
<span class="punctuation">{</span>
<span class="name builtin">gl_Position</span> <span class="operator">=</span> <span class="keyword type">vec4</span><span class="punctuation">(</span><span class="name">position</span><span class="operator">*</span><span class="name">scale</span><span class="punctuation">,</span> <span class="literal number float">0.0</span><span class="punctuation">,</span> <span class="literal number float">1.0</span><span class="punctuation">);</span>
<span class="name">v_color</span> <span class="operator">=</span> <span class="name">color</span><span class="punctuation">;</span>
<span class="punctuation">}</span>
</pre>
<p>and then in the fragment shader, we write:</p>
<pre class="code glsl literal-block">
<span class="keyword">varying</span> <span class="keyword type">vec4</span> <span class="name">v_color</span><span class="punctuation">;</span>
<span class="keyword type">void</span> <span class="name">main</span><span class="punctuation">()</span>
<span class="punctuation">{</span>
<span class="name builtin">gl_FragColor</span> <span class="operator">=</span> <span class="name">v_color</span><span class="punctuation">;</span>
<span class="punctuation">}</span>
</pre>
<p>The question is what is the value of <code>v_color</code> inside the fragment shader ?
If you look at the figure that introduced the gl pipeline, we have 3 vertices
and 21 fragments. What is the color of each individual fragment ?</p>
<p>The answer is <em>the interpolation of all 3 vertices color</em>. This interpolation
is made using the distance of the fragment to each individual vertex. This is a
very important concept to understand. Any varying value is interpolated between
the vertices that compose the elementary item (mostly, line or triangle).</p>
<p>Ok, enough for now, we'll see an explicit example in the next chapter.</p>
</div>
</div>
<div class="section" id="state-of-the-union">
<h2><a class="toc-backref" href="#id5">State of the union</a></h2>
<p>Last, but not least, we need to access the OpenGL library from within Python
and we have mostly two solutions at our disposal. Either we use pure bindings
and we have to program everything (see next chapter) or we use an engine that
provides a lot of convenient functions that ease the development. We'll first
use the PyOpenGL bindings before using the <a class="reference external" href="http://glumpy.github.io">glumpy</a> library that offers a tight
integration with numpy.</p>
<div class="section" id="bindings">
<h3><a class="toc-backref" href="#id5">Bindings</a></h3>
<ul class="simple">
<li><a class="reference external" href="https://bitbucket.org/pyglet/pyglet/wiki/Home">Pyglet</a> is a pure python cross-platform application framework intended for
game development. It supports windowing, user interface event handling,
OpenGL graphics, loading images and videos and playing sounds and music. It
works on Windows, OS X and Linux.</li>
<li><a class="reference external" href="http://pyopengl.sourceforge.net">PyOpenGL</a> is the most common cross platform Python binding to OpenGL and
related APIs. The binding is created using the standard ctypes library, and
is provided under an extremely liberal BSD-style Open-Source license.</li>
<li><a class="reference external" href="https://moderngl.readthedocs.io/en/stable/">ModernGL</a> is a wrapper over OpenGL that simplifies the creation of simple
graphics applications like scientific simulations, small games or user
interfaces. Usually, acquiring in-depth knowledge of OpenGL requires a steep
learning curve. In contrast, ModernGL is easy to learn and use, moreover it
is capable of rendering with the same performance and quality, with less code
written.</li>
<li><a class="reference external" href="https://docs.python.org/3/library/ctypes.html">Ctypes</a> bindings can also be generated quite easily thanks to the <a class="reference external" href="https://github.com/KhronosGroup/OpenGL-Registry/blob/master/xml/gl.xml">gl.xml</a>
file provided by the Khronos group that defines the OpenGL and OpenGL API
Registry. The number of functions and constants given in the table above have
been computed using the <a class="reference external" href="code/chapter-02/registry.py">code/chapter-02/registry.py</a> program that parses
the gl.xml file for each API and version and count the relevant features.</li>
</ul>
</div>
<div class="section" id="engines">
<h3><a class="toc-backref" href="#id5">Engines</a></h3>
<ul class="simple">
<li>The Visualization Toolkit (<a class="reference external" href="http://www.vtk.org">VTK</a>) is an open-source, freely available
software system for 3D computer graphics, image processing, and
visualization. It consists of a C++ class library and several interpreted
interface layers including Tcl/Tk, Java, and Python.</li>
<li><a class="reference external" href="http://py.processing.org">Processing</a> is a programming language, development environment, and online
community. Since 2001, Processing has promoted software literacy within the
visual arts and visual literacy within technology. Today, there are tens of
thousands of students, artists, designers, researchers, and hobbyists who use
Processing for learning, prototyping, and production.</li>
<li><a class="reference external" href="http://www.cityinabottle.org/nodebox/">NodeBox</a> for OpenGL is a free, cross-platform library for generating 2D
animations with Python programming code. It is built on Pyglet and adopts the
drawing API from NodeBox for Mac OS X. It has built-in support for paths,
layers, motion tweening, hardware-accelerated image effects, simple physics
and interactivity.</li>
<li><a class="reference external" href="http://www.panda3d.org/">Panda3D</a> is a 3D engine: a library of subroutines for 3D rendering and game
development. The library is C++ with a set of Python bindings. Game
development with Panda3D usually consists of writing a Python or C++ program
that controls the Panda3D library.</li>
<li><a class="reference external" href="http://vpython.org">VPython</a> makes it easy to create navigable 3D displays and animations, even
for those with limited programming experience. Because it is based on Python,
it also has much to offer for experienced programmers and researchers.</li>
</ul>
</div>
<div class="section" id="libraries">
<h3><a class="toc-backref" href="#id5">Libraries</a></h3>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Even though glumpy and vispy share a number of concepts, they are different.
vispy offers a high-level interface that may be convenient in some
situations but this tends to hide the internal machinery. This is one of the
reasons we'll be using glumpy instead (the other reason being that I'm the
author of glumpy (and one of the authors of vispy as well in fact)).</p>
</div>
<ul class="simple">
<li><a class="reference external" href="http://glumpy.github.io">Glumpy</a> is a python library for scientific visualization that is both fast,
scalable and beautiful. Glumpy leverages the computational power of modern
Graphics Processing Units (GPUs) through the OpenGL library to display very
large datasets and offers an intuitive interface between numpy and modern
OpenGL. We'll use it extensively in this book.</li>
<li><a class="reference external" href="http://vispy.org">Vispy</a> is the sister project of glumpy. It is a high-performance
interactive 2D/3D data visualization library and offer a high-level interface
for scientific visualization. The difference between glumpy and vispy is
approximately the same as the difference between numpy and scipy even though
vispy is independent of glumpy and vice-versa.</li>
</ul>
<!-- - - - Links - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
</div>
</div>
</div>
<div class="section" id="quickstart">
<h1><a class="toc-backref" href="#contents">Quickstart</a></h1>
<div class="contents toc chapter-03 local topic" id="id7">
<p class="topic-title first">.</p>
<ul class="simple">
<li><a class="reference internal" href="#preliminaries" id="id138">Preliminaries</a><ul>
<li><a class="reference internal" href="#normalize-device-coordinates" id="id139">Normalize Device Coordinates</a></li>
<li><a class="reference internal" href="#triangulation" id="id140">Triangulation</a></li>
<li><a class="reference internal" href="#gl-primitives" id="id141">GL Primitives</a></li>
<li><a class="reference internal" href="#interpolation" id="id142">Interpolation</a></li>
</ul>
</li>
<li><a class="reference internal" href="#the-hard-way" id="id143">The hard way</a><ul>
<li><a class="reference internal" href="#writing-shaders" id="id144">Writing shaders</a></li>
<li><a class="reference internal" href="#compiling-the-program" id="id145">Compiling the program</a></li>
<li><a class="reference internal" href="#uploading-data-to-the-gpu" id="id146">Uploading data to the GPU</a></li>
<li><a class="reference internal" href="#rendering" id="id147">Rendering</a></li>
<li><a class="reference internal" href="#uniform-color" id="id148">Uniform color</a></li>
<li><a class="reference internal" href="#varying-color" id="id149">Varying color</a></li>
</ul>
</li>
<li><a class="reference internal" href="#the-easy-way" id="id150">The easy way</a><ul>
<li><a class="reference internal" href="#id9" id="id151">Uniform color</a></li>
<li><a class="reference internal" href="#id10" id="id152">Varying color</a></li>
</ul>
</li>
<li><a class="reference internal" href="#exercises" id="id153">Exercises</a></li>
</ul>
</div>
<p>For the <strong>really</strong> impatient, you can try to run the code in the <a class="reference external" href="code/chapter-03/glumpy-quad-solid.py">teaser image</a> above. If this works, a window should
open on your desktop with a red color in the background. If you now want to
understand how this works, you'll have to read the text below.</p>
<div class="section" id="preliminaries">
<h2><a class="toc-backref" href="#id7">Preliminaries</a></h2>
<p>The main difficulty for newcomers in programming modern OpenGL is that it
requires to understand a lot of different concepts at once and then, to perform
a lot of operations before rendering anything on screen. This complexity
implies that there are many places where your code can be wrong, both at the
conceptual and code level. To illustrate this difficulty, we'll program our
first OpenGL program using the raw interface and our goal is to display a
simple colored quad (i.e. a red square).</p>
<div class="section" id="normalize-device-coordinates">
<h3><a class="toc-backref" href="#id7">Normalize Device Coordinates</a></h3>
<div class="right figure" id="figure-images/chapter-03/NDC.png" style="width: 40%">
<img alt="images/chapter-03/NDC.png" src="images/chapter-03/NDC.png" />
<p class="caption">Figure</p>
<div class="legend">
Normalized Device Coordinates (NDC) where bottom-left corner coordinate is
(-1,-1) and top-right corner is (+1,+1).</div>
</div>
<p>Before even diving into actual code, it is important to understand first how
OpenGL handles coordinates. More precisely, OpenGL considers only coordinates
<code>(x,y,z)</code> that fall into the space where <code>-1 ≤ x,y,z ≤ +1</code>. Any coordinates
that are outside this range will be discarded or clipped (i.e. won't be visible
on screen). This is called Normalized Device Coordinates, or NDC for short.
This is something you cannot change because it is part of the OpenGL API and
implemented in your hardware (GPU). Consequently, even if you intend to render
the whole universe, you'll have utlimately to fit it into this small volume.</p>
<p>The second important fact to know is that <strong>x</strong> coordinates increase from left
to right and <strong>y</strong> coordinates increase from bottom to top. For this latter
one, it is noticeably different from the usual convention and this might induce
some problems, especially when you're dealing with the mouse pointer whose
<strong>y</strong> coordinate goes the other way around.</p>
</div>
<div class="section" id="triangulation">
<h3><a class="toc-backref" href="#id7">Triangulation</a></h3>
<div class="right figure" id="figure-images/chapter-03/triangulation.png" style="width: 35%">
<img alt="images/chapter-03/triangulation.png" src="images/chapter-03/triangulation.png" />
<p class="caption">Figure</p>
<div class="legend">
Different triangulation of the same quad using from 2 to 5 triangles.</div>
</div>
<p><a class="reference external" href="https://en.wikipedia.org/wiki/Surface_triangulation">Triangulation</a> of a
surface means to find a set of triangles, which covers a given surface. This
can be a tedious process but fortunately, there exist many different methods
and algorithms to perform such triangulation automatically for any 2D or 3D
surface. The quality of the triangulation is measured in terms of the closeness
to the approximated surface, the number of triangles necessary (the smaller,
the better) and the homogeneity of the triangles (we prefer to have triangles
that have more or less the same size and to not have any degenerated triangle).</p>
<p>In our case, we want to render a square and we need to find the proper
triangulation (which is not unique as illustrated on the figure). Since we want
to minimize the number of triangles, we'll use the 2 triangles solution that
requires only 4 (shared) vertices corresponding to the four corners of the
quad. However, you can see from the figure that we could have used different
triangulations using more vertices, and later in this book we will just do that
(but for a reason).</p>
<p>Considering the NDC, our quad will thus be composed of two triangles:</p>
<ul class="simple">
<li>One triangle described by vertices <code>(-1,+1), (+1,+1), (-1,-1)</code></li>
<li>One triangle described by vertices <code>(+1,+1), (-1,-1), (+1,-1)</code></li>
</ul>
<p>Here we can see that vertices <code>(-1,-1)</code> and <code>(+1,+1)</code> are common to both triangles. So instead of using 6 vertices to describe the two triangles, we can
re-use the common vertices to describe the whole quad. Let's name them:</p>
<ul class="simple">
<li><code>V₀</code>: <code>(-1,+1)</code></li>
<li><code>V₁</code>: <code>(+1,+1)</code></li>
<li><code>V₂</code>: <code>(-1,-1)</code></li>
<li><code>V₃</code>: <code>(+1,-1)</code></li>
</ul>
<p>Our quad can now be using triangle <code>(V₀,V₁,V₂)</code> and triangle <code>(V₁,V₂,V₃)</code>. This
is exactly what we need to tell OpenGL.</p>
</div>
<div class="section" id="gl-primitives">
<h3><a class="toc-backref" href="#id7">GL Primitives</a></h3>
<div class="right figure" id="figure-images/chapter-03/gl-primitives.png" style="width: 40%">
<img alt="images/chapter-03/gl-primitives.png" src="images/chapter-03/gl-primitives.png" />
<p class="caption">Figure</p>
<div class="legend">
Common OpenGL rendering primitives.</div>
</div>
<p>Ok, now things are getting serious because we need to actually tell OpenGL what
to do with the vertices, i.e. how to render them? What do they describe in terms
of geometrical primitives? This is quite an important topic since this will
determine how fragments will actually be generated as illustrated on the image
below:</p>
<p>Mostly, OpenGL knows how to draw (ugly) points, (ugly) lines and (ugly)
triangles. For lines and triangles, there exist some variations depending if
you want to specify very precisely what to draw or if you can take advantage of
some implicit assumptions. Let's consider lines first for example. Given a set
of four vertices <code>(V₀,V₁,V₂,V₃)</code>, you migh want to draw segments
<code>(V₀,V₁)``(V₂,V₃)</code> using <code>GL_LINES</code> or a broken line <code>(V₀,V₁,V₂,V₃)</code> using
using <code>GL_LINE_STRIP</code> or a closed broken line <code>(V₀,V₁,V₂,V₃,V₀,)</code> using
<code>GL_LINE_LOOP</code>. For triangles, you have the choices of specifying each triangle
individually using <code>GL_TRIANGLES</code> or you can tell OpenGL that triangles follow
an implicit structure using <code>GL_TRIANGLE_STRIP</code>. For example, considering a set
of vertices (Vᵢ), <code>GL_TRIANGLE_STRIP</code> will produce triangles <code>(Vᵢ,Vᵢ₊₁,Vᵢ₊₂)</code>.
There exist other primitives but we won't used them in this book because
they're mainly related to <em>geometry shaders</em> that are not introduced.</p>
<p>If you remember the previous section where we explained that our quad can be
described using using triangle <code>(V₀,V₁,V₂)</code> and triangle <code>(V₁,V₂,V₃)</code>, you can
now realize that we can take advantage or the <code>GL_TRIANGLE_STRIP</code> primitive
because we took care of describing the two triangles following this implicit
structure.</p>
</div>
<div class="section" id="interpolation">
<h3><a class="toc-backref" href="#id7">Interpolation</a></h3>
<div class="right figure" id="figure-images/chapter-03/interpolation.png" style="width: 40%">
<img alt="images/chapter-03/interpolation.png" src="images/chapter-03/interpolation.png" />
<p class="caption">Figure</p>
<div class="legend">
The Barycentric interpolation <code>f</code> of a fragment <code>p</code> is given by <code>f = 𝛌₁f₁ +
𝛌₂f₂ + 𝛌₃f₃</code></div>
</div>
<p>The choice of the triangle as the only surface primitive is not an arbitrary
choice, because a triangle offers the possibility of having a nice and intuitive
interpolation of any point that is inside the triangle. If you look back at
the graphic pipeline as it has been introduced in the <a class="reference internal" href="#modern-opengl">Modern OpenGL</a> section,
you can see that the rasterisation requires for OpenGL to generate fragments
inside the triangle but also to interpolate values (colors on the figure). One
of the legitimate questions to be solved is then: if I have a triangle
(V₁,V₂,V₃), each summit vertex having (for example) a different color, what is
the color of a fragment <code>p</code> inside the triangle? The answer is <a class="reference external" href="https://en.wikibooks.org/wiki/GLSL_Programming/Rasterization">barycentric
interpolation</a>
as illustrated on the figure on the right.</p>
<p>More precisely, for any point p inside a triangle <code>A = (V₁,V₂,V₃)</code>, we consider
triangles:</p>
<ul class="simple">
<li><code>A₁ = (P,V₂,V₃)</code></li>
<li><code>A₂ = (P,V₁,V₃)</code></li>
<li><code>A₃ = (P,V₁,V₂)</code></li>
</ul>
<p>And we can define (using area of triangles):</p>
<ul class="simple">
<li><code>𝛌₁ = A₁/A</code></li>
<li><code>𝛌₂ = A₂/A</code></li>
<li><code>𝛌₃ = A₃/A</code></li>
</ul>
<p>Now, if we attach a value <code>f₁</code> to vertex <code>V₁</code>, <code>f₂</code> to vertex <code>V₂</code> and <code>f₃</code> to
vertex <code>V₃</code>, the interpolated value <code>f</code> of <code>p</code> is given by: <code>f = 𝛌₁f₁ + 𝛌₂f₂ +
𝛌₃f₃</code> You can check by yourself that if the point <code>p</code> is on a border of the
triangle, the resulting interpolated value <code>f</code> is the linear interpolation of
the two vertices defining the segment the point <code>p</code> belongs to.</p>
<p>This <strong>barycentric interpolation is important to understand</strong> even if it is done
automatically by OpenGL (with some variation to take projection into
account). We took the example of colors, but the same interpolation scheme
holds true for any value you pass from the vertex shader to the fragment
shader. And this property will be used and abused in this book.</p>
</div>
</div>
<div class="section" id="the-hard-way">
<h2><a class="toc-backref" href="#id7">The hard way</a></h2>
<p>Having reviewed some important OpenGL concepts, it's time to code our quad
example. But, before even using OpenGL, we need to open a window with a valid GL
context. This can be done using a toolkit such as <a class="reference external" href="https://www.gtk.org">Gtk</a>, <a class="reference external" href="https://www.qt.io">Qt</a> or <a class="reference external" href="https://www.wxwidgets.org">Wx</a> or any native
toolkit (Windows, Linux, OSX). Unfortunately, the <a class="reference external" href="https://docs.python.org/3/library/tk.html">Tk</a> Python interface does not
allow to create a GL context and we cannot use it. Note there also exists
dedicated toolkits such as <a class="reference external" href="http://www.glfw.org">GLFW</a> or <a class="reference external" href="http://freeglut.sourceforge.net">GLUT</a> and the advantage of GLUT is that
it's already installed alongside OpenGL. Even if it is now deprecated, we'll
use GLUT since it's a very lightweight toolkit and does not require any extra
package. Here is a minimal setup that should open a window with a black background.</p>
<pre class="code python literal-block">
<span class="keyword namespace">import</span> <span class="name namespace">sys</span>
<span class="keyword namespace">import</span> <span class="name namespace">OpenGL.GL</span> <span class="keyword namespace">as</span> <span class="name namespace">gl</span>
<span class="keyword namespace">import</span> <span class="name namespace">OpenGL.GLUT</span> <span class="keyword namespace">as</span> <span class="name namespace">glut</span>
<span class="keyword">def</span> <span class="name function">display</span><span class="punctuation">():</span>
<span class="name">gl</span><span class="operator">.</span><span class="name">glClear</span><span class="punctuation">(</span><span class="name">gl</span><span class="operator">.</span><span class="name">GL_COLOR_BUFFER_BIT</span><span class="punctuation">)</span>