GitHub repo - Open-GL-3D-Renderer

About this project

I grew up playing a lot of games, and always wondered how the 3D models of objects and game assets are actually rendered on screen, along with perfectly mapped textures. So I followed some online tutorials and created a very barebones 3D model renderer to teach myself exactly how it works.

Here's the basics: think about a 3 dimensional model of a car in a game. This model consists of entirely polygons, specifically triangles. Usually 10's of thousands of them, with each triangle's 3 vertices being positioned such that the final model resembles a real world object.

Final 3D render vs. the triangle wireframe. Even the square elements are made of two triangles stacked together. The tyres are a point of interest. The more circular we want something to appear in a render, the more densely packed and smaller the triangles need to be in order to remove jagged edges.

Code rundown

The program is written in Java and consists of a few main components:

  • Display manager - creates a window and runs animation frames
  • Model loader - creates VAO's and VBO's (explained later)
  • Raw models - no textures, just plain polygon vertices data
  • Textured models - raw models with an 'texture coordinates array'
  • Shader - used for lighting

It starts with a model that you want to render. I'll explain this with a cube to keep things simple. The first port of call is to create a wireframe. This is simply a collection polygons (triangles in the case of 3D graphics) that form a shape. To create a simple model, I'll use Blender, a free 3D modelling program.

To texture this model, it is unwrapped into its 'faces' and then a texture is mapped onto it.

This model is then exported as a .obj (object) file. These files are simply plain text formatted in a certain way. They contain both the vertex data that tells the renderer how to recreate the shape, as well as vector normals (used for calculating reflections) and coordinates that map the texture files onto its faces.

This file is then parsed by my program, and the model is stored something called a Vertex Array Object, or VAO for short. A VAO is a special kind of data structure used by OpenGL to store the information about a single rendered object. Within a VAO, are 1 or more Vertex Buffer Objects, VBO's for short. A VBO is an array, typically used to store 2D or 3D vertex data about the object in question. For example, at index 0 of the VAO used to store our cube, we might place a VBO of 3D vertex coordinates that specifies where OpenGL is to render polygons on screen. At index 1, we might place a VBO of texture coordinates, which are used to tell OpenGL how to map a texture image onto our model.

Further indexes of a VAO may be used to store things to do with vector normals and other such data. For fully fledged rendered models in games, it isn't unheard of to have as many as 16 or so different VBOs within a single VAO.

Method that creates a VAO object and returns its ID

Method that returns an untextured model. Creates 2 VBOs, one for vertex coordinate positions and another for texture mappings. These are then stored in the VAO specified by the ID, and the whole structure is returned, representing a single model.

A raw model is then created from the .obj file created in Blender. That model object is then textured, using the texture mapping coordinates also supplied by Blender. This is then wrapped in an entity, which allows us to track and manipulate the 3D position of this object while it's being rendered.

We then render this model and rotate it about its x and y axis until the display is closed.

A Successfully rendered 3D model!