{This lesson I will teach you how to use three different texture filtering methods. Teach you how to use the keyboard to move the object in the scene, you will also teach you to apply simple light in the OpenGL scene. This lesson contains a lot of content, if you have questions about the previous courses, go back to review. Good understanding of basic knowledge is very important before entering the following code. We still modified on the code of the first lesson. As long as before, as long as there is any big change, I will write the entire code.
First we have to add the SYSUTILS unit and the GLAUX unit. }
Uses sysutils, OpenGL, Windows, Messages, Glaux in '../../glaux/glaux.pas';
// The following lines are increasing new variables.
// We add three Boolean variables. // Light variable tracks the illumination. // Variable LP and FP are used to store the status of 'L' and 'F' keys. // I will explain the importance of these variables later. Now, put it first. Light: boolean; // Light Source On / Off LP: Boolean; // L button Press? FP: Boolean; // F button presses?
/ / Now sets five variables to control the step size, //, and the rotational speed around the X-axis and the Y-axis about the X-axis and the Y-axis. // also created a z variable to control the distance from the depth of the screen. XROT: GLFLOAT; // X Rotate Yrot: GLFLOAT; // Y Rotate XSpeed: GLFLOAT; // X Rotation Speed YSPEED: GLFLOAT; // Y Rotation Speed
Z: GLFLOAT = -5.0 f; // Deepen the distance of the screen
/ / The array is then set to create a source. // We will use two different lights. // The first is called ambient light. The ambient light comes from all directions. // The objects in all scenarios are in the illumination of ambient light. // The second type of light is called diffuse light. // The diffuse light is generated by a particular light source and reflects on the surface of the object in your scene. // Any object surface under diffuse light is directly illuminated bright, // and the area that is almost unlimited is to be dark. // This will produce a very good shadow effect on the edge of the wooden box we created. // Creating a source of the source and the creation of color is exactly the same. // The first three parameters are RGB three-color components, and the last one is an Alpha channel parameter.
/ / So, the following code we get the white ambient light of the halflight (0.5F). // If there is no environmental light, it will become very dark if you are not logged. Lightambient: Array [0..3] of glfloat = (0.5, 0.5, 0.5, 1.0); // Ambient light parameter (new) // Next line code we generate the brightest diffuse light. // All parameter values are available in maximum 1.0f. // It will look at the front of our wooden box and look good. Lightdiffuse: Array [0..3] of glfloat = (1.0, 1.0, 1.0, 1.0); // diffuse light parameters (new) // We save the location of the light source. // The first three parameters are the same as GLTranslate. // The displacement on the XYZ axis is respectively. // Since we want to light directly in the wooden box directly, the displacement on the XY axis is 0.0. // The third value is the displacement on the Z axis. / / In order to ensure that the light is always in front of the wooden box, // We put the position of the light source toward the observer (which is you.) Moved out the screen. / / We usually refer to 0.0 points of the Z-axis in the position of the screen of the display of the display. // So the displacement on the Z-axis is finally 2.0. // If you can see the light source, it floats in front of your monitor. / / Of course, if the wooden box is not behind the screen of the display, you can't see the box. // "Translator Note: I greatly appreciate the patience of Nehe. // Sometimes I am more troublesome, such a simple thing, what is he talking? / / But if everything is clear, you will also cover this page to see it? "// The last parameter is taken from 1.0F. // This will tell OpenGL here the coordinates of this is the location of the source, and I will explain more in the later tutorial. LightPosition: Array [0..3] of glfloat = (0.0, 0.0, 2.0, 1.0); // The texture type used in the light source position (new) // Filter variable tracking is displayed. // The first texture (Texture 0) is built using GL_Nearest filtering. // Second texture (Texture 1) uses GL_LINEAR (linear filtering) mode, // The closer the image from the screen, the smoother it. // Third texture (Texture 2) Use the MIPMAPPED filtering method, // This will create an excellent appearance. / / According to our type of use, the value of the Filter variable is equal to 0, 1 or 2, respectively. // Let's start from the first texture. // Texture is allocated to allocate storage spaces for three different textures. // They are located in Texture [0], TEXTURE [1] and Texture [2].
Filter: gluint; // filter type texture: array [0..2] of gluint; // 3 texture storage space
Procedure Glgentextures (N: Glsizei; Var Textures: gluint); stdcall; external opengl32;
Procedure Glbindtexture (Target: Glenum; Texture: gluint); stdcall; External OpenGL32;
Function Glubuild2dmipmaps (Target: Glenum; Components, Width, Height: Glint; Format, Atype: Glenum; Data: Pointer: Integer; stdcall; external glu32 name 'glubuild2dmipmaps';
{Now load a bitmap and use it to create three different textures. This lesson uses the GLAUX auxiliary library to load the bitmap, so you should confirm whether you contain the GLAUX library when compiling. I know that Delphi and VC include the GLAUX library, but other languages cannot be guaranteed. "Translator Note: Glaux is the OpenGL auxiliary library, according to OpenGL cross-platform characteristics, the code on all platforms should be universal. However, the auxiliary library is not a formal OpenGL standard library, and does not appear on all platforms. But just available on the Win32 platform. Oh, BCB is certainly no problem. Here I only make an annotations for new code. If you have questions about a row code, check out the tutorial. That lesson explains the contents of loading and creation of textures. At the last code, we increase the following code after the last paragraph code and the glresizewnd (). This is almost the same as the code loaded in the sixth lesson. } Function LoadBMP (FileName: Pchar): PTAUX_RGBIMAGEREC; VAR BitmapFile: Thandle; // File Handle Begin if filename = '' THEN / / Make sure the file name is provided. Result: = nil; // If not provided, return null bitmapfile: = fileopen (filename, fmopenwrite); // Try Open File if BitmapFile> 0 THEN // File exists? begin fileclose (bitmapfile); // Close handle Result : = AUXDIMAGELOADA (FileName); / / Load bitmap and return the pointer ELSE RESULT: = nil; // If load fails, return nil. END;
Function loadtexture: boolean; // Load bitmap and convert to texture var status: boolean; // status indicator TextureImage: array [0..1] of ptaux_rgbimagerec; // Create texture storage STATUS: = false; ZeromeMory (@TextureImage); // Set the pointer to null textureImage [0]: = loadingBMP ('Walls.bmp'); if TextureImage [0] <> nil dam status: = true; // Set Status to True GlGENTEXTURES (1, Texture [0]); // Creating Texture // In the sixth lesson we use linear filtering texture map. // This requires a very high processing capability of the machine, but they look very good. // This lesson, we will use the GL_NEAREST method to create the first texture to create. // In principle, this method is not really filtered. // It only takes a small handling ability and looks very poor. // The only benefit is that our project can run normally on a very fast and slow machine. / / You will notice that we use GL_nearest, // you can mix using GL_Nearest and GL_LINEAR. // Texture seems to be better, but we are more concerned with speed, so low quality maps. // min_filter is used in the original size of the map when image drawing. // MAG_FILTER is used in the original size of the map during image drawing. // create a filter map Nearest glBindTexture (GL_TEXTURE_2D, texture [0]); // generate texture glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // (new) glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // (new)
Glteximage2D (GL_Texture_2D, 0, 3, TextureImage [0] .sizex, TextureImage [0] .sizey, 0, GL_RGB, GL_UNSIGNED_BYTE, TEXTUREIMAGE [0] .DATA);
// The next texture is the same as the sixth lesson, linear filtering. The only difference is in this time in // texture [1]. Because this is the second texture. If you put on // texture [0], he will overwrite the GL_NEAREST texture created in front. GlbindTexture (GL_Texture_2D, Texture [1]); // Use typical texture generated from bitmap data // Generating texture GLTexImage2D (GL_Texture_2D, 0, 3, TextureImage [0] .sizex, TextureImage [0] .sizey, 0, GL_RGB , GL_UNSIGNED_BYTE, TextureImage [0] .data); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // linear filter glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // linear filter
// The following is a new method for creating textures. Mipmapping! // "Translator Note: I can't turn it out in Chinese in this word, but it doesn't matter. After reading this paragraph, you know the most important thing. / / You may notice that many details will be lost when the image becomes very small on the screen. // The pattern that has just been very nice is hard to see. When you tell OpenGL to create a MipMapped texture, // OpenGL will try to create high quality textures of different sizes. When you draw a MipMapped texture to the screen, // OpenGL will select the best texture it has created (more details) to draw, //, not just scaling the original image (this will cause details Lost). // I have said that there is a way to bypass OpenGL's restrictions on texture width and height - 64, 128, 256, and so on. // The method is Glubuild2DMIPMAPS. According to my discovery, you can create textures using any bitmap. // OpenGL will automatically zoom it into normal size. // Because it is the third texture, we save it to Texture [2]. This creation is created in this lesson. // Create MipMapped texture glBindTexture (GL_TEXTURE_2D, texture [2]); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); // (new) // following line generated mipmapped texture. // We use three colors (red, green, blue) to generate a 2D texture. //Textureimage[0].sizex is bitmap width, //textureimage[0].sizey is a bitmap height, // (==== I don't know why, this function doesn't have Height in Delphi, // But help But there is, I don't know what Delphi is, depressed ing ... // I wrote a glubuild2dmipmaps in front of yourself, // to load the glubuild2dmipmaps function in Glu32.dll =====) // GL_RGB It means that we use RGB colors sequentially. // GL_unsigned_byte means that the unit of texture data is byte. //TextureImage[0].data points to the bitmap used by our creation of textures.
gluBuild2DMipmaps (GL_TEXTURE_2D, 3, TextureImage [0] .sizeX, TextureImage [0] .sizey, GL_RGB, GL_UNSIGNED_BYTE, TextureImage [0] .data); // (new)} End; If assigned (TextureImage [0]) Then // Whether the texture exists if assigned (TextureImage [0] .DATA) THEN / / texture image exists with TextureImage [0] .data: = nil; // Release Texture Image Used Memory TEXTUREIMAGE [0]: = NIL; // Release the image structure Result: = status; // Returns statusend; // then load texture and initialize OpenGL settings. The first line of the Glinit function uses the above code to load texture. // After creating a texture, we call Glenable (GL_TEXTURE_2D) to enable 2D texture mapping. // The shadow mode is set to smoothing shadings. // Background color is set to black, we enable depth testing, then we enable optimization perspective calculations.
Procedure Glinit (); // Start all settings of OpenGL for OpenGL (Not LoadTexture) Then // Call texture load subroutines exit; // If it is not loaded, exit
Glenable (GL_TEXTURE_2D); // Enable texture map GLShademodel (GL_SMOOTH); // Enable shadow smooth GlclearColor (0.0, 0.0, 0.0, 0.0); // Black background GlcleardEpth (1.0); // Set depth cache Glenable (GL_Depth_test); // Enable depth test GLDEPTHFUNC (GL_SS); // The type of GLHINT (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Highly optimized perspective projection calculation
// Now set the light source. Below the next line, set the emission amount of the ambient light, // The light source Light1 begins to illuminate. // The beginning of this lesson We we store the emission of the ambient light in the Lightambient array. // Now we use this array (half-brightness ambient light). GLLightfv (GL_Light1, GL_AMBIENT, @Lightambient [0]); // Setting the ambient light // Next we set the amount of light of the diffuse light. It is stored in the LightDiffuse array (full brightness white light). GLLIGHTFV (GL_Light1, GL_DIFFUSE, @lightdiffuse [0]); // Sets the position of the diffuse light // then set the light source. // Location is stored in the lightposition array // (just in the center of the wooden box, X-0.0, Y-0.0, Z direction moved to the observer 2 units
Procedure gldraw (); // Start all of the Draw Begin Glclear (GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); // Clear the screen and depth cache GLLoadIndIndentity (); // Reset the current model observation matrix
// The next three lines of code is placed and rotated to the map cube. //Gltranslatef (0.0, 0.0 ,z) moves the cube along the Z axis. //Glrotatef (XROT, 1.0F, 0.0F, 0.0F) rotates the cube around the X-axis. //Glrotatef (YROT, 0.0F, 1.0F, 0.0F) Rotate the cube around Y axis. Gltranslatef (0.0, 0.0, z); // shift into / removes the screen Z unit glrotatef (xROT, 1.0, 0.0); // Rotate Glrotatef around the X-axis (YROT, 0.0, 1.0, 0.0); // Wound Y Axle rotation
// The next line is similar to us in the sixth lesson. // Different, this time we bind texture is texture [filter], // instead of Texture [0] in the last lesson. // At any time, we press the F key, and the value of the Filter will increase. // If this value is greater than 2, the variable filter will be reset to 0. When the program is initially, the value of the variable Filter will be set to 0. // We can choose any of three textures using the variable filter. GlbindTexture (GL_Texture_2D, Texture [Filter]); // Select the texture determined by Filter
Glbegin (GL_QUADS); // Starting drawing quadrilateral // Glnormal3f is a new thing for this lesson. Normal is the meaning of the normal, // The so-called normal refers to a straight line of the surface (polygon) and perpendicular to this surface (polygon). // You must specify a normal method when using the light source. The normal line tells OpenGL's orientation of this polygon and specifies the positive and back of the polygon. // If there is no specified normal, what monster may happen: don't illuminate the face, the back of the polygon is also illuminated ..... // All, the normal should point to the outside of the polygon. Watching front of the wooden box you will notice that the normal is in the same direction. // This means that the normal line is pointing to the observer - yourself. This is exactly what we hope. / / For the back of the wooden box, as we want, the normal is back to the observer. / / If the cube rotates 180 degrees along the X or Y axis, the front side of the front side is still toward the observer, the normal side of the back is still back to the observer. // In other words, no matter which surface, as long as it is pointing toward the plane of the observer, it points to the observer. // Since the light source is close to the observer, the surface will be illuminated when the normal is against the observer. // and the more the normal is, the brighter, even more. // If you put the observation point in the inside of the cube, you will be dark in the normal. // Because the normal is an outward finger. If there is no light source inside the cube, it is of course black.
// Front Glnormal3f (0.0, 0.0, 1.0); // Fair point to the observer GLTEXCOORD2F (0.0, 0.0); GlvertEX3F (-1.0, -1.0, 1.0); // Texture and quadrilateral upper left GLTEXCOORD2F (1.0, 0.0) GlvertEX3F (1.0, -1.0, 1.0); // Texture and quadrilateral upper right gltexcoord2f (1.0, 1.0); Glvertex3f (1.0, 1.0, 1.0); // Texture and quadrilateral upper right gltexcoord2f (0.0, 1.0); GlvertEx3f (-1.0, 1.0, 1.0); // Texture and quadrilateral left // back GLNORMAL3F (0.0, 0.0, -1.0); // Number back to the observer GltexcoRD2F (1.0, 0.0); GlvertEX3F (-1.0, - 1.0, -1.0); // Texture and quadrilateral upper right gltexcoord2f (1.0, 1.0); Glvertex3f (-1.0, 1.0, -1.0); // Texture and quadrilateral upper right gltexcoord2f (0.0, 1.0); GlvertEX3F (1.0, 1.0, -1.0); // Texture and quadrilateral left GLTEXCOORD2F (0.0, 0.0); GlvertEX3F (1.0, -1.0, -1.0); // Texture and quadrilateral left // top GLNORMAL3F (0.0, 1.0, 0.0) // Failed to GLTEXCOORD2F (0.0, 1.0); GlvertEX3F (-1.0, 1.0, -1.0); // Texture and quadrilateral left gltexcoord2f (0.0, 0.0); Glvertex3f (-1.0, 1.0, 1.0); // Texture and quadrilateral top left gltexcoord2f (1.0, 0.0); GlvertEX3F (1.0, 1.0, 1. 0); // Texture and quadrilateral upper right gltexcoord2f (1.0, 1.0); GlvertEX3F (1.0, 1.0, -1.0); // Texture and quadrilateral right upper // bottom GLNORMAL3F (0.0, -1.0, 0.0); // The normal line faces GLTEXCOORD2F (1.0, 1.0); Glvertex3f (-1.0, -1.0, -1.0); // Texture and quadrilateral upper right gltexcoord2f (0.0, 1.0); GlvertEX3F (1.0, -1.0, -1.0); // Texture and quadrilateral top left gltexcoord2f (0.0, 0.0); GlvertEX3F (1.0, -1.0, 1.0); // Texture and quadrilateral left under the left of Gltexco 3F (1.0, 0.0); GLVERTEX3F (-1.0, -1.0, 1.0); // Texture And the right lower / / right side of the quadrilateral GLNORMAL3F (1.0, 0.0, 0.0); // Fair towards the right gltexcoord2f (1.0, 0.0); GlvertEX3F (1.0, -1.0, -1.0); // Texture and quadrilateral Right GLTEXCOORD2F (1.0, 1.0); Glvertex3f (1.0, 1.0, -1.0); // Texture and quadrilateral upper right gltexcoord2f (0.0, 1.0); Glvertex3f (1.0, 1.0, 1.0);
// Texture and quadrilateral top left gltexcoord2f (0.0, 0.0); Glvertex3f (1.0, -1.0, 1.0); // texture and quadrilateral left // left GLNORMAL3F (-1.0, 0.0, 0.0); // French toward left GLTEXCOORD2F (0.0, 0.0); Glvertex3f (-1.0, -1.0, -1.0); // Texture and quadrilateral left under the left of GltexcoRD2F (1.0, 0.0); GlvertEX3F (-1.0, -1.0, 1.0); // Texture and quadrilateral The upper right gltexcoord2f (1.0, 1.0); GlvertEX3F (-1.0, 1.0, 1.0); // Texture and quadrilateral upper right gltexcoord2f (0.0, 1.0); GlvertEX3F (-1.0, 1.0, -1.0); // Texture and quadrilateral Left (); xrot: = xrot xspeed; // xrot Add XSpeed unit YROT: = YROT YSPEED; // YROT Add YSPEED unit END;
// Now transfer to the WinMain () master function. / / We will increase the switch light, rotate the wooden box, and switch the filter method, and the control code that moves the wooden box to the shift. // At the end of the Winmain () function, you will see the SwapBuffers (HDC) line code. // Then add the following code after this line. // The code will check if the L button is pressed. // If the L button is pressed, the value of LP is not false, meaning the L button has not been released, and what will not happen at this time. SwapBuffers (H_DC); // Switching Cache (dual cache)
IF (Keys [ORD ('L')] and not lp) Then Begin // If the value of LP is false, / / means that the L button has not been pressed, or it has been released, then LP will be set to True. / / At the same time, the reason for both conditions is to prevent the L key from being pressed, and the code is repeated and causes the form to keep flashing. // LP is set to true, the computer knows that the L key is pressed, // We can switch the on / off of the light source accordingly: Boolean variable light controls the switch of the source. LP: = true; // LP is set to true light: = not Light; // Switch the light source TRUE / FALSE if not Light Then // If there is no light source GLDISABLE (GL_Lighting) // Disable Light source else // Otherwis Glenable (GL_Lighting) ; // Enable the source end; if not keys [ORD ('L')] THEN / / L key loose? Lp: = false; // If, set the LP to false // / then "f" Key as a similar examination. // If there is a "F" key and the "F" button is not in the state or it never presses it, // Set the variable FP to True. This means that this button is pressed. / / Then add a Filter variable to one. If the Filter variable is greater than 2 // (because the arrays of our usage are texture [3], the texture of greater than 2 does not exist), // We reset the Filter variable of 0. IF (Keys [ORD ('f')] and not fp) Then // f button presses it? Begin fp: = true; // FP is set to true inc (filter); // filter value plus one IF Filter> 2 THEN / / greater than 2? Filter: = 0; // If it is reset to 0 end; if not keys [ORD ('f')] The // f button let go? FP: = FALSE ; // If FP is set to false
// These four lines check whether the PageUp key is pressed. If it is, the value of the z variable is reduced. This way to call the GLTranslateF (0.0F, 0.0F, Z) contained in the Drawglscene function will make the wooden box from the observer. IF keys [vk_prior] THEN / PAGEUP Press? Z: = z - 0.02; // If you press it, move the wooden box to the screen inside. / / The four lines check if the PageDown button is pressed, if it is, the value of the z variable is added. This way, the GLTRANSLATEF (0.0F, 0.0F, Z) call included in the Drawglscene function will cause the wooden box to move close to the observer. IF keys [vk_next] THEN / / PAGEDOWN Press? Z: = z 0.02; // If you press it, move the wooden box toward the observer. / / Now check the arrow keys. Press the left and right arrow keys XSPEEDs to decrease or increase. // Press the up and down direction button YSPEED to reduce or increase accordingly. / / Remember that if the value of xspeed, YSPEED is increased in the future tutorial, the cube is faster. // If you have been pressing a direction button, the faster the cube turn in that direction. IF keys [vk_up] the // UP direction button presses? Xspeed: = xspeed - 0.01; // If it is, reduce the xspeed if keys [vk_down] the // down direction button is pressed? Xspeed: = xspeed 0.01; // If yes, add the xSpeed if keys [vk_right] THEN / / RIGHT direction button to press? YSPEED: = YSPEED 0.01; // If yes, add yspeed if keys [vk_left] the // LEFT direction button What? YSPEED: = YSPEED - 0.01; // If yes, reduce YSPEED
IF (Keys [vk_escape]) then // If you press the ESC key Finished: = true
Run a look at the effect