icon.png

MantaEngine: A Java 3D renderer


Overview

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.
Oct. 2016
Gouraud shading with ambient, diffuse, specular lighting.

Github – https://github.com/tkwon09/PersonalProjects
Download (.jar) – MantaEngine.zip


Inspiration

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!

SsbbMario.jpg

Basically magic.

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:

  • Objects
  • Cameras
  • Lights

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:

  1. Object to World space
  2. World to View space
  3. Back-face cull
  4. Rasterize
  5. Color vertices
  6. 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.

manta_1.png

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.

manta_2.png

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:

manta_3.png

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.

manta_4.png

Slightly blue on the left, slightly red on the right.

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).

manta_5.png

Disco teapot.

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.


Conclusion

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.