WebGL hacks

webgl julia quaternion raytracerThat’s it, I finally found something fun in web development! I never thought I’d live to see the day when I would feel the motivation to learn javascript, but here we are. WebGL is fun, because you can do all the things you could with regular OpenGL, but now you can send URLs to all your friends to show off. I can’t say I liked javascript really, but I guess it’s passable as long as you can avoid the horrible conventions people have established for pretending to write object-oriented code with it.

So what I did, after experimenting to see how WebGL and javascript programming works, is a port of a GPU-raytracer for 4D quaternion Julia fractals, and a simple 360-panorama viewer. You can find those on my webgl hacks page I put up yesterday.

About WebGL itself now, I’m really disappointed they chose to base it on OpenGL ES 2.0, which is the bastard child of a slashed down OpenGL subset initially spec’ed for fixed point embedded devices, and Khronos’ OpenGL >= 3 d3d10-buttlicking madness. I understand why they chose that, because they intend to have WebGL easily implementable on mobile phones and tablets, but I’m still disappointed.

For those of you not well versed in the differences between the various OpenGL versions that suddenly crept up when Khronos group took control of OpenGL and apparently surrendered it over to inmates of the nearest insane asylum, I’ll give you a short overview of what sucks in OpenGL >= 3.x, OpenGL ES 2.0, and WebGL:

  • No fixed function pipeline. Yeah I know shaders are awesome, I love them too. But it’s convenient to be able to put a goddamn texture on a quad without having to write a bloody shader for it. OpenGL is not just used for video games you know.
  • No immediate mode (glBegin). Again, yes immediate mode is slow if you use it to draw multimillion vertex meshes, but having to make a vertex buffer for a quad representing a button in a GUI or a simple overlay, is insanity.
  • No matrix stack. Obviously when I’m writing a full 3D engine, with hierarchical keyframe animation, I have to ignore the matrix stack and write my own quaternion/matrix code. But for everything else, the OpenGL matrix functions are unbelievably useful.
  • No GL_QUADS.

So anyway, while I was playing around with it these past few days, I had to bring back a little bit of sanity to WebGL. For that reason I wrote SaneGL, a small piece of code that implements immediate mode drawing, and the OpenGL matrix stack on top of WebGL. I bundled that along with a small matrix math library and some helper functions for WebGL programs in a project called webgl-tools, which you can find in my mercurial repository: https://nuclear.mutantstargoat.com/hg/webgl-tools.

Oh by the way, if you’re one of those misguided sods that keep using windows, and you try to run any webgl apps right now you will probably be disappointed. In an unprecedented inspiration of pure stupidity, both firefox4 and chrome chose to implement WebGL over Direct3D by default on windows, using a project called ANGLE. The reason for that, they say, is that most graphics card vendors provide buggy OpenGL implementations on windows, so apparently it makes sense to write an even more buggy OpenGL->D3D translator and use that.

Initially I thought that ANGLE fails to translate huge shaders such as the one on my fractal raytracer, but in fact it seems to fail on pretty much everything, complex or trivial. The only way for windows users to use WebGL at the moment until mozilla and google comes to their senses and make ANGLE a fallback for known buggy OpenGL implementations instead of the default choice, is to go and force the browsers to use OpenGL instead. On firefox you can do that by setting the about:config variable “webgl.prefer-native-gl” to true, while chrome requires the command-line argument: –use-gl=desktop.

On GNU/Linux, as long as you have an nvidia card everything should be peachy from the get-go. Other cards are apparently blacklisted by firefox, so you’ll have to set webgl.force-enable to true, and pray to Odin.

Escaping glutMainLoop

Let’s say you’re writing a distinctly glut-like window-system abstraction library for OpenGL context creation, event handling, etc. For those not familliar with the way one uses OpenGL to draw graphics, what happens is you talk to the native window system (X11, Win32 API, etc) to create a window and process events, then you create an OpenGL context and you bind it to that window using again platform-specific calls (GLX, WGL, etc).

So let’s say you’re writing that code, but you decided your library will allow the user to keep control of the main loop, so you provide a funcion called something like process_events to run a single iteration of your event processing, so that the user may call it in a loop. How do you implement that on top of glut, which has a single glutMainLoop function that doesn’t ever return?

By the way, for those qurious on why would you do that in the first place, the reason to write a glut backend for this library, would be as a catch-all fallback to be able to run on platforms for which no native backend is yet written.

On GNU/Linux systems generally we don’t have the original GLUT, but rather FreeGLUT, which is nice enough to provide a glutMainLoopEvent function which runs a single iteration of the event loop, so we just call that from process_events and we’re done. But I have actually written an X11/GLX backend for my library, so I don’t need GLUT there, I need it on other systems. So how to break the chains of glutMainLoop and return after each iteration of the event handling loop?

