Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Part One: Euclidian Geometric Algebra and Quaternions

0.00/5 (No votes)
15 Mar 2005 1  
Geometric Algebra applied to OpenGL

Sample Image - ega.jpg

Introduction

This will be the first article on Geometric Algebra, (GA), and its applications in graphics using Gaigen. I will evolve this code as I work toward the Conformal Model of a graphics application. I am starting with the three dimensional model of GA as I think it is easier to understand. There are three parts in this article. The GAGL class, Gaigen, and an introduction to Euclidian Geometric Algebra.

The GAGL Class

I'll just introduce the OpenGL class as it is self-contained. For those who have not worked with OpenGL, you may find this an easy way to get started. With one line in OnDarw you can have an object on the screen that can be handled with the mouse. Right now you would still need to include the Gaigen headers where you implement it but I will see about hiding those headers in the future. So far this class handles OpenGL initialization, screen drawing and mouse movements. Build this and you will notice that the mouse movements are intuitive, as if quaternions were used. If you create this on the heap, you won't have to spread the headers around your application. This class can be used with a WINDOWS app, WTL, or windows and views in MFC. I have kept the necessary interface to a minimum. The generated Gaigen files are included in the project download, you do not need the Gaigen generator to work with the sample project or the GAGL class. You don't have to know anything about Geometric Algebra or Gaigen as that is hidden.

To use it in a MFC view, add a pointer in the CMyView declaration:
    GAGL* pGWL;

Initialize it in OnCreate:

    pGLW= new GAGL( *this );

In the view's OnSize member:

    pGLW->OnSize( cx, cy );

A minimum mouse implementation is to roll the screen on the x and y axis. Pass your mouse movements like this:

void CMyView::OnLButtonDown( UINT /*nFlags*/, CPoint point )
{
    SetCapture( );
    bMouseActive= true;
    pGLW->InitMouse( point.x, point.y );
}

void CMyView::OnLButtonUp( UINT /*nFlags*/, CPoint /*point*/ )
{
    ReleaseCapture( );
    bMouseActive= false;
}

void CMyView::OnMouseMove( UINT /*nFlags*/, CPoint point )
{
    if( bMouseActive )
        pGLW->MoveMouse( point.x, point.y );
}

In OnDraw you would:

void CMyView::OnDraw( CDC* /*pDC*/ )
{
    pGLW->PrepareDraw( );
    // Do your drawing here.

    pGLW->RenderDraw( );
}

And to finish up:

void CMyView::OnDestroy( )
{
    delete pGLW;
    CView::OnDestroy( );
}

Note that you will get warnings when the Gaigen files are compiled. Ignore them, they are harmless. If Gaigen comes out with a revision that fixes this I'll submit a new download.

Gaigen

This is optional. There are Gaigen generated files in the project for the Euclidian geometry.

The Gaigen Generator

Gaigen is a c++ file generator. It is fast and convenient for development. You can just keep it open while you are working on the development of the Gaigen classes. Generate and when you alt-tab back to Visual Studio, just let VS load the changed files and compile. You can download Gaigen at SourceForge:

The following is for the VS.NET solution.

You will need the fltk libraries. In the gaigenui project, do the following. Set the 'additional include directories' to your include that contains the /FL directory. Remove the gaigenui.rc from the project. It is missing but you don't need it. Set the linker's 'additional library directories' to the lib of fltk. In 'ignore specific library', add LIBCD.lib. Set the ouput of all the projects to a common directory. The executables need to be together. I've put them in a lib like this:

Sample Gaigen directories

