I’m working with WebGL and as such, I’m discovering some quirks about OpenGL ES 2.0. I have been using display lists as long as I’ve been using OpenGL, but WebGL doesn’t have support for them. So, I’m buckled down and familiarized myself with vertex buffer objects, the (perhaps better) alternative.

At any rate, I need to render a regular 2D grid, and as it doesn’t support quads, either, I was forced to use triangles. In the interest of getting things running, I just provided a wasteful list of discrete triangles. This is wasteful because it references many more vertices than necessary – I ended up declaring 6n^2 vertices when in reality there are only n^2 + n + 1 unique vertices. This worked fine, until I wanted to increase the resolution. It turns out, JavaScript doesn’t like large arrays.

That’s fair, because the implementation was pretty wasteful. A triangle strip was the best choice anyway. A triangle strip is a highly compact form of representing a mesh. For n triangles, it requires only n + 2 vertices defined. Well, that’s roughly true. We’ll see another case in a minute. It’s useful when many triangles share vertices, and perhaps I’ll let Wikipedia’s explanation stand.

It wasn’t immediately obvious how to define a grid out of a single triangle strip and so I got out a pen and paper. I kept in mind a neat trick: if in a triangle strip, you need to skip the use of a vertex, a vertex can be introduced twice in a row. That is, if I need triangles (6, 3, 7) and (7, 11, 6) in that order, you can just make your strip with 6, 3, 7, 7, 11, 6. You can think of it as if there are two triangles created (3, 7, 7) and (7, 7, 11), but they have no area and a degenerate case – a line. Furthermore, these lines lie on triangles already defined.

Perhaps the obvious choice doesn’t yield any results, and in fact in this layout, it can’t be easily done (you have to have vertices appear three times in a row):

This is a bad idea for a topology if you want to use a single triangle strip.

To better convince yourself, try to come up with a good way to put this in a triangle strip. I’ll make the case that it is pretty difficult with a claim from graph theory. In order for a triangle mesh to be turned into a triangle strip, each consecutive triangle must share an edge. We can then think of the mesh as a connectivity graph (the dual of the mesh) and then the problem will emerge more clearly:

The dual graph of the bad idea.

To make the triangle strip “nice,” we ought to be able to visit each node once and exactly once. There’s good and bad news in this – it’s the same problem as finding a Hamlitonian path which is NP complete. The good news is that if we find a solution to our small problem, we’ve found a solution to all such grids (with arbitrarily many triangles). Note that we don’t need an Eulerian path.

If you stare long enough at the above connectivity graph, you’ll hopefully convince yourself that there’s no way to traverse it visiting each node once and exactly once. Go ahead and try – it’s pretty infuriating.

Looking at how we would traverse one strip (triangles a, b, c, d, e and f) actually gives us a clue. A triangular strip for that case would be 0, 4, 1, 5, 2, 6, 3, 7, and happiness ensues and we should move onto the next row. Unfortunately, in the context of this new row, we’re starting in a different place (topologically) than we started with the first strip. Vertex 0 has two connected neighbors in its row – 1 and 4. Vertex 7 has three in its row: 6, 10 and 11. It turns out we can change up the topology to remedy this simply:

A much better topology for drawing this with a single triangle strip.

A much better topology for drawing this with a single triangle strip.

We can also see that this is a much better solution by looking at this new graph’s dual:

The dual of the better topological choice.

You can probably easily find a Hamlitonian path in this case. But this still leaves us with how to determine the vertex orderings. We decided that the first row ought to be 0, 4, 1, 5, 2, 6, 3, 7, but moving on from there we need a bit of “glue” to move onto the next row. We insert 7 again, and then continue on from there: 7, 11, 6, 10, 5, 9, 4, 8. A bit more glue for the third row: 8, 12, 9, 13, 10, 14, 11, and 15:

An alternative representation of the vertex ordering

Looking at the indices from the first row, starting at 0, we can get the next index by alternately adding 4 and then subtracting 3. On the next row, we’ll continue to add 4, but then alternately subtract 5. The 4 is derived as being the number of vertices on a side (if there are n divisions, then there are n+1 vertices), and the 3 and 5 are explained by the fact that we need to change columns in the mesh, by one step at a time.

