-
Notifications
You must be signed in to change notification settings - Fork 0
/
modern-gl.html
431 lines (400 loc) · 23.8 KB
/
modern-gl.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
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Modern OpenGL</title>
<link rel="stylesheet" href="_static/basic.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/bootswatch-3.3.4/cosmo/bootstrap.min.css" type="text/css" />
<link rel="stylesheet" href="_static/bootstrap-sphinx.css" type="text/css" />
<link rel="stylesheet" href="_static/css/font-mfizz.css" type="text/css" />
<link rel="stylesheet" href="_static/css/font-awesome.css" type="text/css" />
<link rel="stylesheet" href="_static/style.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/js/jquery-1.11.0.min.js"></script>
<script type="text/javascript" src="_static/js/jquery-fix.js"></script>
<script type="text/javascript" src="_static/bootstrap-3.3.4/js/bootstrap.min.js"></script>
<script type="text/javascript" src="_static/bootstrap-sphinx.js"></script>
<link rel="shortcut icon" href="_static/favicon.ico"/>
<link rel="top" title="" href="index.html" />
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge,chrome=1'>
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1'>
<meta name="apple-mobile-web-app-capable" content="yes">
</head>
<body role="document">
<div id="navbar" class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<!-- .btn-navbar is used as the toggle for collapsed navbar content -->
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="index.html"><img src="_static/glumpy-text-white.png">
</a>
<span class="navbar-text navbar-version pull-left"><b></b></span>
</div>
<div class="collapse navbar-collapse nav-collapse">
<ul class="nav navbar-nav">
<li class="divider-vertical"></li>
<li><a href="http://glumpy.readthedocs.org/en/latest/">Documentation</a></li>
<li><a href="gallery.html">Gallery</a></li>
<li><a href="resources.html">Resources</a></li>
<li><a href="community.html">Community</a></li>
<li><a href="news.html">News</a></li>
<li class="dropdown globaltoc-container">
<a role="button"
id="dLabelGlobalToc"
data-toggle="dropdown"
data-target="#"
href="index.html">Site <b class="caret"></b></a>
<ul class="dropdown-menu globaltoc"
role="menu"
aria-labelledby="dLabelGlobalToc"></ul>
</li>
</ul>
<!--
<form class="navbar-form navbar-right" action="search.html" method="get">
<div class="form-group">
<input type="text" name="q" class="form-control" placeholder="Search" />
</div>
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
-->
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-3">
<div id="sidebar" class="bs-sidenav" role="complementary"><ul>
<li><a class="reference internal" href="#">Modern OpenGL</a><ul>
<li><a class="reference internal" href="#shaders">Shaders</a></li>
<li><a class="reference internal" href="#buffers">Buffers</a></li>
<li><a class="reference internal" href="#uniform-attribute-varying">Uniform, attribute, varying</a></li>
<li><a class="reference internal" href="#transformations">Transformations</a><ul>
<li><a class="reference internal" href="#projection-matrix">Projection matrix</a></li>
<li><a class="reference internal" href="#model-and-view-matrices">Model and view matrices</a></li>
</ul>
</li>
<li><a class="reference internal" href="#learning-modern-opengl">Learning modern OpenGL</a><ul>
<li><a class="reference internal" href="#an-intro-to-modern-opengl">An intro to modern OpenGL</a></li>
<li><a class="reference internal" href="#learning-modern-3d-graphics-programming">Learning Modern 3D Graphics Programming</a></li>
<li><a class="reference internal" href="#opengl-es-2-0-documentation">OpenGL ES 2.0 documentation</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<form action="search.html" method="get">
<div class="form-group">
<input type="text" name="q" class="form-control" placeholder="Search" />
</div>
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div>
<div class="col-md-9 content">
<div class="section" id="modern-opengl">
<h1>Modern OpenGL<a class="headerlink" href="#modern-opengl" title="Permalink to this headline">¶</a></h1>
<p>OpenGL has evolved over the years and a big change occured in 2003 with the
introduction of the dynamic pipeline (OpenGL 2.0), i.e. the use of shaders that
allow to have direct access to the GPU.</p>
<img alt="_images/gl-history.png" src="_images/gl-history.png" />
<p>Before this version, OpenGL was using a fixed pipeline and you may still find a
lot of tutorials that still use this fixed pipeline. This introduces some
radical changes in the way of programming OpenGL and makes it both more
difficult to program but far more powerful.</p>
<div class="section" id="shaders">
<h2>Shaders<a class="headerlink" href="#shaders" title="Permalink to this headline">¶</a></h2>
<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 subsequents version get the number of OpenGL version. Last version
is 4.4 (February 2014).</p>
</div>
<p>Shaders are pieces of program (using a C-like language) that are build 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> shader as shown below:</p>
<img alt="_images/gl-pipeline.png" src="_images/gl-pipeline.png" />
<p>A vertex shader acts on vertices and is supposed to output the vertex
<strong>position</strong> (→ <code class="docutils literal"><span class="pre">gl_Position</span></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 class="docutils literal"><span class="pre">gl_FragColor</span></code>) of the fragment. Hence, a minimal vertex shader is:</p>
<div class="highlight-python"><div class="highlight"><pre>void main()
{
gl_Position = vec4(0.0,0.0,0.0,1.0);
}
</pre></div>
</div>
<p>while a minimal fragment shader would be:</p>
<div class="highlight-python"><div class="highlight"><pre>void main()
{
gl_FragColor = vec4(0.0,0.0,0.0,1.0);
}
</pre></div>
</div>
<p>These two shaders are not very useful since the first will transform any
vertex into the null vertex while the second will output the black color for
any fragment. We'll see later how to make them to do more useful things.</p>
<p>One question remains: when are those shaders exectuted exactly ? The vertex
shader is executed for each vertex that is given to the rendering pipeline
(we'll see what does that mean exactly later) and the fragment shader is
executed on each fragment 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 (pixel).</p>
</div>
<div class="section" id="buffers">
<h2>Buffers<a class="headerlink" href="#buffers" title="Permalink to this headline">¶</a></h2>
<p>We explained earlier that the vertex shader act on the vertices. The question
is thus where do those vertices comes from ? The idea of modern GL is that
vertices are stored on the GPU and needs to be uploaded (only once) to the GPU
before rendering. The way to do that is to build buffers onto the CPU and to
send them onto the GPU. If your data does not change, no need to upload it
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 many 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. Now you're on your own...</p>
<ul class="simple">
<li><strong>Good news</strong> is that you're now free to do virtually anything you want.</li>
<li><strong>Bad news</strong> is that you have to program everything, even the most basic
things like projection and lighting.</li>
</ul>
<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 the <a class="reference external" href="http://www.numpy.org">numpy</a> library:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">data</span> <span class="o">=</span> <span class="n">numpy</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="n">dtype</span> <span class="o">=</span> <span class="p">[</span> <span class="p">(</span><span class="s">"position"</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">float32</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span>
<span class="p">(</span><span class="s">"color"</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">float32</span><span class="p">,</span> <span class="mi">4</span><span class="p">)]</span> <span class="p">)</span>
</pre></div>
</div>
<p>We just created a CPU buffer with 4 vertices, each of them having a
<code class="docutils literal"><span class="pre">position</span></code> (3 floats for x,y,z coordinates) and a <code class="docutils literal"><span class="pre">color</span></code> (4 floats for
red, blue, green and alpha channels). Note that we explicitely chose to have 3
coordinates for <code class="docutils literal"><span class="pre">position</span></code> but we may have chosen to have only 2 if were to
work in two-dimensions only. Same holds true for <code class="docutils literal"><span class="pre">color</span></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 you data size grows up to
one or ten million vertices.</p>
</div>
<div class="section" id="uniform-attribute-varying">
<h2>Uniform, attribute, varying<a class="headerlink" href="#uniform-attribute-varying" title="Permalink to this headline">¶</a></h2>
<p>At this point in the tutorial, we know what are shaders and buffers but we
still need to explain how they may be connected together. So, let's consider
again our CPU buffer:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">data</span> <span class="o">=</span> <span class="n">numpy</span><span class="o">.</span><span class="n">zeros</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="n">dtype</span> <span class="o">=</span> <span class="p">[</span> <span class="p">(</span><span class="s">"position"</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">float32</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span>
<span class="p">(</span><span class="s">"color"</span><span class="p">,</span> <span class="n">np</span><span class="o">.</span><span class="n">float32</span><span class="p">,</span> <span class="mi">4</span><span class="p">)]</span> <span class="p">)</span>
</pre></div>
</div>
<p>We need to tell the vertex shader that it will have to handle vertices where a
position is a tuple of 3 floats and color is a tuple of 4 floats. This is
precisely what attributes are meant for. Let us change slightly our previous
vertex shader:</p>
<div class="highlight-python"><div class="highlight"><pre>attribute vec2 position;
attribute vec4 color;
void main()
{
gl_Position = vec4(position, 0.0, 1.0);
}
</pre></div>
</div>
<p>This vertex shader now expects a vertex to possess 2 attributes, one named
<code class="docutils literal"><span class="pre">position</span></code> and one named <code class="docutils literal"><span class="pre">color</span></code> with specified types (vec3 means tuple of
3 floats and vec4 means tuple of 4 floats). It is important to note that even
if we labeled the first attribute <code class="docutils literal"><span class="pre">position</span></code>, this attribute is not yet bound
to the actual <code class="docutils literal"><span class="pre">position</span></code> in the numpy array. We'll need to do it explicitly
at some point in our program and there is no automagic 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 are the uniforms
that may be considered as constant values (across all the vertices). Let's say
for example we want to scale all the vertices by a constant factor <code class="docutils literal"><span class="pre">scale</span></code>,
we would thus write:</p>
<div class="highlight-python"><div class="highlight"><pre>uniform float scale;
attribute vec2 position;
attribute vec4 color;
void main()
{
gl_Position = vec4(position*scale, 0.0, 1.0);
}
</pre></div>
</div>
<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>
<div class="highlight-python"><div class="highlight"><pre>uniform float scale;
attribute vec2 position;
attribute vec4 color;
varying vec4 v_color;
void main()
{
gl_Position = vec4(position*scale, 0.0, 1.0);
v_color = color;
}
</pre></div>
</div>
<p>and then in the fragment shader, we write:</p>
<div class="highlight-python"><div class="highlight"><pre>varying vec4 v_color;
void main()
{
gl_FragColor = v_color;
}
</pre></div>
</div>
<p>The question is what is the value of <code class="docutils literal"><span class="pre">v_color</span></code> inside the fragment shader ?
If you look at the figure that introduced the gl pipleline, 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 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>
</div>
<div class="section" id="transformations">
<h2>Transformations<a class="headerlink" href="#transformations" title="Permalink to this headline">¶</a></h2>
<div class="section" id="projection-matrix">
<h3>Projection matrix<a class="headerlink" href="#projection-matrix" title="Permalink to this headline">¶</a></h3>
<p>We need first to define what do we want to view, that is, we need to define a
viewing volume such that any object within the volume (even partially) will be
rendered while objects outside won't. On the image below, the yellow and red
spheres are within the volume while the green one is not and does not appear on
the projection.</p>
<img alt="_images/ViewFrustum.png" src="_images/ViewFrustum.png" />
<p>There exist many different ways to project a 3D volume onto a 2D screen but
we'll only use the <a class="reference external" href="https://en.wikipedia.org/wiki/Perspective_(graphical)">perspective projection</a> (distant objects
appear smaller) and the <a class="reference external" href="https://en.wikipedia.org/wiki/Orthographic_projection_(geometry)">orthographic projection</a> which is a
parallel projection (distant objects have the same size as closer ones) as
illustrated on the image above. Until now (previous section), we have been
using implicitly an orthographic projection in the z=0 plane.</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">In older versions of OpenGL, these matrices were available as <a class="reference external" href="https://www.opengl.org/sdk/docs/man2/xhtml/glFrustum.xml">glFrustum</a> and <a class="reference external" href="https://www.opengl.org/sdk/docs/man2/xhtml/glOrtho.xml">glOrtho</a>.</p>
</div>
<p>Depending on the projection we want, we will use one of the two projection matrices
below:</p>
<p><strong>Perspective matrix</strong></p>
<img alt="_images/frustum-matrix.png" src="_images/frustum-matrix.png" />
<p><strong>Orthographic matrix</strong></p>
<img alt="_images/ortho-matrix.png" src="_images/ortho-matrix.png" />
<p>At this point, it is not necessary to understand how these matrices were built.
Suffice it to say they are standard matrices in the 3D world. Both suppose the
viewer (=camera) is located at position (0,0,0) and is looking in the direction
(0,0,1).</p>
<p>There exists a second form of the perpective matrix that might be easier to
manipulate. Instead of specifying the right/left/top/bottom planes, we'll use
field of view in the horizontal and vertical direction:</p>
<p><strong>Perspective matrix</strong></p>
<img alt="_images/perspective-matrix.png" src="_images/perspective-matrix.png" />
<p>where <code class="docutils literal"><span class="pre">fovy</span></code> specifies the field of view angle, in degrees, in the y
direction and <code class="docutils literal"><span class="pre">aspect</span></code> specifies the aspect ratio that determines the field
of view in the x direction.</p>
</div>
<div class="section" id="model-and-view-matrices">
<h3>Model and view matrices<a class="headerlink" href="#model-and-view-matrices" title="Permalink to this headline">¶</a></h3>
<p>We are almost done with matrices. You may have guessed that the above matrix
requires the viewing volume to be in the z direction. We could design our 3D
scene such that all objects are withing this direction but it would not be very
convenient. So instead, we'll use a view matrix that will map the the world
space to camera space. This is pretty much as if we were orienting the camera
at a given position and look toward a given direction. In the meantime, we can
further refine the whole pipeline by providing a model matrix that will maps
the object's local coordinate space into world space. For example, this wil be
useful for rotating an object around its center. To sum up, we need:</p>
<ul class="simple">
<li><strong>Model matrix</strong> maps from an object's local coordinate space into world space</li>
<li><strong>View matrix</strong> maps from world space to camera space</li>
<li><strong>Projection matrix</strong> maps from camera to screen space</li>
</ul>
</div>
</div>
<div class="section" id="learning-modern-opengl">
<h2>Learning modern OpenGL<a class="headerlink" href="#learning-modern-opengl" title="Permalink to this headline">¶</a></h2>
<p>There exist a lot of resources on the web related to OpenGL. I only mention
here a few of them that deals with the dynamic rendering pipeline. If you've
found other resources, make sure they deal with the dynamic rendering pipeline
and not the fixed one.</p>
<div class="section" id="an-intro-to-modern-opengl">
<h3>An intro to modern OpenGL<a class="headerlink" href="#an-intro-to-modern-opengl" title="Permalink to this headline">¶</a></h3>
<p>OpenGL has been around a long time, and from reading all the accumulated layers
of documentation out there on the Internet, it's not always clear what parts
are historic and what parts are still useful and supported on modern graphics
hardware. It's about time for a new OpenGL <a class="reference external" href="http://duriansoftware.com/joe/An-intro-to-modern-OpenGL.-Table-of-Contents.html">introduction that</a>
walks through the parts that are still relevant today.</p>
</div>
<div class="section" id="learning-modern-3d-graphics-programming">
<h3>Learning Modern 3D Graphics Programming<a class="headerlink" href="#learning-modern-3d-graphics-programming" title="Permalink to this headline">¶</a></h3>
<p>This <a class="reference external" href="http://www.arcsynthesis.org/gltut/">book</a> is intended to teach you how
to be a graphics programmer. It is not aimed at any particular graphics field;
it is designed to cover most of the basics of 3D rendering. So if you want to
be a game developer, a CAD program designer, do some computer visualization, or
any number of things, this book can still be an asset for you. This does not
mean that it covers everything there is about 3D graphics. Hardly. It tries to
provide a sound foundation for your further exploration in whatever field of 3D
graphics you are interested in.</p>
</div>
<div class="section" id="opengl-es-2-0-documentation">
<h3>OpenGL ES 2.0 documentation<a class="headerlink" href="#opengl-es-2-0-documentation" title="Permalink to this headline">¶</a></h3>
<p><a class="reference external" href="https://www.khronos.org/opengles/2_X/">OpenGL ES 2.0</a> is defined relative to
the OpenGL 2.0 specification and emphasizes a programmable 3D graphics pipeline
with the ability to create shader and program objects and the ability to write
vertex and fragment shaders in the OpenGL ES Shading Language. Vispy is based
on OpenGL ES 2.0 because it give access to the programmable pipeline while
keeping overall complexity tractable.</p>
</div>
</div>
</div>
</div>
</div>
</div>
<footer class="footer">
<div class="container">
<ul class="list-inline">
<li><a href="https://github.com/glumpy/glumpy">GitHub</a></li>
<li>·</li>
<li><a href=""><a href="https://github.com/glumpy/glumpy/blob/master/examples/README.rst">Examples</a></li>
<li>·</li>
<li><a href="https://github.com/glumpy/glumpy/issues">Issues</a></li>
<li>·</li>
<li><a href="">Changelog</a></li>
<li>·</li>
<li><a href="https://github.com/glumpy/glumpy/releases">Releases</a></li>
<li class="pull-right"><a href="#">Back to top</a></li>
</ul>
<ul class="list-unstyled small">
<li>Copyright (c) 2011-2016 Nicolas P. Rougier</li>
<li>Code licensed under
<a href="http://opensource.org/licenses/BSD-2-Clause">BSD license</a>,
documentation under <a href="http://creativecommons.org/licenses/by/3.0/">CC BY 3.0 </a>
</li>
<li>
Made with <a href="http://sphinx-doc.org">sphinx</a> using the excellent
<a href="https://github.com/ryan-roemer/sphinx-bootstrap-theme">bootstrap theme</a>
</li>
</ul>
</div>
</footer>
</body>
</html>