Jeff Molofee (nehe) OpenGL Tutorial Ninth Tip Translated By Cker
Welcome to the ninth lesson. Up to now, you should understand OpenGL very well. "CKER: If not, it must be the sin of my translation ...". You have learned every detail to set an OpenGL window. Learn to map on the rotating object and put the light and mix colored (transparent). This lesson should be an intermediate tutorial in the first class. You will learn the following: Move bitmap in 3D scenes and remove black pixels on the bitmap (mixed with color). Then it is black and white texture, and finally you will learn to create rich colors, and mix the textures of different colors to each other to get a simple animation effect. We have modified on the code of the first lesson. First add a few variables at the beginning of the program source code. I have rewritten the whole code for the clear start. #include
#include
#include
#include
#include
HDC HDC = NULL; // Private GDI Device Description Table
HGLRC HRC = NULL; // Permanent Coloring Description Table
HWND HWND = NULL; / / Save our window handle
Hinstance hinstance; // Save the program's instance
Bool Keys [256]; // A number of groups for keyboard routines
Bool Active = true; // Events flag of the window, default TRUE
Bool fullscreen = true; // full screen sign default setting into full screen mode
The following lines are new. Twinkle and TP are Boolean variables that they can only be set to TRUE or FALSE. Twinkle is used to track if the flicker effect is enabled. TP is used to check that the 't' button is not pressed or released. (Tp = true, schedule TP = false).
BOOL TWINKLE; / / Flashing stars
Bool tp; // 't' presses?
Num Tracking Stars Drawn on the Screen. This number is defined as a constant. This means that it cannot be modified in the subsequent code. The reason for this is because you can't redefine an array. Therefore, if we define an array of 50 stars, then add NUM to 51, it will go wrong "CKER: Array Crossing". But you can still modify this number at this line at this line. But please don't change the value of NUM later, unless you want to see the disaster.
Const Num = 50; // Drawn Stars
Now let's create a structure. Structure This word sounds a little terrible, but it is actually not the case. A structure uses a set of simple types of data (and variables, etc.) to express larger similarity-based data combinations. We know that we are keeping track of stars. You can see that the seventh line below is Stars; and each star has three integer color values. Third line INT R, G, B set three integers. A red (R), a green (G), and a blue (B). In addition, each star is different from the center of the screen, and can be One angle in any 360 degree of the origin at the center of the screen. If you look at the fourth line below, we will find that we use a floating point called DIST to keep track of distance. The fifth line uses a floating point called Angle to the stars angle value. So we used a set of data to describe the color, distance, and angle of the stars on the screen. Unfortunately, we don't just track a stars. But there is no need to create 50 red values, 50 green values, 50 blue values, 50 distance values, and 50 angle values, just create an array star. Each element of the Star array is a Stars type, which stores all the data describing the stars. The Star array is created in the eighth line below. The eighth line is like this: Stars Star [Num]. The array type is a Stars structure. The array can store information about all STARS structures. The array name is Star. The array size is [NUM]. The elements of the Stars structure are stored in the array. Tracking structural elements can be easier than tracking variables separated from each other. But it is also stupid, because we can't change the constant NUM to increase the number of stars. Typedef struct // creates a structure for the stars
{
INT R, G, B; / / Star's colors
GLFLOAT DIST; / / Star Distance
GLFLOAT ANGLE; / / Current angle at the current stars
}
Stars; // Structure is named Stars
Stars star [Num]; // Generate a 'Star' array containing the 'Num' element using the 'Stars' structure
Width = 28> width = "100%">
Valign = Top width = "100%">
Next we set a few tracking variables: the distance of the Stars off the observer (zoom), the angle of the stars we have seen, and the variable spin spinning the flashing star rotated around the Z-axis. Loop variables are used to draw 50 stars. Texture [1] used to store a black and white texture. If you need more textures, you should increase the size of the Texture array to you determine the number of textures.
GLFLOAT ZOOM = -15.0F; // Star from the distance from the observer
GLFLOAT TILT = 90.0f; // Star's inclination
GLFLOAT spin; // Scintter stars rotate
Gluint loop; // global L loop variable
Gluint texture [1]; // Store a texture
LResult Callback WndProc (HWND, UINT, WPARAM, LPARAM); // WndProc declaration
Width = 28> width = "100%"> width = 28>
Valign = Top width = "100%">
The above code is the code we use to load the texture. I don't intend to explain this code in detail. This is the same as our code used in sixth, seventh, and eight classes. This loaded bitmap is called Star.BMP. Here we use GLGENTEXTURES (1, & Texture [0]) to generate a texture. Texture uses a linear filtering method.
AUX_RGBIMAGEREC * LOADBMP (Char * filename) // Load bitmap file {
File * file = null; // file handle
If (! filename) // confirm that the file name has been given
{
Return null; // No return NULL
}
File = fopen (filename, "r"); / / Check if the file exists
IF (file) // file existence?
{
fclose (file); // Close the file handle
Return AuxDibImageLoad (filename); / / Load bitmap and return pointer
}
Return null; // If load failure returns NULL
}
Width = 28> width = "100%"> width = 28>
Valign = Top width = "100%">
The following code (call the code above) load bitmap and converted to texture. Variables are used to track whether textures are loaded and created.
INT loadGLTextures () // Load bitmap and converted into texture
{
Int status = false; // status status indicator
AUX_RGBIMAGEREC * textureImage [1]; / / allocate storage space for texture
MEMSET (TextureImage, 0, SizeOf (Void *) * 1); // Set the pointer to NULL
// Load bitmap, check the error, exit if the bitmap file is not found
IF (TextureImage [0] = loadingbmp ("Data / Star.Bmp")))
{
Status = true; // Set Status True
Glgentextures (1, & texture [0]); // Create a texture
// Create a linear filter texture
Glbindtexture (GL_Texture_2D, Texture [0]);
Gltexparameteri (GL_Texture_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GLTEXPARAMETERI (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
GLTexImage2D (GL_Texture_2D, 0, 3, TextureImage [0] -> Sizex, TextureImage [0] -> Sizey,
0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage [0] -> DATA);
}
IF (TextureImage [0]) // If the texture exists
{
IF (TextureImage [0] -> DATA) // If the texture image exists
{
Free (TextureImage [0] -> DATA); / / Release the memory of the texture image
}
Free (TextureImage [0]); // Release the image structure
}
Return status; // Return to Status value
}
Width = 28> width = "100%"> width = 28>
Valign = Top width = "100%">
Now set the OpenGL rendering method. It doesn't plan to use a depth test. If you use the code of the first lesson, please confirm if GlDepthfunc (GL_LEQUAL); and GLENABLE (GL_Depth_test); Otherwise, what you see will be a mess. Here we use texture mappings, so please confirm that you have added the code in these first lessons. You will notice that we enable texture mapping by mixing. INT INITGL (GLVOID) / / Start all settings for OpenGL here
{
IF (! loadGltextures ()) // Call texture load subroutine
{
Return false; // If you fail to load, return false
}
Glenable (GL_TEXTURE_2D); // Enable texture mapping
Glshademodel (GL_SMOOTH); // Enable shadow smooth
GlclearColor (0.0F, 0.0F, 0.0F, 0.5F); // black background
GLCLEARDEPTH (1.0F); // Set depth cache
GLHINT (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); / / True fine perspective correction
GLBLENDFUNC (GL_SRC_ALPHA, GL_ONE); // Sets the mixing function to achieve a translucent effect
Glenable (GL_BLEND); // Enable mixing color
Width = 28> width = "100%"> width = 28>
Valign = Top width = "100%">
The following is a new code. Set the start angle, distance, and color of each star. You will notice that the properties of the modified structure are easier. All 50 stars will be set cycled. To change the perspective of Star [1], we have to do just star [1] .angle = {a value}; it is as simple!
For (loop = 0; loop { Star [loop] .angle = 0.0f; // All stars start from zero angle Width = 28> width = "100%"> width = 28> Valign = Top width = "100%"> The distance from the center of LOOP is the center of the LOOP to the total number of the stars and then take 5.0f. Basically, the latter stars are more far more than the previous stars. This is when the LOOP is 50 (last stars), the LOOP is exactly 1.0F in addition to NUM. The reason why it is necessary to multiply by 5.0f because 1.0F * 5.0F is 5.0F. "Cker: nonsense, nonsense! How do this foreigner with Kong B! :) "5.0f is already close to the edge of the screen. I don't want the stars to fly out of the screen, 5.0f is the best choice. Of course, if you can use the scene settings inside the screen, you may use a value greater than 5.0F, but the stars look smaller (all the perspective). You will also notice that the colors of each star are a random number between 0 to 255. Maybe you will be strange why the color here is not between 0.0F ~ 1.0F of OpenGL. Here we use the color setting function is GLCOLOR4UB, not the previous GLColor4f. UB means that the parameters are unsigned byte. A Byte value range is 0 ~ 255. This is easier to use byte value to take the random integer to take a floating point. Star [loop] .dist = (float (loop) / NUM) * 5.0F; // Calculate the distance from the center Star [loop] .r = rand ()% 256; // Setting a random red component star [loop] for star [loop] .g = rand ()% 256; // Setting random red components for star [loop] Star [loop] .b = rand ()% 256; // Setting a random red component for star [loop] } Return True; // Initialize everything OK } Width = 28> width = "100%"> width = 28> Valign = Top width = "100%"> Resize's code is also the same, now we transfer to the drawing code. If you use the code of the first lesson, delete the old DrawGlscene code, just copy the following code to the past. In fact, the code of the first lesson is only two lines, so there is not much thing to delete. INT Drawglscene (GLVOID) // This process includes all drawing code { GLCLEAR (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); / / Clear Screen and Depth Cache GlbindTexture (GL_Texture_2D, Texture [0]); // Select Texture For (loop = 0; loop { GLLOADIDENTITY (); // Draw a reset model observation matrix before each stars GltranslateF (0.0F, 0.0F, zoom); // Inuting the screen (using 'zoom') GLROTATEF (TILT, 1.0F, 0.0F, 0.0F); // Tilt view (using 'Tilt') Width = 28> width = "100%"> width = 28> Valign = Top width = "100%"> Now let's move the stars. The stars are at the center of the screen. The first thing we have to do is to rotate the scene along the Y axis. If we rotate 90 degrees, the X axis is no longer from left to right, and he will pass the screen outward. In order to make everyone more clear, take an example. Imagine you standing in the middle of the house. Then I envisage the wall on the left side of your left, write -z, the front wall is x, the right wall is x, and the wall behind you is z. Join the entire house to turn 90 degrees, but you are not moving, then the front wall will be -x and no longer -z. All other walls are also moving. -z appears on the right, z appears on the left, x appears behind you. The nerve is disorderly? By rotating the scene, we changed the direction of the X and Z planes. The second line of code moves a positive value along the X axis. Typically, the positive value on the X-axis is moved toward the right side of the screen (that is, the normal X-axis of the X-axis), but here we rotate the coordinate system around the Y-axis, the positive direction of the X-axis can be any direction. If we turn 180 degrees, the image is reversed on the left and right side of the screen. Therefore, when we move forward in the X axis, it may be left, right, forward or backward. GLROTATEF (Star [loop] .angle, 0.0f, 1.0f, 0.0f); // Rotate to the point of origin of the current stars Gltranslatef (Star [loop] .dist, 0.0f, 0.0f); // Positive movement along the X-axis Width = 28> width = "100%"> width = 28> Valign = Top width = "100%"> Then the code takes a little tip. The stars are actually a flat texture. Now you have drawn a flat quadrilateral shape on the center of the screen, then post the texture, this looks very good. Everything is as you think. But when you turn around 90 degrees along the Y axis, the texture is only left on the right side and the two sides of the left side toward you. It seems to be a thin line. This is not what we want. We hope that the stars will always face us, regardless of how the screen is rotated or tilted. We have achieved this by offset any rotation made to the stars before drawing the stars. You can use an inverse ordered to offset rotation. When we tilted the screen, we actually rotate the stars in the current angle. By reverse order, we "reverse rotate" stars in the current angle. That is to rotate the stars in a negative value of the current angle. That is to say, if we rotate the stars 10 degrees, we rotate the -10 degree to make the stars back to the screen on that axis. The first line below offset the rotation along the Y axis. We also need to cancel the screen tilt along the X axis. To do this, we only need to turn the screen again - TILT inclination. After the rotation of the X and Y axes, the stars are completely facing us. GLROTATEF (-star [loop] .angle, 0.0f, 1.0f, 0.0f); // Cancel the current star angle GLROTATEF (-TILT, 1.0F, 0.0F, 0.0F); // Cancel the screen tilt Width = 28> width = "100%"> width = 28> Valign = Top width = "100%"> If Twinkle is True, we draw a spark on the screen: Turn the total number of stars (NUM) to minus 1, to extract the different colors of each star (this is because The loop ranges from 0 to NUM-1). For example, the result is 10, we use the color of the No. 10 star. This is always different in the color of the neighboring star. This is not a good way, but it is very effective. The last value is the Alpha channel component. The smaller this value, the darken this star. Since Twinkle is enabled, each stars will finally draw twice. The program is running slowly, it depends on how your machine performance is. But the two-way color of the stars are integrated with each other, and it will produce a great effect. At the same time, because the first round of the stars do not rotate, the stars after the Twinkle after the stars have appeared to have an animation effect. (If you don't know what you know here, you can see the running effect of the program.) It is worth noting that it is easy to give texture color. Although the texture itself is black and white, the texture will turn into any of the selected colors before drawing it. In addition, it is also worth noting that the color value we used here is Byte type, not the usual floating point. Even Alpha channel components are also true. IF (twinkle) // Enable flashing effect { // Specify a color using the BYTE type value Glcolor4ub (Star [(Num-Loop) -1] .r, Star [(Num-Loop) -1] .g, Star [(Num-Loop) -1] .b, 255); Glbegin (GL_QUADS); // Start drawing the four-sided shape of the texture GLTEXCOORD2F (0.0F, 0.0F); GlvertEX3F (-1.0F, -1.0F, 0.0F); GLTEXCOORD2F (1.0F, 0.0F); GLVERTEX3F (1.0F, -1.0F, 0.0F); GLTEXCOORD2F (1.0F, 1.0F); GLVERTEX3F (1.0F, 1.0F, 0.0F); GLTEXCOORD2F (0.0F, 1.0F); GLVERTEX3F (-1.0F, 1.0F, 0.0F); Glend (); // quadrilateral drawback } Width = 28> width = "100%"> width = 28> Width = 28> nowrap width = 28> NOWRAP WIDTH = 28> Valign = Top Width = "100%"> nowrap width = 28> Now draw a second round of stars. The only and the previous code is that this round of the stars will definitely be drawn, and this star is rotated around the Z axis. GLROTATEF (Spin, 0.0F, 0.0F, 1.0F); // Rotating the stars around Z // Specify a color using the BYTE type value Glcolor4ub (Star [loop] .r, star [loop] .g, star [loop] .b, 255); Glbegin (GL_QUADS); // Start drawing the four-sided shape of the texture GLTEXCOORD2F (0.0F, 0.0F); GlvertEX3F (-1.0F, -1.0F, 0.0F); GLTEXCOORD2F (1.0F, 0.0F); GLVERTEX3F (1.0F, -1.0F, 0.0F); GLTEXCOORD2F (1.0F, 1.0F); GLVERTEX3F (1.0F, 1.0F, 0.0F); GLTEXCOORD2F (0.0F, 1.0F); GLVERTEX3F (-1.0F, 1.0F, 0.0F); Glend (); // quadrilateral drawback Width = 28> width = "100%"> width = 28> Width = 28> NOWRAP WIDTH = 28> NOWRAP WIDTH = 28> Valign = Top Width = "100%"> nowrap width = 28> The following code represents the movement of the stars. We increase the value of Spin to rotate all stars (public turn). Then, the rotation angle of each star is then increased LOOP / NUM. This makes a faster stars that are further away from the center. Finally reduce the distance of each star away from the screen. This looks like this, the stars seem to have been in the center of the screen. Spin = 0.01F; // Star's public Star [loop] .angle = float (loop) / NUM; // change the rotation angle of the stars Star [loop] .dist- = 0.01f; // change the distance from the center Width = 28> width = "100%"> width = 28> Width = 28> NOWRAP WIDTH = 28> NOWRAP WIDTH = 28> Valign = Top Width = "100%"> nowrap width = 28> Then check whether the stars have encountered the screen center. When the stars encounter the screen center, we assign a new color, then move 5 units, this stars will embark on the journey of its return to the screen. IF (Star [loop] .dist <0.0f) // Star arrives in the center? { Star [loop] .dist = 5.0f; // Move 5 units Star [loop] .r = rand ()% 256; // assign a new red component Star [loop] .g = rand ()% 256; // assign a new green component Star [loop] .b = rand ()% 256; // assign a new blue component } } Return True; // all normal } Width = 28> width = "100%"> width = 28> Width = 28> Now we add the code that monitors the keyboard. Move down to WinMain (). Find a row of SwapBuffers (HDC). We will add keyboard monitoring code after this line. The code will check if the T key is pressed. If the T key is pressed, it is released, the code within the IF block will be executed. If twinkle is false, he will become true. vice versa. As long as the T key is pressed, the TP changes to true. This will prevent the code within the block from being executed if you have been pressing the T key. SwapBuffers (HDC); // Switch buffer (double buffer) IF (Keys ['T'] &&! TP) // Whether the T button is pressed and the TP value is false { TP = true; // is set to TRUE Twinkle =! twinkle; // Turn the value of Twinkle } Width = 28> width = "100%"> The following code checks if the T key is released. If so, make TP = false. Unless the value of TP is false, what will not happen when you press T. So this line code is very important. IF (! keys ['t']) // t button is released? { TP = false; // If it is, TP is false } Width = 28> width = "100%"> The remaining code checks, the lower arrow button, the upward page button, or the down the page button is pressed. IF (Keys [VK_UP]) / / The upper point is pressed? { TILT- = 0.5F; / / screen topping up } IF (Keys [vk_down]) / / lower direction button is pressed? { TILT = 0.5F; / / screen down } IF (Keys [vk_prior]) / / Page button up button? { ZOOM- = 0.2F; // } IF (Keys [vk_next]) / / The page button is pressed down? { ZOOM = 0.2f; // Zoom } Width = 28> width = "100%"> As before, confirm that the title of the window is correct. IF (Keys [vk_f1]) / / F1 button is pressed? { Keys [vk_f1] = false; // If yes, the value in the corresponding KEY array is false KillglWindow (); // destroy the current window Fullscreen =! fullscreen; / / Switch full screen / window mode / / Rebuild the OpenGL window IF ("" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" { RETURN 0; // If the window is not created, the program exits } } } } Width = 28> width = "100%">