An clean implementation is not trivial, but not extremely difficult. In terms of results, I can fit more than 4 times as many vertices into the mesh than with a per-triangle implementation. And to boot, it has cut the work of the vertex shader a great deal.

Tagged with:
 

webGLot – A Preview

I’ve mentioned WebGL before, and I think it could be very important. There is a competitor from Google, but like OpenGL and OpenCL, this API is managed by the Khronos Group and that fact appeals to me. Perhaps it’s that I’ve used it fairly extensively, but I really like OpenGL. Despite its quirks, it’s quite powerful.

The big “get” is that it gives programmers access to hardware-accelerated graphics from directly within the browser. There’s a lot of interest in this arena for game development as it would obviate much of the need for separate distributions based on operating system. (Skip to the end for more of an opinion on this subject.)

As such, I’ve been working with WebGL as opposed to the Google-proposed O3D. (I have every intention to explore O3D, time permitting, as there are some jagged edges to the current specification.) The result of this recent toil is a budding WebGL implementation of my OpenGLot project. It’s still in early stages, but in the coming weeks, it should develop even further. To whet appetites, I have a few pictures.

A scalar field, my persistent test function.

A scalar field, my persistent test function.

A 3D surface, again one of my usual test functions.

A 3D surface, again one of my usual test functions.

I seriously doubt that WebGL will every match the performance of OpenGL. Even though JavaScript interpreters are getting faster at a somewhat alarming rate, they won’t match the speed of C or C++. That said, if one can appropriately offload work onto the GPU, it won’t matter as much, but there will always be that overhead.

It won’t so much be a matter of having the same performance, but enough performance. If a person can go to a single webpage and get 60 frames per second performance in a game or tool without having to install software, that’s tremendous. Currently I’ve been getting between 60 and 90 frames per second with WebGLot, and I’m sure I can keep that number up as more features are added.

My hope is that this will be a tool and library that has a wide-enough feature set by the time WebGL is widely adopted that becomes often-used. But that’s just ego. The purer motivation is that if you’re a math teacher, and you want to have interactive demonstrations of Newton’s method, or parametric surfaces, or even flow fields, you can write an application in 20 minutes that does all the heavy lifting of graphing it for you. As long as you can describe the mathematical primitives, you should be able to render it. Of course there will be a general-purpose grapher available for any calculus student who’s having trouble visualizing this or that, too. Or a resourceful PDE student who need to solve his homework (the GPU-based PDE solver will take a little bit more time, but it’s very nearly complete).

In short, the strength of WebGL is that is has respectable performance, and in a year’s time, half the browsers (well maybe not half) on computers will support it, giving the average internet-user access to a wealth of media.

Tagged with:
 

Programming Praxis

I’m all for sharpening the saw, and working on little puzzles. In that vein, I recently came across a site called Programming Praxis that suggests tasks from implementing heapsort to writing AI to play the game Mastermind.

I don’t work on their puzzles as often as I like, but if you’ve got a little bit of free time, they’re worth checking out.

 

OpenGLot3D Video

I gave ScreenFlow a shot, and it was definitely the best screencasting tool I found. Thanks to it, I can now share a more dynamic sense of the capabilities of this plotting library.

OpenGLot3D from Dan Lecocq on Vimeo.

Tagged with:
 

OpenGLot Release

A short while ago I posted a new release of OpenGLot, which featured parametric curves, scalar fields, contour lines and flow fields all implemented in GLSL shaders.

And they support time dependence.

It can plot virtually any function in x, y and t, and on my MacBook with its NVIDIA GeForce 9400M it has been getting 10k+ fps. I’m still a little surprised by this number, but it seems to be running at that speed.

Flow (vector) fields appear as advected dye. They're currently streamlines, but in the near future I hope to support streaklines and particle flow as well.

Flow (vector) fields appear as advected dye. They're currently streamlines, but in the near future I hope to support streaklines and particle flow as well.

Scalar fields appear as a mapping of height onto color.  If this function were to be plotted in 3D, it would like a sheet rippling, but sometimes it's more useful to see it in 2D.

Scalar fields appear as a mapping of height onto color. If this function were to be plotted in 3D, it would like a sheet rippling, but sometimes it's more useful to see it in 2D.

