I wrote this thing ages ago for a commercial project for the now-defunct subsidiary of Sony, Sony Development. We were trying to make a giant pinball machine where you tilted the entire machine to play. To test the physical controller hardware as they worked the kinks out of the design, they needed a little 3D engine to hook up to them so they could see what it would do. So in about a week, I wrote one.
It’s a little odd as engines go in that it loads Lightwave 6.x (or greater) scene and model files and renders them, and then lets you fly a camera around and look at them. It lights the scene according to whatever lights you put in the scene, but all lights are translated as point lights. I never got spotlights or area lights working. It does respect global ambience settings in the scene, though, as well as maintain the hierarchical relationship between all the scene elements (i.e., parenting of scene elements is preserved at runtime.
It eventually ended up being listed in the news section on the now defunct Flay.com, one of the world’s more important Lightwave 3D web sites, and OpenGL.Org also had my listing. I even found a web site in Japan that linked to the original page. Too bad I can’t read Japanese! The engine has been downloaded tens of thousands of times since I posted it after SIGGRAPH 2001.
The engine does do texture maps, but only UV textures, and there are a few ways to apply the textures in Lightwave that don’t actually work. The best approach seems to be to convert whatever conventional texture mapping you might have on your models into UV maps using the “Make UVs” tool in the “Map” toolset in modeler. Since the loader doesn’t handle DMAP chunks, models using cylindrical or spherical mapping need to have the vertices split at the seam, or you’ll get mapping errors.
The source code will compile under either Windows, using Microsoft Visual C++ 6.x or greater, or under Linux using GCC. Yup, it’s cross-platform code!
Download the source code, binaries and sample data here. It’s pretty tiny by modern standards – only 3 megs, even though it includes all the model files and textures and whatnot that you get with it. It’s a fairly modest example of a 3D engine. Once I got the object and scene loaders working, the rest of the engine was done in about five days. It does give some good example code for reading objects in native Lightwave LWO2 format, though. By the way, in the ‘credit where credit is due’ department, I started with the example ‘C’ loader code written by Yoshiaki Tazaki at D-Storm.
Once you’ve gotten it to compile (it shouldn’t be difficult if you know how to use the compiler at all), run it by giving a parameter of either a model file or a scene file. If you give it a scene file as a parameter, it’ll assume all the assets are right there in the same directory with you, even if the scene file says otherwise. If you give it a model file as a parameter, it’ll just load the model file and let you spin it around and look at it from different angles. If you can’t compile the project or don’t want to bother, binary executables are included for both Linux and Windows.
A comment: this project was set up to compile from KDevelop in versions prior to 2.x. If your version is more recent than that, you’re going to have a few problems getting to compile as a project using KDevelop. I’ll may revisit this and make a newer version with new project files (thought I can’t promise when.)
Interestingly, the Linux version runs significantly faster than the Windows version does, even though it’s exactly the same code. I think Linux just works better from the standpoint of interfacing the OpenGL API with the hardware. I know I could do a lot more about optimizing the rendering pipeline, though. Right now the only thing I do is sort the polygons by material; this cuts down on having to use the GL material commands for every single darned polygon, and it sped things up a lot. It’s still not a really quick engine as engines go, but it’s quicker than it first was. I never even implemented tri-strips, and that would have sped it up at least double.
I’ve absolutely got to offer a caveat here as well: I wrote this engine as an exercise, and I stopped before I finished it. There are leftovers and leavings of various ideas in it that I never implemented. The object and scene loading classes themselves are fairly clean, however, and I did my best to keep that functionality as encapsulated as possible so they could be reused by somebody else if needed.
Could I write the same code now? No. If you don’t use linear algebra for 3D for a few years, you forget how. Could I learn to write the same code now? Absolutely. I did it before. I can do it again.
Update: It Runs on a Raspberry Pi
My Raspberry Pi 4 running OpenGL code I wrote over 20 years ago and ported to the Pi in August of 2016. The fastest of these windows is running 120 frames per second, and the CPU is barely warm to the touch.
For a lark, I decided to try compiling this on a Raspberry Pi, and to my great surprise, apart from a small tweak to one of the headers, it worked! Thinking on it, the Raspberry Pi is actually much more powerful than the big bruiser of a desktop machine I developed it on in the first place, yet the computer is no bigger than a pack of cards and draws only about 15w of power. The lightbulb in your refrigerator, if you still have one that isn’t LED based, probably draws more.
I’ve recently finished a short contract doing preproduction work on SciFi Channel’s new “Battlestar Galactica” mini-series, and now I’m working on some web development with PHP and MySQL, some Lightwave animation for a car commercial and an OpenGL game demo. Man, when it rains it pours.
I worked under the great Gary Hutzel, and worked under his direct guidance every single day. I was in heaven. I was told that there would be a place for me on production.
Then I got told that Hutzel had moved the whole production thing to Canada, and that I hadn’t been invited to come with.
The nGENE
Here’s the source code and compiled binaries for my little OpenGL engine, which I have named the “nGene” after a suggestion by a coworker.
It’s a little odd as engines go in that it loads Lightwave 6.x (or greater) scene and model files and renders them, and then lets you fly a camera around and look at them. It lights the scene according to whatever lights you put in the scene, but all lights are translated as point lights. I never got spotlights or area lights working. It does respect global ambience settings in the scene, though, as well as maintain the hierarchical relationship between all the scene elements (i.e., parenting of scene elements is preserved at runtime.
To clarify the copyright status of the nGene, it’s open source and licensed under the LGPL, meaning you can use this code for your commercial projects if you wish, without having to worry about having to release the code for it or your own project along with the compiled form. By all means, steal the parts you like and toss them into your project if you think it’ll help. It’s why I wrote it in the first place. Note that I’m not responsible for the results, i.e, if it breaks, you get to keep all the pieces.
If you do download it, note that you’ll be in good company – the nGene has been downloaded over a quarter million times since I originally posted it.
Special thanks to gifted artist and animator Eric Estrada, currently a lighter at Dreamworks, for the 3D scan of his head.
It texture maps, but only UV textures, and there are a few ways to apply the textures in Lightwave that don’t actually work. The best approach seems to be to convert whatever conventional texture mapping you might have on your models into UV maps using the “Make UVs” tool in the “Map” toolset in modeler. Since the loader doesn’t handle DMAP chunks, models using cylindrical or spherical mapping need to have the vertices split at the seam, or you’ll get mapping errors. Also, I never got around to writing the polygon smoothing algorithm, so for now it’s flat shaded only.
The source code will compile under either Windows, using Microsoft Visual C++ 6.x or greater, or under Linux using GCC. Yup, it’s cross-platform code!
Download the source code, binaries and sample data here. It’s about 3 megs because of all the model files and textures and whatnot that you get with it. I wouldn’t get too excited if I were you – once I got the object and scene loaders working, the rest of the engine was done in about five days. It does give some good example code for reading objects in native Lightwave LWO2 format, though. By the way, in the ‘credit where credit is due’ department, I started with the example ‘C’ loader code written by Yoshiaki Tazaki at D-Storm.
UPDATE: I’ve only just now gotten around to fixing a problem with the project files that kept you from using KDevelop 2.1. I know 3.0 is out, that’s next, but at least this version works in Linux now. It’s a tarred, gzipped archive.
Once you’ve gotten it to compile (it shouldn’t be difficult if you know how to use the compiler at all), run it by giving a parameter of either a model file or a scene file. If you give it a scene file as a parameter, it’ll assume all the assets are right there in the same directory with you, even if the scene file says otherwise. If you give it a model file as a parameter, it’ll just load the model file and let you spin it around and look at it from different angles. If you can’t compile the project or don’t want to bother, binary executables are included for both Linux and Windows.
Interestingly, the Linux version runs significantly faster than the Windows version does, even though it’s exactly the same code. I think Linux just works better from the standpoint of interfacing the OpenGL API with the hardware. I know I could do a lot more about optimizing the rendering pipeline, though. Right now the only thing I do is sort the polygons by material; this cuts down on having to use the GL material commands for every single darned polygon, and it sped things up a lot. It’s still not a really quick engine as engines go, but it’s quicker than it first was.
I wrote this engine as an exercise, and I stopped before I finished it. There are leftovers and leavings of various ideas in it that I never implemented. The object and scene loading classes themselves are fairly clean, however, and I did my best to keep that functionality as encapsulated as possible so they could be reused by somebody else if needed. So don’t cringe when you read the code. You’ve been warned.
It was used by the UCLA Laboratory of Neuro-Imaging – here is the testimonial letter I received from Craig Schwartz:
E-MAIL: craig@nospamplease.loni.ucla.edu
X-Mailer: ELM [version 2.5 PL2]
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
X-Mailer: ELM [version 2.5 PL2]
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Dear Gene,a few weeks ago you helped me with nGene – which I’ve been using to debug a small java library which creates LWO files as output. Although the contributed ModelViewer module did not have everything I wanted, and was unable to display the largest of my test data sets, it did enough (supported by nGene) that I was able to use it to keep my coding, thereby contributing significantly to my successful project. Many thanks! Craig SchwartzUCLA Laboratory of Neuro-Imaging
I’ve just finished a couple of contracts for the U.S. Government, of all things! A lab rat and a bald eagle, both animated talking spokespersons for two different branches of the government (the National Instituts of Health and the Air Mobility Warfare Center at Fort Dix). You take your jobs where you find them, but how odd that I would find these.
The rat’s name was Sydney, and I understand it was some sort of inside joke at the National Institute of Health. And yeah, Sydney was a girl rat. Go figure.
Oh, and I’ve started learning Maya, now, too. It turns out that as fun as Lightwave is, 99.9% of the jobs out there want strong Maya skills. I love Lightwave, but I also like to eat and live in a house.
I am nearing completion of a small suite of plugins for a commercial client – what an adventure that’s been! I was writing Lightwave plugins to translate STL object model format into Lightwave model format, while preserving the materials attributes (raw STL doesn’t support materials). Then I had to write a new shader to render them that took into account the surface smoothing errors that the STL models tend to have in them (because of the strange tesselation choices the exporting software that creates STL files tend to make). I got it all working, finally. But boy was that stuff hard. I decided I’d never do another Lightwave plugin after that.
Recent Comments