Subversion Repositories gelsvn

Rev

Rev 405 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 405 Rev 465
Line 13... Line 13...
13
            linkcolor=blue
13
            linkcolor=blue
14
           ]{hyperref}
14
           ]{hyperref}
15
\makeindex
15
\makeindex
16
\lstset{tabsize=1,language=C++,basicstyle=\small}
16
\lstset{tabsize=1,language=C++,basicstyle=\small}
17
\author{J. Andreas B{\ae}rentzen}
17
\author{J. Andreas B{\ae}rentzen}
18
\title{Introduction to GEL}
18
\title{Introduction to GEL\\\vspace{0.25cm} \normalsize
-
 
19
\textit{An informal introduction to the GEL library with many examples of usage}.}
19
\setcounter{tocdepth}{2}
20
\setcounter{tocdepth}{2}
20
\begin{document}
21
\begin{document}
21
\maketitle
22
\maketitle
22
\tableofcontents
23
\tableofcontents
23
\section{Introduction}
24
\newpage\section{Introduction}
24
 
25
 
25
GEL is an abbreviation of GEometry and Linear algebra. GEL is a C++ library with tools for manipulating digital representations of geometry such as polygonal meshes, triangle meshes, point clouds, and voxel grids. Since linear algebra tools are invariably needed for this, GEL also contains tools for linear algebra. Finally, GEL contains tools for drawing geometry using OpenGL and various utilities.
26
GEL is an abbreviation of GEometry and Linear algebra. GEL is a C++ library with tools for manipulating digital representations of geometry such as polygonal meshes, triangle meshes, point clouds, and voxel grids. Since linear algebra tools are invariably needed for this, GEL also contains tools for linear algebra. Finally, GEL contains tools for drawing geometry using OpenGL and various utilities.
26
 
27
 