On of the great thing about implementing this on the graphics card is that it doesn’t require much CPU time on the machine running it. Even at 10k frames per second, my MacBook never uses more than 30% of a single core’s time. A place where this particularly shines is on tiled displays – a bunch of HDTVs tiled together to run as if it were one large screen. In such setups, a computer will control 2-4 screens, and each computer’s graphics card has enough power to run the animation for its portion of the screen. There are still some bugs to be worked out, but I ran a proof-of-concept on one of the tiled displays at KAUST.

Running a demo of OpenGLot on a KAUST tiled display

Running a demo of OpenGLot on a KAUST tiled display

Lately I’ve been working on getting the 3D analogs of the various 2D primitives working, again all with time dependence (it’s the support for animation that really makes this shine in my mind). So far it’s surfaces, parametric curves and surfaces and flow fields, but the flow fields have some work yet. It turns out that while modern hardware is definitely capable of handling 3D flow fields, it doesn’t actually make much sense when you see the result – it’s just too busy. To be able to easily visualize flow in 3D is very much an open problem.

3D streamlines end up just becoming confusing more than they are helpful.

3D streamlines end up just becoming confusing more than they are helpful.

In order to get some interesting shapes working, I had to add support for cylindrical and spherical coordinates which is actually providing an interesting challenge – how best to generate the shaders. The shader source code (that runs on the graphics card) is generated and compiled when you run OpenGLot, and I’ve not found an altogether easy and intuitive interface for adding simple coordinate transformations to it. Still, it works, but the programatic interface will likely change.

This is a torus of sorts, which I got as an example from Grapher.app

This is a torus of sorts, which I got as an example from Grapher.app


This is the same torus, just colored by using its surface normals as RGB values

This is the same torus, just colored by using its surface normals as RGB values

In order to determine surface normals (which are something usually determined when one defines the geometry of an object), the vertex shader approximates various derivatives numerically. So far, the shading results have been pretty decent.

A trigonometric function, colored by mapping the surface normals to colors

A trigonometric function, colored by mapping the surface normals to colors


The superimposition of two trigonometric functions, lit based on their surface normals and a texture to give visual clues about distortion

The superimposition of two trigonometric functions, lit based on their surface normals and a texture to give visual clues about distortion

I’m still working on making video of this in action available, but so far a number of the tools I would usually use have come up short. I’ve been trying to integrate a video encoder into a utility library for OpenGLot so it can record video straight out of the box, but the framerate is still too low.

Tagged with:
 

Projection Mapping

Projectors these days are not uncommon. People are buying projectors for their own homes, schools have projectors to plug computers into – they’re pretty widespread.

An application for them I hadn’t seen until a few weeks ago was projection mapping. I’ve run across a couple of posts about them on MAKE. Where traditionally you project onto a flat screen or wall, you can equally project onto any other geometry. If you have a representation of that geometry, one can create all manner of optical illusions. Perhaps some videos will make this clear:

The amazing thing about these is that something so impressive is going on that you don’t even notice it. You might think that the same illusion can be accomplished on a flat screen, but making use of the fact that your brain uses context to build a picture means that this can be much more impressive.

Beau Lotto talks about this in a really interesting TED Talk I saw recently. What I have in mind particularly is when he talks about the tiles in light and shadow and how we perceive their color. The buildings the above videos project onto are the tiles in this analogy, and by projecting varying levels of light onto them, we perceive a different situation from what’s actually happening, and what’s so amazing to me is that it’s so compelling and convincing, you don’t it didn’t quite soak in at first just how impressive it is.

I hope to be able to have a project like one of these projection mappings at KAUST.

Tagged with:
 

OpenGLot

As a teaching tool for a course last semester, I put together an interactive plotter in openGL which I endearingly named “openGLot.” (For those who missed it, “openGL” + “plot” = “openGLot.”) See, I felt like I had to give it a very unsavory name so that if it ever became widely used, people would be forced to use its ill-sounding moniker.

At any rate, I originally wrote in Ruby, but have been slowly porting it to C++ with high hopes for its use and applicability. I still have a bunch of interactive demos for numerical methods (from Newton’s method to the trapezoidal rule for numerical integration) in the Ruby version, but I’ll be bringing those to the C++ version one of these days. I started a sourceforge project for it a while ago, which was kind of exciting.

At any rate, as a brief (albeit nerdy) respite from the academic onslaught today, I added a class for parameterized curves.

A demo of a parameterized curve in openGLot