gaigenui.exe is the executable you would want to start. It should run by now but will crash if you try to generate files. Here is a link for the installation manual: I think you could use 'gaigen_local_install.cpp' in the src directory, (I haven't tried it). I've set the environment variable 'GAIGEN_CONFIG' to point to the gaigen.config file which also seems to be missing from this release. Here is a copy: Set your directories for the algebras and executables. But wait! That's not all! open the 'enviroment.cpp' in one of the projects. Set the initializers after the #else to something like this:
char *g_dataDir = "C:\\cpp\\gaigen\\ui_4\\algebras";
char *g_includeDir = "C:\\cpp\\gaigen\\ui_4\\algebras";
char *g_binDir = 
  "C:\\cpp\\gaigen\\ui_4\\lib"; //this must be set to your executables

char *g_algebrasDir = 
  "C:\\cpp\\gaigen\\ui_4\\temp"; //This doesn't seem to have effect

Here I have copied the src/gaspectemplates.txt to the algebras/ directory. Before you generate your files, go to the 'generate' tab and set the directory of the project where you would like to use the files. If you have any troubles, go immediately to the output window to see what went wrong. That should tell you, you should not have to debug. I have included the 'e3ga.gas' file in my project download. It is the GA I'm using in the example. If you are serious about using Gaigen, you will also want these two manuals:

One more note. It seems that Gaigen has a memory leak, it's not mine. I've taken a little look but haven't found it yet. The source for the generator is in gaspectemplates.txt.

Quaternions and all the rest

Geometric Algebra is not just for doing graphics. In fact, the Gaigen generator was intended for scientific modeling from what I've seen. But I'll stick to the graphics in this article.

Points are 'grade one blades' in the Euclidian space, which are just vectors from the origin. So, just like you would, translate space and draw the point. I am also drawing lines from the origin to the points in this example. It gives it a real contraption look.

Lines or vectors are again just vectors. But they are coordinate free. To place them in space takes a second vector. It may have been more elegant to demand that the base vector were normal to the line, but after thinking about it, not at all. To be able to specify any arbitrary point for the line to go through is much more powerful. Rather than draw lines, I've elected to draw vectors. But as you will see in the project, they can as easily be treated like lines. In the CGLView::DrawVector member I have shown an example of turning a vector into a rotor. This, so I could line up the model matrix on the vector and draw the line with gluCylinder.

Planes are bivectors, or, 'grade two blades'. There is actually more information in a bivector than we need for a plane. It includes a directed magnitude. If you were going to draw a finite plane like a disk, this magnitude would be used. For an infinite plane we are interested in the directed nature of the bivector. To make simple calls to glVertex3f, I will just bring the model matrix to the normal from the origin

Rotors are also bivectors and will do the same thing as quaternions. The beauty is that you can actually visualize how it works. While quaternions seem to be some mysterious '4-dimentional' functions, think about what it actually do. You have some well defined plane that you want to rotate some given amount on. Rotations are really a two dimensional subspace in three dimensions! To use a rotor is really simple and you can use them on any GA object. You will find several examples in the project. They will usually look something like this:

e3ga rotatedObject= rotor * origanalObject * !rotor;

Take a look in the wingl.cpp, at gaRotateMatrix, for an example of rotating an OpenGL matrix. I've included tracing you can turn on to see it at work. Because you can rotate GA objects directly, you don't need to rotate the model matrix to draw them like you would with the glu and aux objects. Here are two PDFs that chart the different objects and operations in the different geometries:

The code just before drawing the plane shows the intersection of a line with the plane. And drawing the reflection just takes a couple of more lines of code using a rotor. The intersection code is right out of the raytracer pdf. Gaigen is rich with overloaded operators so you can see that the implementation looks much like the formula. It only took a few minutes with the Gaigen manual to code the reflection. (That, after some time invested in understanding what I could about GA and Gaigen!) Here I treat the vectors like lines. When you run the animation, you will see the vector reflect from the plane as if it were infinite.

You will notice that the GA objects live quite separately from the OpenGL interface. The action of the lines, (also see the animated rotation of the lines in CGLView::OnTimer, is just GA math. OpenGL is considered only at rendering time. There are graphics members in the Gaigen code but nothing is implemented. It may never happen as it would not seem it could be as flexible as just keeping it separate.

Something to note if you take this up. What is called a 'normal' in Gaigen is, to quote, 'the sum of the square of all coordinates'. It is not an orthonormal object, it is a scalar. For the conventional normal, you would use the 'dual'. You will see use of 'norm' and 'dual' in the project. You will find the dual is the same as multiplying by the pseudoscalar of the space. See DrawVector in example.

I have only looked to introduce Geometric Algebra in this article as an alternative to quaternions and Plucker coordinates. There is a lot of information on the web on GA. Here are a couple of good links:

I had one paper in mind that I've printed a while back, but I can't find it on the web and the PDF is on a drive that isn't in a computer now. There are lots of good papers on both those sites. So, I won't recommend 'one' paper as each reader will come from a different background and have differing tastes. Some papers I didn't like when I started look very good now. These may work for you:

Geometric algebra: a computational framework for geometrical applications

If you download the raytracer project you won't need Gaigen. They have included all the generated files. It works with one exception. In the wood.rtm file two lines were left with absolute file references. change the lines to:

diffuse_texture "../files/wood.png"
bumpmap "../files/wood2.png"

Thanks, Dan.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here