27
\subsection{GEL Homepage}
28
\subsection{GEL Homepage}
28
The online home of GEL is here:
29
The online home of GEL is here:
29
\href{http://www.imm.dtu.dk/GEL/}{http://www.imm.dtu.dk/GEL/}
30
\href{http://www.imm.dtu.dk/GEL/}{http://www.imm.dtu.dk/GEL/}
30
 
31
 
31
\subsection{Purpose of this document}
32
\subsection{Purpose of this document}
32
GEL is not sufficiently documented, but a fair amount of Doxygen documentation is provided for those parts of GEL which are used a lot. The goal of this document is to provide more detail and to help people getting started. In particular, this document focuses on functionality in the CGLA and HMesh namespaces.
33
GEL is not sufficiently documented, but a fair amount of Doxygen documentation is provided for those parts of GEL which are used a lot. The goal of this document is to provide more detail and to help people getting started. In particular, this document focuses on functionality in the CGLA and HMesh namespaces, but we shall also take a look at some other parts of GEL. Unfortunately, it is rather difficult to be complete: There is functionality in GEL not covered here. Consequently, if you are looking for something particular, we \textbf{entreat }you to look at the Doxygen web (start at the GEL homepage). Most functions and classes are in fact described in the auto-generated documentation.
33
 
-
 
34
However, if you are looking for something particular, we \textbf{implore and entreat }you to look at the Doxygen web (start at the GEL homepage).
-
 
35
 
34
 
36
\subsection{Overview of GEL}
35
\subsection{Overview of GEL}
37
 
36
 
38
GEL contains many tools for geometry processing and a number of data structures. Perhaps the most important is the Manifold class which resides in the HMesh namespace. A Manifold is a halfedge based representation of a polygonal mesh. There is also a simpler triangle mesh data structure, TriMesh, based on an indexed face set. There are several voxel grid data structures, a fairly efficient k-D tree for storing points, bounding box hierarchies etc.
37
GEL contains many tools for geometry processing and a number of data structures. Perhaps the most important is the Manifold class which resides in the HMesh namespace. A Manifold is a halfedge based representation of a polygonal mesh. There is also a simpler triangle mesh data structure, TriMesh, based on an indexed face set. There are several voxel grid data structures, a fairly efficient k-D tree for storing points, bounding box hierarchies etc.
39
 
38
 
40
A number of algorithms exist for manipulating these representations of geometric data. For instance, Manifold has a function quadratic error measures simplification, several functions for smoothing (including anisotropic), mesh optimization, and mesh clean up.
39
A number of algorithms exist for manipulating these representations of geometric data. For instance, Manifold has a function for mesh simplification, several functions for smoothing (including anisotropic), mesh optimization, and mesh clean up.
41
Another strong point of GEL is the fact that it contains good support for converting between representations; especially between meshes and voxel grids. There are several tools for polygonizing isosurfaces and also converting meshes to distance fields.  The tools pertaining to the Manifold data structure are in the HMesh namespace. The other geometry related tools are in the Geometry namespace.
40
Another strong point of GEL is the fact that it contains good support for converting between representations; especially between meshes and voxel grids. There are several tools for polygonizing isosurfaces and also converting meshes to distance fields.  The tools pertaining to the Manifold data structure are in the HMesh namespace. The other geometry related tools are in the Geometry namespace.
42
 
41
 
43
There are two packages for linear algebra: CGLA is strictly for small vectors and matrices (dimensions 2,3, and 4). LinAlg is a Lapack wrapper for slightly larger problems. At this point, it is fairly simple but includes a number of functions for solving linear systems, factoring matrices and finding eigensolutions for symmetric matrices.
42
There are two packages for linear algebra: CGLA is strictly for small vectors and matrices (dimensions 2,3, and 4). LinAlg is a Lapack wrapper for slightly larger problems. At this point, it is fairly simple but includes a number of functions for solving linear systems, factoring matrices and finding eigensolutions for symmetric matrices.
44
 
43
 
45
GLGraphics contains facilities for drawing entities from other parts of GEL via OpenGL. Especially TriMesh and Manifold have good support. For instance, there is a nice wireframe drawing class. There are also two virtual trackballs for interactive programs and some tools for viewing in interactive programs and SOIL a small open source library for image loading by Jonathan Dummer.
44
GLGraphics contains facilities for drawing entities from other parts of GEL via OpenGL. Especially TriMesh and Manifold have good support. For instance, there is a nice wireframe drawing class. There are also two virtual trackballs for interactive programs and some tools for viewing in interactive programs and SOIL a small open source library for image loading by Jonathan Dummer.
Line 70... Line 69...
70
 
69
 
71
\section{CGLA}
70
\section{CGLA}
72
 
71
 
73
CGLA is a set of numerical C++ vector and matrix classes and class
72
CGLA is a set of numerical C++ vector and matrix classes and class
74
templates designed with computer graphics in mind. CGLA stands for
73
templates designed with computer graphics in mind. CGLA stands for
75
``Computer Graphics Linear Algebra''. It is a part of the larger
-
 
76
package called GEL but deserves its own document since it is an  important part.
-
 
77
 
-
 
78
Let us get right down to the obvious question: Why create another
74
``Computer Graphics Linear Algebra''. Let us get right down to the obvious question: Why create another
79
linear algebra package?
75
linear algebra package?
80
Well, CGLA evolved from a few matrix and vector classes because I
76
Well, CGLA evolved from a few matrix and vector classes because I
81
didn't have anything better. Also, I created CGLA to experiment with
77
didn't have anything better. Also, I created CGLA to experiment with
82
some template programming techniques. This led to the most important
78
some template programming techniques. This led to the most important
83
feature of CGLA, namely the fact that all vector types are derived
79
feature of CGLA, namely the fact that all vector types are derived
Line 183... Line 179...
183
  Vec3f p2(10,20,10);
179
  Vec3f p2(10,20,10);
184
\end{verbatim}
180
\end{verbatim}
185
if we had left out the arguments the three vectors would have been
181
if we had left out the arguments the three vectors would have been
186
uninitialized, at least in release mode. If we compile in debug mode
182
uninitialized, at least in release mode. If we compile in debug mode
187
they would have been initialized to ``Not a Number'' to aid
183
they would have been initialized to ``Not a Number'' to aid
188
debugging. However, the $[10 10 10]^T$ vector could also have been
184
debugging. However, the $[10 \;10 \;10]^T$ vector could also have been
189
created differently, using
185
created differently, using
190
\begin{verbatim}
186
\begin{verbatim}
191
  Vec3f p0(10);
187
  Vec3f p0(10);
192
\end{verbatim}
188
\end{verbatim}
193
 
189
 
Line 391... Line 387...
391
p/= fc.no_steps();
387
p/= fc.no_steps();
392
\end{verbatim}
388
\end{verbatim}
393
 
389
 
394
Internally, both the vertex and face circulators simply keep track of a single halfedge. So \texttt{get\_vertex()} returns the vertex pointed to by that halfedge. There are similar functions for getting the halfedge itself, the face it points to or its opposite halfedge.
390
Internally, both the vertex and face circulators simply keep track of a single halfedge. So \texttt{get\_vertex()} returns the vertex pointed to by that halfedge. There are similar functions for getting the halfedge itself, the face it points to or its opposite halfedge.
395
 
391
 
396
Use circulators whenever you need to go around a face or vertex, but not when you need more complex navigation which is not easily expressed as circulation. In that case it is probably easier to just use the next, prev,  and opp to move around.
392
Use circulators whenever you need to go around a face or vertex, but not when you need more complex navigation which is not easily expressed as circulation. In that case it is probably easier to just use the next, prev,  and opp to move around. To work with the functions and classes just described, you will need the following header files:
-
 
393
\begin{verbatim}
-
 
394
#include <HMesh/Manifold.h>
-
 
395
#include <HMesh/FaceCirculator.h>
-
 
396
#include <HMesh/VertexCirculator.h>
-
 
397
\end{verbatim}
-
 
398
\subsection{Extended Example: Edge Flipping}
-
 
399
The following example demonstrates how to create a Manifold and add polygons (in this case triangles) and finally how to flip edges of a manifold. First, let us define some vertices
-
 
400
\begin{verbatim}
-
 
401
	vector<Vec3f> vertices(3);
-
 
402
	vertices[0] = p1;
-
 
403
	vertices[1] = p2;
-
 
404
	vertices[2] = p3;
-
 
405
\end{verbatim}
-
 
406
and then a vector of faces. The faces vector contains the number of vertices of each face in the mesh we want tor produce. Initially, we want to make a mesh with just one single triangle, so we produce a vector of one element and set that element to 3.
-
 
407
\begin{verbatim}
-
 
408
vector<int> faces(1);
-
 
409
faces[0] = 3;
-
 
410
\end{verbatim}
-
 
411
 
-
 
412
Next, we need the index vector. This vector is a long list of indices to vertices. For each face, we store the indices to its vertices in this vector. Since we just have a triangle, we store three vertices in the vector.
-
 
413
\begin{verbatim}
-
 
414
vector<int> indices(3);
-
 
415
indices[0]=0;
-
 
416
indices[1]=1;
-
 
417
indices[2]=2;
-
 
418
\end{verbatim}
-
 
419
So, if we had had two triangles, we would have stored six indices. Finally, we call \texttt{build\_manifold} with the indexed face set data, we have compiled. 
-
 
420
\begin{verbatim}
-
 
421
build_manifold(mani,        	// The triangle mesh.
-
 
422
			 3,           		// Number of vertices.
-
 
423
			 &vertices[0],	// Pointer to vertices.
-
 
424
			 1,           		// Number of faces.
-
 
425
			 &faces[0],  	// Pointer to faces.
-
 
426
			 &indices[0]);	// Pointer to indices.
-
 
427
\end{verbatim}
-
 
428
The result of the above is a mesh with a single triangle. Note that \texttt{build\_manifold} is in
-
 
429
\begin{verbatim}
-
 
430
#include <HMesh/build_manifold.h>
-
 
431
\end{verbatim}
-
 
432
Next, we try to split an edge. We grab the first halfedge and split it: Now we have two triangles. Splitting the halfedge changes the containing triangle to a quadrilateral, and we call triangulate to divide it into two triangls again.
-
 
433
\begin{verbatim}
-
 
434
	HalfEdgeIter h = m.halfedges_begin();
-
 
435
	m.split_edge(h);
-
 
436
	m.triangulate(h->face); 
-
 
437
\end{verbatim}
-
 
438
Now, we obtain an iterator to the first of our (two) triangles.
-
 
439
\begin{verbatim}
-
 
440
	FaceIter f1 =m.faces_begin();
-
 
441
\end{verbatim}
-
 
442
We create a vertex, \texttt{v}, at centre of \texttt{f1} and insert it in that face:
-
 
443
\begin{verbatim}
-
 
444
	VertexIter v=m.create_vertex(centre(f1));
-
 
445
	m.face_insert_point(f1,v);
-
 
446
\end{verbatim}
-
 
447
The code below, marks one of a pair of halfedges (with the value 1).
-
 
448
\begin{verbatim}
-
 
449
for(HalfEdgeIter h = m.halfedges_begin(); h!=m.halfedges_end(); ++h)
-
 
450
  h->touched =0;
-
 
451
for(HalfEdgeIter h = m.halfedges_begin(); h!=m.halfedges_end(); ++h)
-
 
452
  if(h->opp->touched == 0)
-
 
453
    h->touched = 1;
-
 
454
\end{verbatim}
-
 
455
Next, we set the \texttt{flipper} variable to point to the first of these halfedges:
-
 
456
\begin{verbatim}
-
 
457
	flipper = m.halfedges_begin();
-
 
458
\end{verbatim}
-
 
459
The long piece of code below examines a halfedge pointed to by \texttt{flipper}, and if it is not a boundary halfedge it tries to flip it. Then it increments the \texttt{flipper} variable until it lands on a halfedge marked with 1. If \texttt{flipper} reaches the end of the list of halfedges, we start over.
-
 
460
\begin{verbatim}
-
 
461
if(is_boundary(flipper))
-
 
462
  cout << "boundary edge: could not flip" << endl;
-
 
463
else
-
 
464
  if(!m.flip(flipper))
-
 
465
    cout << "could not flip" << endl;
-
 
466
do
-
 
467
{
-
 
468
  ++flipper;
-
 
469
  if(flipper==m.halfedges_end())
-
 
470
    flipper = m.halfedges_begin();
-
 
471
}
-
 
472
while(flipper->touched == 0); 
-
 
473
\end{verbatim}
-
 
474
\subsection{Extended Example: Implicit Surface Polygonization}
-
 
475
This example demonstrates how we can produce an HMesh Manifold from an implicitly defined object. Say, we have some function, \texttt{f}, which represents an object by what we sometimes call a characteristic function (\texttt{f<0} inside the object, \texttt{f>0} outside, \texttt{f=0}  on the surface). We wish to extract the 0 set as a Manifold.
-
 
476
 
-
 
477
First, we create a 3D grid of floating point values as shown below.
-
 
478
\begin{verbatim}
-
 
479
RGrid<float> grid(Vec3i(N,N,N)); // Voxel grid on which to sample 
-
 
480
\end{verbatim}
-
 
481
We sample \texttt{f} on that grid
-
 
482
\begin{verbatim}
-
 
483
for(int i=0;i<N;++i)
-
 
484
  for(int j=0;j<N;++j)
-
 
485
    for(int k=0;k<N;++k)
-
 
486
      grid[Vec3i(i,j,k)] = f(i,j,k);
-
 
487
\end{verbatim}
-
 
488
Next, we call a function which polygonizes the 0 set. The first two arguments are the grid and the manifold, the third argument is set to 0, since we want the zero level set, and the final argument tells the polygonizer to push the vertices onto the zero set (as opposed to leaving them in their initial position which is close to but not actually on the zero set).
-
 
489
\begin{verbatim}
-
 
490
cuberille_polygonize(grid, mani, 0.0, true);
-
 
491
\end{verbatim}
-
 
492
In post-processing, we triangulate \texttt{mani} and remove ugly triangles. Caps are triangles with one big angle (close to 180 degrees). Needles are triangles with one very short edge.
-
 
493
\begin{verbatim}
-
 
494
triangulate(mani);
-
 
495
remove_caps_from_trimesh(mani, M_PI * 0.85);
-
 
496
remove_needles_from_trimesh(mani, 1e-2);
-
 
497
\end{verbatim}
-
 
498
Note that you need the following header files:
-
 
499
\begin{verbatim}
-
 
500
#include <Geometry/RGrid.h>
-
 
501
#include <HMesh/volume_polygonize.h>
-
 
502
\end{verbatim}
-
 
503
to use the grid and the polygonizer, respectively.
-
 
504
 
-
 
505
 
-
 
506
\section{GLGraphics}
-
 
507
 
-
 
508
GLGraphics contains a set of tools needed for visualization of geometrical objects. In particular, this namespace contains mesh rendering facilities, and in the following, a very simple example is given. This section is basically a walk through of the simplest GEL program that draws a mesh. Apart from GEL, we also use OpenGL and that requires a toolkit for connecting with the window system. With GEL programs, one generally uses GLUT, and this example is not an exception.
-
 
509
 
-
 
510
For starters, we need to include some files mostly from GLGraphics but also the header file for the mesh load function of HMesh and the GLEW header. Why incude glew.h rather than just gl.h? Well, HMesh/draw.h contains some draw functions which rely on shaders, and since gl.h is normally not up to date, it makes sense to use glew.h instead of gl.h even though it inflicts a dependency. We include GLGraphics/gel\_glut.h rather than the normal glut.h. That is because the GEL version works the same on Windows, OSX, Linux and probably other platforms.
-
 
511
 
-
 
512
We also open the namespaces we will need and declare two globals: The view controller \texttt{view\_ctrl} and the mesh \texttt{mani}. The view controller class is rather complex. It more or less insulates you from having to deal directly with the projections and transformations of OpenGL: It sets up a perspective projection and also the modelview transformation needed to view the object. From a user interface perspective, it defines a virtual trackball which allows you to rotate the object.
-
 
513
\begin{verbatim}
-
 
514
#include <GL/glew.h>
-
 
515
#include <GLGraphics/gel_glut.h>
-
 
516
#include <GLGraphics/draw.h>
-
 
517
#include <GLGraphics/GLViewController.h>
-
 
518
#include <HMesh/load.h>
-
 
519
 
-
 
520
using namespace std;
-
 
521
using namespace HMesh;
-
 
522
using namespace CGLA;
-
 
523
using namespace GLGraphics;
-
 
524
 
-
 
525
GLViewController* view_ctrl;
-
 
526
Manifold mani;
-
 
527
\end{verbatim}
-
 
528
 
-
 
529
Below is the display function which is called from the GLUT event loop whenever an event that requires redrawing is received. All drawing takes place inside this function. In this case, it is simple since all we need to do is clear the screen (and depth buffer), set up a new modelview transformation with the view controller and then call the draw function followed by a swap of buffers.
-
 
530
 
-
 
531
The draw function sends the polygons to the graphics card. It is very inefficient and uses the fixed function pipeline. At a minimum one should draw the polygons to a display list, but for a simple example, this works. The buffer swap is because we use double buffering; in other words, we draw to the back buffer.
-
 
532
\begin{verbatim}
-
 
533
void display() {
-
 
534
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
 
535
    view_ctrl->set_gl_modelview();
-
 
536
    draw(mani);
-
 
537
    glutSwapBuffers();
-
 
538
}
-
 
539
 
-
 
540
\end{verbatim}
-
 
541
The mouse callback below is called when a mouse event has occurred. This is where user input  for the virtual trackball is registered. We check whether a mouse is pressed or released. If it is pressed, we detect which button and then ``grab'' the virtual trackball in order to rotate, zoom, or pan depending on which button is pressed. If the button is released, we inform the view controller of this.
-
 
542
\begin{verbatim}
-
 
543
void mouse(int button, int state, int x, int y)  {
-
 
544
    Vec2i pos(x,y);
-
 
545
    if (state==GLUT_DOWN) 
-
 
546
    {
-
 
547
        if (button==GLUT_LEFT_BUTTON) 
-
 
548
            view_ctrl->grab_ball(ROTATE_ACTION,pos);
-
 
549
        else if (button==GLUT_MIDDLE_BUTTON) 
-
 
550
            view_ctrl->grab_ball(ZOOM_ACTION,pos);
-
 
551
        else if (button==GLUT_RIGHT_BUTTON) 
-
 
552
            view_ctrl->grab_ball(PAN_ACTION,pos);
-
 
553
    }
-
 
554
    else if (state==GLUT_UP)
-
 
555
        view_ctrl->release_ball();
-
 
556
}
-
 
557
\end{verbatim}
-
 
558
If the mouse moves with a button depressed, we register motion in the function below. The new mouse position is sent to the view controller
-
 
559
which then, e.g., rotates the trackball accordingly. Note that this function ends by posting a redisplay event, i.e. informs GLUT that display should be called at the earliest convenience.
-
 
560
\begin{verbatim}
-
 
561
void motion(int x, int y) {
-
 
562
    Vec2i pos(x,y);
-
 
563
    view_ctrl->roll_ball(Vec2i(x,y));
-
 
564
    glutPostRedisplay();
-
 
565
}
-
 
566
\end{verbatim}
-
 
567
 
-
 
568
Finally, in the main function, we first load the mesh and then setup glut. This mostly involves defining the callback function just described. We set up the view controller passing it window dimensions and the size and position of the bounding sphere of the object just loaded. Finally, we do some minimal OpenGL set up: Essentially clearing the depth buffer and enabling lights. Finally, we pass control to the GLUT event loop.
-
 
569
\begin{verbatim}
-
 
570
int main(int argc, char** argv) {
-
 
571
    string file = "bunny-little.x3d";
-
 
572
    load(file, mani);
-
 
573
 
-
 
574
    glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);
-
 
575
    glutInitWindowSize(800, 800);
-
 
576
    glutInit(&argc, argv);
-
 
577
    glutCreateWindow("GEL Example Program");
-
 
578
    glutDisplayFunc(display);
-
 
579
    glutMouseFunc(mouse);
-
 
580
    glutMotionFunc(motion);
-
 
581
    
-
 
582
    Vec3f bsphere_center(0,0,0);   
-
 
583
    float bsphere_radius = 3;
-
 
584
    mani.get_bsphere(bsphere_center,bsphere_radius);
-
 
585
    view_ctrl = new GLViewController(800,800, 
-
 
586
        bsphere_center,bsphere_radius*2);
-
 
587
    
-
 
588
    glClearColor(0.0f, 0.0f, .5f, 0.f);
-
 
589
    glEnable(GL_DEPTH_TEST);
-
 
590
    glEnable(GL_LIGHTING);
-
 
591
    glEnable(GL_LIGHT0);
-
 
592
    
-
 
593
    glutMainLoop();
-
 
594
}
-
 
595
\end{verbatim}
-
 
596
Note that the mesh can be either an X3D, OBJ, PLY, or OFF files. However, only the geometry is loaded not the textures. In the case of OBJ files, we also convert all polygons to triangles, because the TriMesh loader (see the geometry class) is in fact used.
-
 
597
 
-
 
598
Apart from the drawing functions and the viewcontroller, GLGraphics also contains  other useful pieces: A few functions which greatly simplify shader loading and SOIL. SOIL is a small library for loading images. It is designed for OpenGL and makes it easy to e.g. save screen shots or load an image for use as a texture. While the need for image loading is fairly obvious, it might be more difficult to see the need for shader loading functions. However, it \textit{is} a little tricky to make shader programs in C++ using GLSL but the problems are almost all silly little things. For instance, how do you robustly read from a text file? How do you compile a shader and check for errors? In OpenGL What is the difference between a GLSL program and a shader anyway?
-
 
599
 
-
 
600
The short answer to the last question is this: A "shader" can be either a vertex shader, a geometry shader (in OpenGL 2.0) or a fragment shader. A "program" is a linked combination of these three types of shaders. Note that you don't have to have a geometry shader.
-
 
601
 
-
 
602
These functions attempt to obviate the need for an answer to the first two questions by providing an API for loading and compiling shaders and checking for errors. However, I don't include functions for creating the program, attaching shaders and linking. Why not? Because the need for flexibility means that the API would be just as complex as just using the OpenGL functions directly! However, loading shaders and checking for errors in compiled shaders is different. It makes sense to wrap that. It also makes sense to wrap the error checking for programs that are linked, so there is a function for that too.
-
 
603
 
-
 
604
Since shader loading and error check sandwhich the two calls needed for compilation, the most important function in this API, \texttt{create\_glsl\_shader}, loads a shader, compiles it, checks for errors and returns the shader handle. There is also a version which creates a shader from a string.
-
 
605
 
-
 
606
There is some code below to illustrate usage.	
-
 
607
\begin{verbatim}
-
 
608
GLuint vs = create_glsl_shader(GL_VERTEX_SHADER, 
-
 
609
  shader_path, "tri.vert");
-
 
610
GLuint gs = create_glsl_shader(GL_GEOMETRY_SHADER_EXT, 
-
 
611
  shader_path, "tri.geom");
-
 
612
GLuint fs = create_glsl_shader(GL_FRAGMENT_SHADER, 
-
 
613
  shader_path, "tri.frag");
-
 
614
 
-
 
615
prog_P0 = glCreateProgram();
-
 
616
 
-
 
617
if(vs) glAttachShader(prog_P0, vs);
-
 
618
if(gs) glAttachShader(prog_P0, gs);
-
 
619
if(fs) glAttachShader(prog_P0, fs);
-
 
620
 
-
 
621
// Specify input and output for the geometry shader.
-
 
622
// Note that this must be done before linking the program.
-
 
623
glProgramParameteriEXT(prog_P0,GL_GEOMETRY_INPUT_TYPE_EXT,
-
 
624
  GL_TRIANGLES);
-
 
625
glProgramParameteriEXT(prog_P0,GL_GEOMETRY_VERTICES_OUT_EXT,3);
-
 
626
glProgramParameteriEXT(prog_P0,GL_GEOMETRY_OUTPUT_TYPE_EXT,
-
 
627
  GL_TRIANGLE_STRIP);
-
 
628
 
-
 
629
// Link the program object and print out the info log
-
 
630
glLinkProgram(prog_P0);
-
 
631
print_glsl_program_log(prog_P0);
-
 
632
 
-
 
633
// Install program object as part of current state
-
 
634
glUseProgram(prog_P0);
-
 
635
 
-
 
636
// Set the value of a uniform
-
 
637
glUniform2f(glGetUniformLocation(prog_P0,"WIN_SCALE"), 
-
 
638
  win_size_x/2.0, win_size_y/2.0);
-
 
639
\end{verbatim}
-
 
640
 
-
 
641
\section{LinAlg}
-
 
642
Sometimes the simple 2,3,4 dimensional vectors from CGLA just don't cut it. We often need to solve large linear systems. The LinAlg namespace contains some vector and matrix classes and an interface to Lapack. This provides fairly easy way to do many numerical computations.
-
 
643
 
-
 
644
In the example below, we  find coefficients for $a x^2 + b y^2 +cxy + dx + ey + f$ such that the surface contains six specific points. The coefficients are found by solving the linear system $\mathbf A \mathbf x = \mathbf b$ where the rows of the $\mathbf A$ matrix contains $x^2 \; y^2 \; xy \; x \; y \; 1$ computed from the $xy$ positions of each point, $\mathbf x$ contains the unknown coefficients, and $\mathbf b$ on the right hand side contains the $z$ values of the six points. Using LinAlg, we implement it as follows: 
-
 
645
\begin{verbatim}
-
 
646
    CMatrix A(6,6);
-
 
647
    CVector b(6);
-
 
648
    
-
 
649
    for(int i=0;i<6;++i)
-
 
650
    {
-
 
651
        A.set(i,0,pts[i][0]*pts[i][0]);
-
 
652
        A.set(i,1,pts[i][1]*pts[i][1]);
-
 
653
        A.set(i,2,pts[i][0]*pts[i][1]);
-
 
654
        A.set(i,3,pts[i][0]);
-
 
655
        A.set(i,4,pts[i][1]);
-
 
656
        A.set(i,5,1);
-
 
657
        b[i] = pts[i][2];
-
 
658
    }
-
 
659
    CVector x;
-
 
660
    LinearSolve(A,b,x);
-
 
661
\end{verbatim}
-
 
662
While this example shows only the function for solving a system which should have a solution, there are also functions for solving overdetermined systems in the least square sense and finding the minimum norm solution to underdetermined systems using singular value decomposition. There is also a function for finding eigenvalues and eigenvectors of symmetric matrices and more.
-
 
663
\section{Geometry}
-
 
664
The Geometry namespace contains many different classes and functions. Roughly, we can divide the contents into
-
 
665
\begin{itemize}
-
 
666
\item Spatial data structures such as kd tress, bounding box hierarchies, and BSP trees.
-
 
667
\item A Triangle mesh data structure called TriMesh. TriMesh is different from HMesh in that it only contains triangles. It is much more an API for real time rendering which also facilitates material properties and not just geometry.
-
 
668
\item Classes and functions for dealing with volume data. HGrid and RGrid are, respectively, a class for hierarchically stored voxel grids (sparse grids) and regular grids. There is a number of functions for traversing voxel grids systematically and along rays.
-
 
669
\item Surprisingly, you will also find my C++ port of Jules Bloomenthals isosurface polygonizer and an implementation of Luiz Velho's parametric surface tiler in this namespace.
-
 
670
\end{itemize}
-
 
671
One of the most frequently used tools in Geometry is the kD tree class which merits an example. In the code below, we create a kD tree which had \texttt{Vec3f}s as keys and integers as data. Note that since the kD tree is a template, we could use any other type as both key and data, however, only CGLA vectors have been tested as key types, but there are no restrictions on data types.
-
 
672
\begin{verbatim}
-
 
673
    KDTree<Vec3f,int> tree;
-
 
674
    for(int i=0;i<N;++i)
-
 
675
        {
-
 
676
            Vec3f p0;
-
 
677
            make_ran_point(p0);
-
 
678
            tree.insert(p0, i);
-
 
679
        }
-
 
680
    tree.build();
-
 
681
\end{verbatim}
-
 
682
Note also, that before we use the tree it needs to be built. This is because the internal representation is a balanced binary heap which it is easier to build at the end rather than maintain during insertion of new points. To look for the points near a given point, we can call
-
 
683
\begin{verbatim}
-
 
684
    Vec3f p0;
-
 
685
    // ...
-
 
686
    std::vector<Vec3f> keys;
-
 
687
    std::vector<int> vals;
-
 
688
    float radius = 1.95f;
-
 
689
    int N = tree.in_sphere(p0, radius , keys, vals);
-
 
690
\end{verbatim}
-
 
691
This will find all points in a radius of 1.95 units from \texttt{p0}. The keys and values are stored in \texttt{keys} and \texttt{vals} when the functions returns. The return value of the function is the number of points found within the radius. 
-
 
692
 
-
 
693
Sometimes, we simply want the point closest to a given point \texttt{p0} which is done using \texttt{tree.closest\_point(p0, d, pos, x)} where the two first arguments indicate the point and the maximum search radius. The two last arguments are set to the key and data of the point found to be closest to \texttt{p0}. The function returns true if a closest point was found.
-
 
694
 
-
 
695
 
-
 
696
 
-
 
697
 
-
 
698
\section{Util}
-
 
699
The Util namespace contains a rather mixed bag of utilities many of which are quite useful and very diverse. 
-
 
700
\begin{trivlist}
-
 
701
\item The XML parser for instance is written from scratch and the basis for our X3D loader although it will load any XML file. 
-
 
702
\item \texttt{Grid2D} is often useful when we want to deal with e.g. simulation on a 2D grid. 
-
 
703
\item The \texttt{Timer} class is nearly indispensable when we need to time something, and it is very easy to use. 
-
 
704
\item \texttt{ArgExtracter} is a class for getting the command line arguments to a program. 
-
 
705
\item There is more - for instance a resource manager template, some string utility templates and a hash table implementation.
-
 
706
\end{trivlist}
-
 
707
Arguably, it would be more pretty if these pieces had been more thematically linked, but many are used a lot, and it seemed reasonable to have somewhere to stick various functions and classes that did not naturally belong elsewhere.
-
 
708
 
397
 
709
 
398
\subsection{Authors and License}  
710
\section{Authors and License}  
399
Many other people contribute, but the core of GEL was written (mostly) by Andreas B{\ae}entzen (jab{@}imm.dtu.dk), and any bug fixes, contributions, or questions should be addressed to me, unless you know precisely who could take care of the problem.
711
Many other people contribute, but the core of GEL was written (mostly) by Andreas B{\ae}entzen (jab{@}imm.dtu.dk), and any bug fixes, contributions, or questions should be addressed to me, unless you know precisely who could take care of the problem.
400
 
712
 
401
I was considering putting GEL under the LGPL. But it is a long complex
713
I was considering putting GEL under the LGPL. But it is a long complex
402
text. The longer any kind of document, the more chances for loopholes
714
text. The longer any kind of document, the more chances for loopholes
403
in my opinion. Instead, I list a few simple rules below. The most
715
in my opinion. Instead, I list a few rules below. The most
404
important one is that if you want to use GEL for some purpose, and it
716
important one is that if you want to use GEL for some purpose, and it
405
is not crystal clear whether it is against the rules, contact me. As
717
is not crystal clear whether it is against the rules, contact me. As
406
for the rules:
718
for the rules:
407
 
719
 
408
You are allowed to use GEL for academic or commercial purposes. In
720
You are allowed to use GEL for academic or commercial purposes. In
Line 424... Line 736...
424
GEL for a bigger project, I'd appreciate an email to jab@imm.dtu.dk
736
GEL for a bigger project, I'd appreciate an email to jab@imm.dtu.dk
425
 
737
 
426
In a project such as this, it is almost impossible to completely avoid
738
In a project such as this, it is almost impossible to completely avoid
427
building upon fragments of other peoples source code. GEL includes an
739
building upon fragments of other peoples source code. GEL includes an
428
obj loader based on work by Nate Robins. Some pieces of source code
740
obj loader based on work by Nate Robins. Some pieces of source code
429
from Graphics Gems have also been used. Moreover, I have simply included
741
from Graphics Gems have also been used. Moreover, I have included
430
rply by Diego Nehab, Princeton University, and the Simple OpenGL Image Loader by
742
rply by Diego Nehab, Princeton University, and the Simple OpenGL Image Loader by
431
Jonathan Dummer.  All of this amounts to only a fraction of the GEL source code and it should not be in violation of any license. In particular, SOIL and RPLY are under the MIT license and it is acceptable to include these packages as long as the copyright notice is retained (which it is.)
743
Jonathan Dummer.  All of this amounts to only a fraction of the GEL source code and it should not be in violation of any license. In particular, SOIL and RPLY are under the MIT license and it is acceptable to include these packages as long as the copyright notice is retained (which it is.)
432
 
744
 
433
\end{document}
745
\end{document}