A demo of a parameterized curve in openGLot

I’ve got a bunch more primitives to add to it (scalar and vector fields, for example), but those will surely come one of these days. I’ve added adaptive mesh refinement (so that “busier” functions require more sampling to get a more accurate visual representation), but I’m still not quite happy with it.

A "busy" function with no adaptive refinement

A "busy" function with no adaptive refinement

The same "busy" function with recursive refinement.

The same "busy" function with recursive refinement.

I’ve also got a 3D version, but that’s not been polished or formalized, but everyone loves a pretty graph:
openGLot3D

Tagged with:
 

Empirical Mathematics

As I read in a lecture recently, Richard Hamming described his philosophy of computing with, “the purpose of computing is insight, not numbers.”

On a relatively regular basis, I use numerical methods to verify an analytical solution I’ve reached and occasionally, to reach an analytical result. At one point, I was playing around with the time complexity of heapsort, and I came across a statement about which I was unsure. I verified that it was the case, but it brought about other questions about a more general case.

\sum_{h=0}^{\infty}{\frac{h}{n^h}}

How does this converge for different n‘s?

I played around with it for a little bit to see if I saw any pattern that emerged, like with a geometric series or an arithmetic sum, but I came up with nothing. So, I decided to explore the numbers a little bit, writing a short little Ruby script to take the first 100-or-so elements. It turns out that even this approximation provided the insight to get the general expression:

  • n=2 \Rightarrow 2
  • n=3 \Rightarrow 0.75 = \frac{3}{4}
  • n=4 \Rightarrow 0.4444... = \frac{4}{9}

The expression thus seemed to be:

\sum_{h=0}^{\infty}{\frac{h}{n^h}} = \frac{n}{(n-1)^2}

Of course this needed to be verified, but that task is easy enough. The point is, that sometimes the numerical approximation can give you the exploratory insight needed to solve a problem. Sure, it’s rough around the edges, and isn’t as elegant as I would necessarily like, but it’s very useful.

 

When asked recently about why I began in computer science, I realized that it owes a lot to the mother of a friend who worked as a software engineer at Ball Aerospace. It was my junior year of high school when we spoke at a barbeque:

Katja has M.S. and although I’m afraid I’m uncertain of the specifics, she was confined to a wheelchair at this point. She asked the powers that be to make the entrance of the building where she worked more wheelchair accessible, and they suggested that when she arrived at work that she could just call the front desk or get the attention of the security guard to have the door opened for her. She tried to explain to me that, “it was the door’s job to open itself.”

I didn’t understand what she meant then, but she assured me that someday I would. She wasn’t referring to the automatic opener, but rather that it’s the door’s responsibility to provide a way to open it. Whether that’s a handle, a latch or a button, there shouldn’t be outside resources that enter into the equation of opening the door. I don’t remember the day that I understood it, but it came after taking Data Structures (it seems like a lifetime ago at this point).

During today’s NPAR sessions, it cemented what I had been coming to realize – computer scientists are really philosophers. We argue about what it means to be a door and by what metrics art should be judged. We’re made uncomfortable by hacks that do not obey a cohesive design philosophy and if you talk to any computer scientist worth his weight in gold, he has a sense of the “right” way to design something and can substantiate that claim.

All this is especially true of people in graphics, I’ve found. The people at NPAR are often concerned with visualization and communicating an idea (after all, our eyes are our highest bandwidth sense). It’s one thing to know facts, like the population and GDP of countries over the last 40 years, but it’s another thing entirely to have a feel for the trends they describe. It’s been said before that “a picture is worth a thousand words,” and the goal of any good visualization should be to convey understanding. We seek to reveal the truth, the “chairness of the chair,” and this is goal I feel very strongly about and take to heart at every chance.

This concept is well-summarized by a quote one of the presenters mentioned:

Drawing is not following a line on the model, it is drawing your sense of the thing. – Robert Henri

Tagged with:
 

Matt Matteson had a homework problem dealing with (n+a)^b, and finding a bound for it. Expanding this and evaluating it at n=a piqued my curiosity about the sum of each of the binomial expansion terms. That is to say, the sum of bC0 + bC1 + … + bCb. Well, I explored it a little bit, and did a quick-and-dirty writeup of my findings:

Sum of Combinatoric Terms

Tagged with: