New! Unlimited audio, video & web asset downloads! Unlimited audio, video & web assets! From $16.50/m
Advertisement
  1. Game Development
  2. Programming
Gamedevelopment

Let's Build a 3D Graphics Engine: Spaces and Culling

by
Difficulty:IntermediateLength:MediumLanguages:
This post is part of a series called Let’s Build a 3D Graphics Software Engine.
Let's Build a 3D Graphics Engine: Linear Transformations
Let's Build a 3D Graphics Engine: Rasterizing Line Segments and Circles

Welcome! This is the third part of our series on 3D graphics engines. If you made it this far into the series, you'll be glad to know that this piece will be much lighter on the math aspect of 3D engines, and instead will take a focus on more practical things - in particular, adding a camera and a basic rendering system.

Tip: If you haven't read the first two parts yet, I highly suggest that you do before continuing.

You can also get extra help over on Envato Studio, where you can choose from a wide range of high-quality 3D Design & Modeling services from experienced providers. 

3D Design  Modeling services
3D Design & Modeling services on Envato Studio

Recap

First off, let's take a look at the classes that we've created so far:

Using these two classes on their own has proven a little messy thus far, and drawing every possible point can drain your system's memory fairly quickly. To solve these problems, we are going to introduce a new class into our game engine: the camera.

Our camera is going to be where all our rendering happens, exclusively; its going to cull all of our objects to the screen, and it is also going to manage a list of all of our points.

But before we can get to all of that, we must first talk a little bit about culling.


London Culling

Culling, by definition, is the selection of objects from a larger group of objects. For our game engine, the small selection that we take will be the points that we want to draw to the screen. The larger group of objects will be every point that exists.

Doing this drastically reduces your engine's drain on a system's memory, by drawing only what a player is actually able to see, rather than an entire world's worth of points. In our engine, we are going to do this by setting parameters for a view space.

Our view space will be defined across all three of the traditional axes: x, y, and z. Its x definition will consist of everything between the window's left and right boundaries, its y definition will consist of everything between the window's top and bottom boundaries, and its z definition will be between 0 (where the camera is set) and our player's view distance (for our demonstration, we will be using an arbitrary value of 100).

Prior to drawing a point, our camera class is going to check to see whether that point lies within our view space. If it does, then the point will be drawn; otherwise, it will not.


Can We Get Some Cameras in Here?

With that basic understanding of culling, we can deduce that our class will look like this, so far:

We are also going to have our camera handle all of the rendering for our engine as well. Depending on the engine, you will find that renderers are often separated from the camera systems. This is typically done to keep the systems encapsulated nicely, since - depending on the scope of your engine - the two could get quite messy if kept together. For our purposes, though, it will be simpler to treat them as one.

First, we're going to want a function that can be called externally from the class that will draw the scene. This function will cycle through each of the points that exist, compare them to the camera's culling parameters, and draw them if applicable.

ViewFrustum
Source: http://en.wikipedia.org/wiki/File:ViewFrustum.svg

Tip: If you wanted to separate your camera system from your renderer, you could simply create a Renderer class, have the camera system cull the points, store the ones to be drawn in an array, and then send that array to the draw() function of your renderer.


Point Management

The final piece of our camera class is going to be its point management system. Depending on the programming language you are using, this could just be a simple array of all of the objects that can be drawn (we will be handling more than just points in later parts). Alternatively, you may have to use the language's default object parent class. If you are super unlucky, you will have to create your own object parent class and have each drawable class (so far only points) be a child of that class.

After adding that into the class, a basic overview of our camera would look like this:

With these additions, let's improve a little upon the program that we made last time.


Bigger and Better Things

We are going to create a simple point drawing program, with the sample program that we created last time as a starting point.

In this iteration of the program, we are going to add in the use of our new camera class. When the D key is pressed, the program will redraw the screen without culling, displaying the number of objects that were rendered in the top right-hand corner of the screen. When the C key is pressed, the program will redraw the screen with culling, also displaying the number of rendered objects.

Let's take a look at the code:

Now you can see, first-hand, the power of culling! Do note that if you are looking through the sample code, some things are done a bit differently in order to make the demos more web-friendly. (You can check out my simple demo here.)


Conclusion

With a camera and rendering system under your belt, you can technically say that you've created a 3D game engine! It may not be overly impressive just yet, but it's on its way.

In our next article, we'll be looking at adding some geometric shapes to our engine (namely line segments and circles), and we will talk about the algorithms that can be used to fit their equations to the pixels of a screen.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.