Jeff Molofee (nehe) OpenGL Tutorial Tenth lesson Translated by Cker
This class is written by Lionel Brits (βtelgeuse). In this lesson, we only explain the added code. Of course, only the code written in the course is not running. If you are interested in knowing how each row code is running, download the full source code and track the source code while browsing this lesson. Well, now I welcome the tenth lesson that I don't see it. Up to now, you should have the ability to create a rotating cube or a group of stars, should you feel some of the 3D programming? But still please wait! Don't immediately impulsive to start writing a quake iv, it is good ... :). It is also difficult to create a cool opponent that can decide a dead war by rotating cubes .... :). Now that these days you need is a big one, more complex, dynamic 3D world, which has space-free six degree freedoms and fancy effects such as mirror, entrance, twisted, etc., of course, there must be faster Frame display speed. This class will explain a basic 3D world "structure" and how to swim in this world. Data Structure When you want to use a series of numbers to perfectly express 3D environments, with the rise of environment complexity, this work is also rising. For this reason, we must classify data to have more operability. The sector's definition is displayed in the program list header. Each 3D world can basically be regarded as a collection of sector. A sector can be a room, a cube, or any closed interval. TypeDef struct tagsector // Create a sector section structure {int Numtriangles; // sector's triangle number Triangle * Triangle; / / Pointer to triangular array} sector; // named Sector
A sector includes a series of polygons, so the next goal is Triangle (we will use only triangles, this writing code is easier). Typedef struct tagtriangle // Create Triangle triangle structure {Vertex Vertex [3]; // Vertex vector array, size 3} triangle; // named Triangle
The triangle is essentially a polygon of (two or more) vertices, and the vertex is also our most basic classification unit. The vertex contains the data that OpenGL truly interested. We define each vertex of triangles (x, y, z) and their texture coordinates (U, V) in 3D space. Typedf struct tagvertex // Create a Vertex vertex structure {float x, y, z; // 3D coordinate float u, v; // texture coordinate} Vertex; // Name Vertex
Loading files directly stored data inside the program that allows programs to be too dead and boring. Loading world data from disk, will bring us more flexibility, allow us to experience different worlds without being forced to recompile the program. Another benefit is that users can switch world data and modify them without knowing how programs are read to output them. Type of data files We are ready to use text format. This is easier to edit, and the code written is less. Waiting for us to use binary files. The problem is, how can I get data from the file? First, create a new function called setupworld (). Define this file as Filein and open the file using a read-only mode. We must close the file after it is used. Let's take a look at the current code: // Previous definition: char * worldfile = "data // world.txt"; void setupWorld () // Set our world {file * filein; // work file filein = fopen (WorldFile, "RT"); // Open File ... (read data) ... fclose (filein); // Close file return; // Return} Zhang Cai 0573-6082032 (h) Next challenge is Read each individual text line into the variable. There are many ways to do this. One problem is that all rows are not all lines all contain meaningful information. Dark lines and comments should not be read. We created a function called ReadStr (). This function reads a meaningful row to an initialized string from a data file. Below is the code: void readstr (file * f, char * string) // reads a string {DO // cycle start {fgets (string, 255, f); // read a row} while ((String [0 ] == '/') || (String [0] == '/ n')); // Test if it is necessary to process return; // return}
Next, we read the section data. This lesson will only process a segment, but it is easy to achieve a multi-zone engine. Let us turn attention to setupworld (). The program must know how many triangles in the section contain. We define the quantity of triangles in the data file: Numpollies n Next is the code to read the number of triangles: int NumTriangles; // Different quantity of triangle in the section CHAR OneLine [255]; // Store data string ... ReadStr (Filein, OneLine); // Reads a line of data SSCANF (OneLine, "Numpollies% D / N", & Numtriangles); // Read the quantity of triangles
The remaining world load process uses a similar approach. Next, we initialize the segment and read some data: // Previous definition: sector sector1; char one orine [255]; // Store data string int num turning or // section of triangular quantity float x, Y, z, u, v; // 3d and texture coordinates ... sector1.triangle = new triangle [Numtriangles]; / / For Numtriangles triangular assignment memory and set pointer sector1.numtriangles = Numtriangles; // Define sections 1 Triangular quantity // traversal section of each triangle for (int Triloop = 0; triloop Rotate and convert the lens position according to the user's instruction. Rotate the world around the origin to rotate the world with the opposite direction of the lens. (The illusion of the lens rotation) is translated in the opposite way to the lens translation (people produce the illusion of the lens movement). This is very simple to implement. Bill below from the first step (translation and rotating the lens). IF (Keys [vk_right]) // Right Direction button Press? {yrot - = 1.5f; // Rotate the scene} if (Keys [vk_left]) // Left direction button? {yrot = 1.5F; / / Rotate the scene to the right} IF (Keys [vk_up]) / / The up-direction button is pressed? {XPOS - = (float) sin (Heading * PiOVER180) * 0.05f; // The X plane mobile ZPOS - = (float) Cos (Heading * PiOver180) * 0.05F; // Walkbiasangle> = 359? {Walkbiasangle = 0.0F; // Set WalkBiasangle to L 0} else // Otherwise {WalkBiasangle = 10; // If WalkBiasangle <359, increase 10} WalkBias = (float) sin (WalkBiasangle * PiOver180) /20.0f; // Let the player generate a skip sensing} if (Keys [vk_down]) / / down the direction button? {XPOS = (float) sin (Heading * PiOVER180) * 0.05F; // Walk along the X plane moves ZPOS = (FLOAT) COS (Heading * PiOVer180) * 0.05f; // Along the player Z plane mobile IF (Walkbiasangle <= 1.0F) // WalkBiasangle <= 1? {Walkbiasangle = 359.0f; // Make WalkBiasangle equal to 359} else / / Otherwise {Walkbiasangle- = 10; // If WalkBiasangle> 1 minus 10 } walkbias = (float) sin (Walkbiasangle * PiOver180) /20.0f; // makes the player generating a sense of jump} This implementation is simple. When the left and right arrow keys are pressed, the rotation variable YROT has increased or decreased accordingly. When the current rear direction button is pressed, we use the SINE and COSINE functions to regenerate the lens position (you need some knowledge of the triangle function :-). PiOver180 is a very simple set of converting factors for discretion and radians. Then you may ask: What does Walkbias mean? This is the word of the invention of Nehe :-). Basically, when people walk, the head produces the magnitude of the upper and lower swings. We use simple SINE sine waves to adjust the Y-axis position of the lens. If you don't add this, just move forward, the program doesn't look so good. Now, we already have these variables below. Steps 2 and 3 can be started. Since our procedure is not very complicated, we do not need to create a function, but complete these steps directly in the display cycle. INT Drawglscene (GLVOID) / / Draw OpenGL Scene {Glclear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Scenario and Deep Buffer GLLoadIdentity (); // Reset Current Matrix GLFLOAT X_M, Y_M, Z_M, U_M, V_M; // Verte Temporary X, Y, Z, U and V value GLFLOAT XTRANS = -Xpos; // The size of the game when the player is translated in the X-axis, and the size of the player is transferred in the z-axis. GLFLOAT YTRANS = -walkbias-0.25f; // Used to swing up and down GLFLOAT SCENEROTY = 360.0F - yRot; // 位 位 位 g 整 g g g g g g g g (((g ((((((( 1.0F, 0, 0); // Rotate the GLROTATEF (ScenerOrOroty, 0, 1.0F, 0); // According to the direction of the player's front, XTrans, YTRANS, ZTRANS); // Take the player panning scenes centered glBindTexture (GL_TEXTURE_2D, texture [filter]); // filter according to the selected texture numtriangles = sector1.numtriangles; // number of triangles Sector1 made of triangular @ processed one by one for (int loop_m = 0; loop_m // The third point x component y_m = sector1.triangle [loop_m] .vertex [2] .y; // The third Y component z_m = sector1.triangle [loop_m] .vertex [2] .z; // The third point Z component u_m = sector1.triangle [loop_m] .vertex [2] .u; // second point U texture coordinate V_m = sector1.triangle [loop_m] .vertex [2] .v; // Two-point V texture coordinate GLTEXCOORD2F (U_M, V_M); GLVERTEX3F (X_M, Y_M, Z_M); // Set texture coordinates and vertex glend (); // triangle drawback} return true; // Return} to get! We have completed our first frame. This is definitely not there any quake, but cough ... we are absolutely not Carmack or Abrash. When running the program, you can press the F, B, PGUP and PGDOWN keys to see the effect. PGUP / PGDOWN simple up and down lens. If Nehe decides, the texture used in the program is taken from the photos on my school ID documents and do a relief effect .... :). Now you may think about what to do next. But don't consider using these code to implement a complete 3D engine, it is not the case. You may wish that you have more than a sector in your game, especially those like entrances, you may also need to use polygons (more than 3 vertices). The program now code implementation allows the load to load multiple sector and remove the back (the back lens does not need to draw the polygon). I will write such a tutorial in the future, but this requires more mathematical knowledge foundations. Nehe (05/01/00): I have added annotations to each line of code referenced in the tutorial. I hope this is meaningful to you. Only a few lines of code have been made before this. If there is any problem with the tutorial and code (this is my first tutorial, my explanation may also be unclear), please don't hesitate to give me. (iam@cadvision.com).