MantaEngine: A Java 3D renderer
A simple 3D renderer built in high school. Recent improvements complete all features.
|Feb. – June 2009
Base engine with .obj file parser, z-sort, backface cull, rasterizer, simple lighting.
Gouraud shading with ambient, diffuse, specular lighting.
Github – https://github.com/tkwon09/PersonalProjects
Download (.jar) – MantaEngine.zip
During my childhood, real-time 3D graphics went from simple flat-shaded polygons to fully textured 3D models with normal maps, lighting, shadows, and a million triangles!
My fascination for 3D graphics never left me. So, during my senior year in high school, I tried investigating the arcane arts of 3D rendering.
2009: First Attempts
When I began, I was a novice programmer with little experience under my belt. The most complex piece of software I had programmed was a simple Bomberman game. Fortunately, the internet is abundant with resources. Combining information from several tutorials, I came up with a basic structure for the engine.
The engine kept track of several entities in a World:
Each entity had a position, rotation, and scale in World space. Objects loaded into the engine were stored as triangles, vertices, and vertex normals. The rendering pipeline followed these steps:
- Object to World space
- World to View space
- Back-face cull
- Color vertices
- View to Screen space
Problems with Matrices
To implement the transformations between spaces, I needed to dive into linear algebra. My high school classes touched on barely enough to get me started. Initially, I was determined to do everything by hand. However, matrix operations was beyond my programming capabilities at the time.
I looked for Matrix and Vector implementations online. These required me only to understand the formulae: Perfect for a novice programmer.
Once I completed steps 1-4, I rendered my own piece of geometry.
A humble start. Still, I was excited. For months I had stared at a blank screen while debugging the renderer, unsure if the z-sorting was incorrect, the backface culling wasn’t working, or if my virtual camera was simply pointing the wrong direction.
In the tradition of 3D rendering, my first piece of complex geometry was the Utah teapot.
Problems with Shading
The next step was to add color and lights. I chose Gouraud shading for its simplicity.
It turned out Gouraud shading was too complex for me in high school. The calculations were simple, but the theory was beyond me. So, I couldn’t properly debug my implementation. In the end, I simply colored vertices based on their orientation to a single light source.
This was the end result:
You could also spin the teapot:
However, I was still dissatisfied. I knew I was working with limited understanding, and felt frustrated because of it.
It doesn’t mean I didn’t try. I followed NeHe’s excellent OpenGL tutorials to produce my second attempt: MobulaEngine. This engine used a simple OpenGL 2.0 pipeline to render 20 MB .obj files in grayscale.
Despite my best attempts, I realized I was following the tutorials blindly. Acknowledging that I was missing too many of the fundamentals to continue, I put the project on hold.
2016: Recent Development
MantaEngine turned up while I was browsing through my old projects. Recalling my dissatisfaction, I decided to tackle its final missing feature: Gouraud shading.
A class I took in robot vision helped me helped me recall the basics. In about an hour I had diffuse lighting debugged and properly handling multiple light sources.
Next was handling ambient light and mixing it properly with differently colored lights.
Once I got the equations right, I added specular and fresnel (the shiny spot).
The renderer created slight artifacts in the rasterizer. Because they occurred outside of Gouraud shading, I didn’t solve them.
It was time to make the engine demo-ready. I used semaphores to solve object/light removal problems, added additional objects, additional lights, and added tweakable options.
Now that I have a better understanding of linear algebra, computer architecture, and rendering, I’d like to try more complex techniques.
First, I want to try implementing modern techniques.
Second, MantaEngine’s structure is rather amorphous. Next time, I want to evaluate my program’s structure more deliberately as I develop.
Looking at old code was extremely educating. It was useful to see what I’d do differently and what I’d do the same.
All in all, it was nice to put closure on MantaEngine.
The game image is from Super Smash Bros. Brawl by Nintendo.