The solution is obvious, use setjmp/longjmp. In process_events we call setjmp which obviously returns 0 the first time around, in which case glutMainLoop is called. Now glut enters its infinite loop and waits for events from the window system. As soon as all pending events are processed, or if there are no events to be processed, it calls our idle callback, then when that returns it loops back to the top again, and again, and again.

Of course we set up an idle callback that doesn’t actually return. It calls the user’s idle callback if there’s one registered, and then calls longjmp which unwinds the stack until we end up back into process_events at which point setjmp returns non-zero and we return execution to the user.

One minor issue that needs to be addressed is that since we set an idle function, if the user didn’t set one with our library, we’re wasting cpu cycles busy-looping because GLUT will never block waiting for events when there’s an idle callback. This again is easily remedied. If the user didn’t register an idle function with us, we don’t actually set our idle function to GLUT a-priori, instead we wait for one of the other event callbacks to trigger, and at the end of those callbacks we set the idle callback, and remove it again when it gets called, before longjmping back to the user.

Here are a few snippets of the actual code demonstrating the above:
Read the rest of this entry »

Linuxtrack 6dof headtracking for wine games

linuxtrack-wine logoSince I was a little kid, I always loved airplanes. When I became a little older, mainly during the 90s I used to play a lot of flight simulators on my computer, I even had a set of decent flight controls (stick/throttle), but for some reason I dropped that hobby for many years. Until I very recently picked it up again.

One really important thing that changed during my abstinence from flight simulators, a huge change that transformed the whole experience, was the almost universal adoption of 6dof headtracking for looking around as you fly!

Now people are able, with simple intuitive movements of their head to be able to look outside as they fly above that beautiful lake, “check six” to effectively maneuver to avoid an enemy plane in a dogfight, or follow the runway with their own eyes as the airplane turns slowly into final approach to line up perfectly for landing! Even better, since 6dof headtracking includes translation as well as rotation, the user can look around an obstacle blocking the view, to see for instance a pesky instrumment in the panel that’s partly hidden behind the stick, or a plane in formation which happens to fly just where the canopy frame happens to have a metal support bar. Just moving the head a bit to the left or the right does the trick… Unbelivable!

Instrumental for the universal adoption of 6dof headtracking among flight simulator users and developers, is a company called NaturalPoint who sells a complete head-tracking system called TrackIR, that includes an infrared high framerate camera, markers that the user attaches to their heads, and supplies an API to game developers to access their headtracking data easily. Now that set doesn’t come cheap, so there’s the necessary free alternative out there, that works with a simple (or even better modified) webcam, called freetrack. The main problem with both of those as you might have guessed, is that they only work on windows.

After the first dissapointment, I obviously had to have that functionality, so I decided to start hacking my old 3dof headtracking experiment to make it 6dof and connect it somehow with games running through wine. However, while I was researching how to do that, I stumbled upon the linux-track project, which does exactly what I needed, but it only worked with a native GNU/Linux flight simulator called x-plane.

So, with only a small piece of the puzzle missing, I went on and wrote a program that emulates the TrackIR API which is supported by many windows games, but feeds them data from linuxtrack instead. Currently I’m happily playing IL-2 Sturmovik and Falcon4 AF through wine, with full head-tracking support, enjoying the virtual view from my cockpit.

This new project of mine is called linuxtrack-wine and is available under GNU GPLv3.

I also had to do a hardware hack, to convert my old flight controllers from gameport to USB, but that’s much less interesting, and I’m too lazy to write about it right now :)

Wacom Hacking

Recently, I acquired a rather old Wacom Intuos A5 tablet, for reasons I won’t delve into at the moment.

Wacom Intuos A5 Serial

It’s an old serial model, and although I don’t have a serial port anymore, I do have a USB-to-serial adapter, which thought would probably work fine with the X.org driver produced by the linuxwacom project, since they do mention support for serial tablets on their website.

I plugged it in, followed the linuxwacom documentation about setting everything up in xorg.conf, and fired up the X server. Nothing happened… So I started digging in the wacom driver source.

First Obstacle: Prolific PL2303 USB Serial Port

The first problem I encountered was with my USB-serial adaptor. Apparently, the wacom driver used a TCIOCGSERIAL ioctl, which is supposed to return information on a serial device, to determine if it’s talking to a serial or a USB device. If the ioctl fails, it thinks it’s not talking to a serial device, and starts talking USB HID to the tablet.

Unfortunately, the pl2303 driver in the linux kernel (as of version 2.6.32.8 that I tested) does not implement the aforementioned ioctl, even though it’s supposed to present a proper serial port to the system. So I had to hack the kernel, and add that ioctl in the pl2303 driver (patch against 2.6.32.8).

