|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
TUTORIAL 1: THE 3D ENGINE |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
INTRODUCTION First, it's necessary to explain
the basic concept... what is a 3d engine? The main sections of a 3d engine are: 1-The acquisition of the objects' data in structures. 2-The transformations to position the objects in the world. 3-Rendering the scene on the 2d screen. This is why we are here so... let's go to work! In this lesson, we will study how to define the main structures needed to draw a 3d object.
THE VERTICES Suppose you have an object and want to show it on a 2d screen. In order to do this, it's necessary to obtain information about its structure. How can we do this? First, we define some key points: the vertices of the object. Every vertex is composed of three coordinates x, y, z. Every coordinate must be expressed through a FLOAT or DOUBLE variable, this is because we always need the best resolution to render the scene. This solution is used in every 3d engine but it is not free of flaws, in fact it loses precision when the numerical value is too high. This fact limits the space in which the simulation can work. In a space simulator, we should be able to move through infinite space so we will face this problem eventually. To define a vertex in C, we use a structure composed of three variables x, y, z. typedef struct{ It's very important to keep in mind that all of the calculations that deal with the positioning and the rotation of the object are applied to the vertices, since they are the units that make up the basic structure. The second structure, in terms of importance, is the polygon.
THE POLYGONS The polygons are the faces of the object and
are composed from N vertices. In most 3d engines polygons are composed of 3
vertices hence we will use this rule as well. typedef
struct{ We will also declare a polygon_type array variable that will be filled with all the polygons that constitute the object. #define
MAX_POLYGONS 2000 But... look out! Our definition assigns 3 vertices to every polygon and these vertices are not shared with the other polygons. Actually, if we reflect a while we are going to see that every polygon of an object does in fact shares its sides, and also its vertices, with other polygons. So we have made a mistake! Well, it is not really a mistake, but we have increased, considerably, the real number of vertices on the scene well beyond what is necessary. We have already said the engine will use the vertices to carry out most of its calculations so we should really find another method to define the polygons. We could create a list of vertices that will hold all of the vertices of the entire object. Then, in order to define the polygons, we will use a sort of referencing scheme to "point" to the vertices of that list. We now declare an array variable of type vertex_type that will hold MAX_VERTICES vertices. #define MAX_VERTICES 2000 The polygon structure will not contain the vertices any more but only 3 numbers that will point to 3 elements of the vertices list. In this way more polygons can point to the same vertex. This greatly optimizes the design of the engine. typedef
struct{
THE OBJECT We do a little bit of cleanup here and organize the previous definitions in a structure that we will call obj_type. typedef
struct{ That's only a basic definition. In the future, we will add more fields that will identify the position, rotation and state of the object. At this point we can declare the object variable and fill the vertices list: obj_type obj; obj.vertex[0].x=0; obj.vertex[0].y=0; obj.vertex[0].z=0; //vertex v0obj.vertex[1].x=1; obj.vertex[1].y=0; obj.vertex[1].z=0; //vertex v1 obj.vertex[2].x=1; obj.vertex[2].y=0; obj.vertex[2].z=1; //vertex v2 obj.vertex[3].x=0; obj.vertex[3].y=0; obj.vertex[3].z=1; //vertex v3 obj.vertex[4].x=0; obj.vertex[4].y=1; obj.vertex[4].z=0; //vertex v4 obj.vertex[5].x=1; obj.vertex[5].y=1; obj.vertex[5].z=0; //vertex v5 obj.vertex[6].x=1; obj.vertex[6].y=1; obj.vertex[6].z=1; //vertex v6 obj.vertex[7].x=0; obj.vertex[7].y=1; obj.vertex[7].z=1; //vertex v7 Now the problem is on how to subdivide our cube in triangles. The answer is simple: every face of the cube is a square composed of two adjacent triangles. So our cube will be composed of 12 polygons (triangles) and 8 vertices.
The list of polygons must be filled like so: obj.polygon[0].a=0;
obj.polygon[0].b=1; obj.polygon[0].c=4; //polygon v0,v1,v4 You must keep in mind that in order to define the polygons properly it is necessary to always use the same clockwise or counter-clockwise direction for all the polygons on the scene. We will see in the next tutorial, how the direction is used to control weather the polygon is visible or not. So pay close attention to the way you define the polygons or many of them will not be visible. We will use the counter-clockwise method (for example the first polygon is defined by v0,v1,v4 or v1,v4,v0 or v4,v0,v1 and not v1,v0,v4 or v0,v4,v1 or v4,v1,v0).
ANOTHER MORE ELEGANT WAY TO DEFINE OUR OBJECT In C/C++ we can fill the obj_type structure using this more elegant way:
You can also see that we changed the vertices coordinates from 0,1 to 10,-10. This is intentional, In fact, we need to have the center of the object at 0,0 (we will understand why in the next tutorial). Our object is also 20 times bigger (just to easily manage coordinates).
CONCLUSIONS That's all for this lesson. In the next one, we will begin to use OpenGL to show our cube on the screen. If you have any doubts or find mistakes don't hesitate to write me at info[at]spacesimulator.net SOURCE CODE Download the source code here: C/C++ source code
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
©2000-2005 Damiano Vitulli. All Rights Reserved. No Portion Of This Site May Be Reproduced Without Permission. Best viewed at 1024x768. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||