GL3DEngine v2.0 & GL3DLifeEngine
I can’t explain what I have done to improve the 3D engine, if I don’t
explain what it was doing before the upgrade. I will spend a short paragraph
explaining what GL3D Engine 1.0 does and then I will explain the upgrade I chose
to implement.
I started programming this 3D engine trying to think big. I wanted this to
be as close as I could to a professional 3D engine with room for improvement
if I had the opportunity. OpenGL is “linear”, there is no concept
of object. As far as OpenGL is concerned, there are no objects; it’s all
a bunch of points linked together forming triangles. Any changes made at one
point in the process of drawing triangles (such as setting the color of polygons)
will affect all the following polygons (all polygons will have the color we
set until we change the color again). So, using C++, I created an object oriented
structure for each 3D Object. For instance: a GL3DLight, a GL3DCamera and a
GL3DVAObject ARE_ALL GL3DObject using inheritance provided by C++.
In order to have a decent frame rate, we cannot afford to send every object
in the world to the video card. This latter will choke crunching numbers. We
must only draw objects that are in front of the camera. I implemented a quad
tree in which I store the ID of each object depending on its x,z coordinate.
(Note: In OpenGL, y is the height coordinate)
For every single frame, the program parses the tree and creates a linked list
of object to be drawn.
Drawing realistic 3D object can take hours if we don’t use a tool such
as 3D Studio Max. Computing manually the position of every point of simple cylinder
would probably take at least 15 minutes. So I implemented a tool that converts
ASE (ASCII Scene) into 3OB (3d OBjects) which is a file format I create for
the 3D engine. I could have loaded ASE file straight into the 3D engine, but
I wanted to have control over what is in the file and ASE is a text file which
take much longer to load. Load time of text file would noticeably increase when
you have many objects to load. 3OB is a binary file and therefore doesn’t
take as long to read. So I can create an entire scene in 3DStudio Max, export
it as an ASE file and convert it into 3OB file that I then load into the 3D
engine each time it starts
Finally, I have a bitmap manager and a 3D structure manager so that if I have
10 cars that have the same 3D structure but different bitmap, I only store the
vertices for the car once in the structure manager and draw it 10 times with
a different texture. The same way, I can have different object with the same
texture and the bitmap for that texture is stored only once in memory. This
makes a major difference when you start having thousands of objects that are
mostly similar.
The drawing below shows how the memory is organized between the different C++
classes. Arrays are represented as tables and pointers as arrows.
fig 1. GL3D Engine V1.0 Architecture
Well, this all sounds very nice, but you may ask, what did I improve that justifies
turning it into a project for the Modern Game Design class?
In order to have this 3D engine plug into the Marinakis’ artificial life
program, I had to make some major modifications and additions.
Here is the list of improvements up to this date:
• Object Templates
• Complex Objects
• Adding & removing object to/from the tree on the fly
• Transparency
• GL3DLifeEngine interface
• 2D User Interface
• Optimization
• Level of Detail
• Design the 3D Objects
• Vertex program
I will give a detailed description of each of these in the next section, but I will first make a quick overview.
Object Templates:
Object Template allows the user to have objects (3D Structure & texture)
ready to use in memory but without any actual position. They cannot be draw
to screen. It sound very similar to what the Texture manager and Structure manager
does, but a template associate both a texture and a structure. Obviously, without
the texture manager and the structure manager, I couldn’t have implemented
a template system efficiently since the template uses both. A template object
is like a class in C++. It is the blue print of an object.
Complex Objects
Complex object is a 3D object made out of many other objects. For example, an
animal has a body and legs. Each object can be translated and rotated independently
relative the complex object’s position and rotation.
Adding object to the quad tree on the fly
In version 1.0, all objects had to be in memory in order to build the quad tree.
The id’s of objects where added to each node of the tree as the tree was
built. Once the program started, no object could be added to the tree or removed
from the tree. That implies implementing the necessary functions to add the
ID of an object at the right location in the tree.
Transparency
Transparency is used to create some objects such as trees. A tree would have
too many polygons if we wanted to create every leaf. One way to create a good
looking tree and save on polygons is to map the texture of a tree with a transparent
background. Transparent objects have to be drawn in a specific order. So this
requires some ordering of the object being draw before actually drawing them.
GL3DLifeEngine Interface
The GL3DLifeEngine is a class inherited from GL3DScene. It has a set of functions
that Marinakis’ program requires in order to add, remove and draw objects
in the 3D world.
2D User Interface
A program without a user interface is useless. So I created a full set of classes
for user interface including text display, menu, window and button.
Optimization
Much optimization was needed and still is needed. Some functions may take more
CPU time than needed which slows down the whole process. As I mentioned earlier,
in a real time 3D program, speed is very important. Any program displaying 3D
graphic need to draw at least 15 frames per second or no one will be interested
in using it.
Level of Detail
Level of detail is used to improve performance. Basically, each 3D object will
have a very detailed 3d structure when they are close to the camera, a less
detail version of the object if the object is a little further from the camera,
and if the object is at the horizon, it has only one triangle with an image
of the object textured onto it. Far objects are basically billboards. It doesn’t
make sense to have a very detailed object at the horizon. The user cannot see
the details but the graphic card will still compute every point, every line,
every triangle and texture onto those triangles as if the object was close to
the camera.
3D Objects
Finally, the 3D engine is very nice but useless if we don’t have any 3D
object to load into it. So I created 3 types of animals (Spiders, LadyBugs and
Ants), 3 types of plants (Weed, Algae and SunPlants), 3 types of rocks and a
tree.
And for each of these objects, I created up to 3 different levels of detail
and for each level of detail of each animals and plants, I created 3 sizes since
the animals and the plants can grow.
Vertex Program
Vertex program is used to modify the vertices by the graphic card. In this program,
I use vertex programming to make the plant move as if it was a windy day. This
could be done without vertex program but the program would be very slow; I would
expect the frame rate to drop under 5 FPS. There are sometimes hundreds of plants
being drawn on the screen at the same time. The vertex program run on each plant
and modify the x,z coordinate of the vertices.
The graphic processor is modifying those points which allow having good looking
effects without asking too much to the main CPU of the computer.
As I showed the memory organization of GL3DEngine v1.0, I show on the graph below the memory organization in the new version of the 3D engine.
fig 2. GL3D Engine V2.0 Architecture
I should also mention how Marinakis’ program is going to plug in with
my program. And the best way of doing that is with a diagram
fig 3. Organization of the different modules
The whole logic of where object should be, where they should go, collision detection, AI of the animals is all done by Marinakis’ program ALIFE. I have no concept of collision and the program will happily draw 2 objects at the same location if ALIFE program asks me too. GL3DLifeEngine is only a 3D graphical interface.
FREE TYPE:
In order to write text to the screen within the program, I am using GNU FreeType.
They have done an excellent job of display smooth looking text based on TTF
fonts.
NEHE on Gamedev.net:
I have learned most of the basics and some of the advanced feature of OpenGL
on NeHe. The author of
this site has a large collection of OpenGL tutorial that are very well written.
Gamedev.net:
And of course, I have to mention the forum of gamedev.net
where I got excellent help every time I was stuck with a problem writting the
3D Engine.