(edit: my pl2303 patch got included in linux 2.6.34, so you don’t need the patch any more)

Sadly however, although now the wacom driver realized that it was dealing with a serial device, the tablet still didn’t work…

Second Obstacle: The linuxwacom Driver

After a lot of digging around the source of multiple wacom driver versions, it turns out the guys at the linuxwacom project removed the code for old serial tablets from the driver sometime last year!

I tried installing a few older versions of the driver (anything prior to 0.9.1 had the serial code), but they would not compile with the much newer X.org headers in my system. Apparently some changes with the XInput extension broke the old driver. So I started hacking again.

First I tried back-porting the XInput changes from the newer wacom driver to the old 0.8.4 version, but although I managed to compile it, it would segfault upon being loaded by the X server. Evidently I screwed something up during the backport, which I could have probably fixed eventually, but I realized that it’s a bad idea to get stuck to the old wacom driver.

So instead I started from scratch in the opposite direction, re-integrating the old serial code from 0.8.4 to the most recent 0.10.4 wacom driver.

Success!

And indeed after a few hours of hacking, I managed to get my serial Wacom Intuos to work perfectly! Here’s the patch in case anyone needs it.

I must say it’s an impressive input device, pressure-sensitivity, tilt sensing, everything works perfectly. The only problem is that I still can’t draw any more than I could on paper :)

Stereoscopic OpenGL part2

Me with my shutter glassesMy obsession with stereoscopic rendering continues unabated. It’s just so fucking cool to write a bit of code and have 3D objects pop outside of your monitor and float above your keyboard.

Fact is, I couldn’t settle with my crummy anaglyph glasses see previous post. I had to try out proper shutter glasses and quad-buffer OpenGL visuals.

Thanks to nvidia’s policy of supporting quad-buffer visuals and stereo ports only on expensive Quadro graphics boards, and the proliferation of flat panels which are entirely unsuitable for use with shutter glasses due to ridiculously low refresh rates, I couldn’t do that with my PC. On the other hand, my trusty Silicon Graphics Octane2 workstation was more than up to the task as it comes with a stereo synchronization port and quad-buffered OpenGL support out of the box.

So off I go to ebay, where I bought the cheapest lcd shutter glasses I could find, the ASUS VR100 glasses which came once upon a time bundled with some expensive ASUS TNT2 graphics cards as a high-end gimmick.

SGI to ASUS VR100 adaptor circuitConnecting these glasses to SGI workstations has been done before and it was a piece of cake to follow that guy’s schematic and construct the necessary circuit to translate the signals from the SGI stereo port to those required by the shutter glasses.

The only problem I’ve had, is that my Octane2 has the low-end V6 graphics option, which apparently doesn’t provide a z-buffer when using stereo visuals.

3D tunnelNow I didn’t feel like z-sorting all polygons like the good old days when z-buffering was too expensive to use on underpowered PCs while doing software polygon rendering, so I tried to figure out a couple of graphics hacks that I could do which wouldn’t require a z-buffer to look right. So I came up with this swirling tunnel, and a simple wireframe teapot.

OpenGL stereoscopic anaglyphs and patents

An anaglyph is a combination of two images into one, in such a way that they can later be separated by viewing the image through appropriately colored transparent filters. The objective is to present slightly shifted views of the same 3D environment to each eye, in order to achieve depth perception (i.e. really perceive the 3rd dimension).

anaglyph glasses

I’ve never dealt with anaglyphs in the past, but during my recent week-old obsession with stereoscopy, I’ve stumbled upon a pair of free anaglyph viewing glasses (made out of cardboard and cellophane of course). So I couldn’t help but try to find out how I can use them with my own programs.
Read the rest of this entry »

Raytracing Anamorphic Images

A long time ago, I stumbled upon a couple of strikingly odd images on Jim Arvo’s web site, which are apparently called “anamorphic”. The idea behind an anamorphic image, is that it’s distorted in such a way, that its true shape can be seen only when viewed in a particular manner. In the case of these images, you’re supposed to print the image and place a highly reflective cylindrical object, such as a chrome pipe, at a specific marked location in order to see the geometric shapes correctly.

I kept the images back then, with the purpose of either finding an appropriate cylindrical object, or raytracing them to see what they look like, but for some reason I’ve forgotten all about them until I accidentally found them again yesterday, in a dusty corner of my filesystem.

So I decided to hack some code to add perfect (x^2 + y^2 = r^2) cylinder primitives to my raytracer and do a couple of renderings with those images texture-mapped onto a ground quad (I could just do the same thing with another raytracer such as pov-ray but where’s the fun in that?).

So anyway here are the anamorphic images along with the renderings (click on the images for the full rendering):

Follow

Get every new post delivered to your Inbox.