Http://developer.178.com/201103/94955548786.html
Today is about three-dimensional transformation of the content, the course is more boring. Mainly because many functions are not good at describing their effects when used alone, I have to give a more comprehensive example at the end. I hope you can see the bottom in one breath. It may not be enough to look at once, but if you feel confused, look at it two more times. Questions can be raised in the following thread.
I've also used a number of graphs that I hope can help understand.
Do you think the scope of our drawing is too narrow when we draw the geometry in front of us? Coordinates can only be from 1 to 1, and can only be x-axis to the right, y-axis upward, and z-axis vertical screen. These restrictions have brought a lot of inconvenience to our drawings.
We live in a three-dimensional world-if we want to observe an object, we can:
1, from a different position to observe it. (View transform)
2, move or rotate it, of course, if it is only the object inside the computer, we can also enlarge or reduce it. (Model Transformation)
3, if the object is drawn down, we can choose: whether a "near-large far small" perspective effect is required. In addition, we may only want to see part of the object, not all (clipping). (Projection transformation)
4. We may want to draw the entire picture, but it only occupies part of the paper, not all of it. (Viewport transform)
All of this can be achieved in OpenGL.
OpenGL transforms are actually implemented by matrix multiplication. Whether moving, rotating, or scaling, it is achieved by multiplying a new matrix on the basis of the current matrix. Knowledge of the matrix, not detailed here, interested friends can look at linear algebra (college students are most likely to learn).
OpenGL can operate the matrix directly at the lowest level, but as a beginner, this does not make much sense. There is no introduction here.
1. Model Transformation and view transformation
From the point of view of "relative movement", it is equivalent to change the position and direction of the observer and change the position and direction of the object itself. In OpenGL, these two functions are implemented even using the same functions.
Since both the model and the view transform are implemented by matrix operations, the matrix of the current operation should be set as the Model view matrix before the transformation. The method to set is to call the Glmatrixmode function as a gl_modelview parameter, like this:
Glmatrixmode (Gl_modelview);
In general, we need to set the current matrix to the unit matrix before making the transformation. This also requires one line of code:
Glloadidentity ();
Then, you can make model transformations and view transformations. The model and view transformations are mainly related to three functions:
gltranslate*, multiplies the current matrix and a matrix that represents the moving object. The three parameters represent the displacement values at three coordinates, respectively.
glrotate*, multiplies the current matrix and a matrix that represents a rotating object. The object will rotate counterclockwise around (0,0,0) to a straight line (x, Y, z), and the parameter angle represents the angle of rotation.
glscale*, multiplies the current matrix and a matrix that represents the scaling object. x, y, and Z indicate the scaling in that direction, respectively.
Note that I mean "multiply with XX", not just say "This function is rotation" or "This function is moving", for a reason, it will be said right away.
Suppose the current matrix is a unit matrix, then multiply by a matrix R representing rotation, multiplied by a matrix t representing the move, and the resulting matrix is multiplied by the coordinate matrix V of each vertex. So, the vertex coordinates that are transformed are ((RT) v). Because of the binding rate of matrix multiplication ((RT) v) = (R (Tv)), in other words, it is actually moved first and then rotated. That is, the order of the actual transformations is reversed from the order in which the code is written. Since the results of "move after first" and "move after first" are likely to be different, you need to pay special attention to this when you are beginners.
OpenGL is designed to be more efficient. But when drawing complex three-dimensional graphics, it is painful to think about how to turn the transformation upside down every time. Here's another way of thinking that makes your code look more natural (the code you write is exactly the same, but it's different when you think about the problem).
Let us imagine that the coordinates are not constant. When rotated, the coordinate system rotates with the object. When moving, the coordinate system moves with the object. This way, there is no need to consider the sequential reversal of the code.
All of these are introduced to change the position and direction of the object. If you want to change the location of the observer, you can use this function in addition to using the glrotate* and gltranslate* functions: Glulookat. Its parameters are more, the first three parameters represent the position of the observer, the middle three parameters represent the position of the observation target, and the last three parameters represent the line from (0,0,0) to (x, Y, z), which represents the "up" direction that the Observer thinks.
2. Projection transformation
A projection transformation is defined as a visual space in which objects outside the visual space are not drawn to the screen. (Note that from now on, the coordinates can no longer be 1.0 to 1.0!) )
OpenGL supports two types of projection transformations, perspective projection and orthographic projection. Projections are also implemented using matrices. If you need to manipulate the projection matrix, you need to call the Glmatrixmode function with Gl_projection as the parameter.
Glmatrixmode (gl_projection);
In general, we need to set the current matrix to the unit matrix before making the transformation.
Glloadidentity ();
The perspective projection produces results similar to a photo, with a near-large effect, such as a photo of a railroad track in front of the locomotive, and the two rails seem to intersect in the distance.
Use the Glfrustum function to set the current visual space as a perspective projection space. The meaning of its parameters is as follows:
Disclaimer: The picture is from www.opengl.org, which is the drawing of the book "OpenGL Programming Guide", because the old version of the book (the first edition, 1994) has been circulated on the Internet, I hope I have not touched the copyright issue.
You can also use the more commonly used gluperspective function. The meaning of its parameters is as follows:
Disclaimer: The picture is from www.opengl.org, which is the drawing of the book "OpenGL Programming Guide", because the old version of the book (the first edition, 1994) has been circulated on the Internet, I hope I have not touched the copyright issue.
The positive projection is equivalent to the result observed in an infinite distance, it is only an ideal state. For a computer, however, it is possible to use a positive projection to get a better run speed.
Use the Glortho function to set the current visual space as a positive projection space. The meaning of its parameters is as follows:
Disclaimer: The picture is from www.opengl.org, which is the drawing of the book "OpenGL Programming Guide", because the old version of the book (the first edition, 1994) has been circulated on the Internet, I hope I have not touched the copyright issue.
If the drawing space itself is two-dimensional, you can use gluortho2d. His use is similar to Glorgho.
3. Viewport transform
When everything is ready, just draw the pixel to the screen. The last question remains: which area of the window should the pixels be drawn to? Normally, the default is to fill the entire window completely, but we can just fill in half. (That is, the entire image is filled in half of the window)
Disclaimer: The picture is from www.opengl.org, which is the drawing of the book "OpenGL Programming Guide", because the old version of the book (the first edition, 1994) has been circulated on the Internet, I hope I have not touched the copyright issue.
Use Glviewport to define viewports. The first two parameters define the left bottom of the viewport (0,0 represents the leftmost bottom), and the last two parameters are width and height respectively.
4. Operation Matrix Stack
Somewhere in the beginning tutorial, let's start with a brief introduction to the stack. You can think of stacks as a stack of plates. At the beginning, a plate is not available, you can put it on one or the other, and you can take it off one at a time. Each time it was taken, it was the last plate to be put up. Typically, when the computer implements the stack, the capacity of the stack is limited, and if there are too many plates, an error occurs. Of course, if there is no plate, then asked to fetch a plate, it will be wrong.
When we are doing a matrix operation, it is possible to save a matrix before recovering it over a period of time. When we need to save, call the Glpushmatrix function, which is equivalent to putting a matrix (equivalent to a plate) on the stack. When you need to restore the last save, call the Glpopmatrix function, which is equivalent to removing the matrix from the stack. OpenGL specifies that the stack capacity can hold at least 32 matrices, and in some OpenGL implementations, the stack capacity actually exceeds 32. So don't worry too much about the capacity of the matrix.
Usually, it is more convenient and quicker to use this kind of recovery after saving than to change and reverse the transformation first.
Note: Both the Model View matrix and the projection matrix have a corresponding stack. Use Glmatrixmode to specify whether the current operation is a model view matrix or a projection matrix.
5. Comprehensive examples
Well, the beginning of the view transformation is almost done. But we can't just end it like this. Because the content of this course is too dull, if the separate example, may be ineffective. I have to say a comprehensive example, to give you a reference. As for the actual mastery, but also rely on the people themselves to spend Kung fu. Gossip less, now get to the point.
We're going to make a three-dimensional scene that includes the sun, the Earth, and the moon. Suppose that there are 12 months in a year, 30 days a month. Every year, the Earth goes round the sun. Every month the moon revolves around the Earth. That is, there are 360 days in a year. The date number (0~359) is now given, which requires plotting the relative position of the sun, Earth, and Moon. (This is designed for ease of programming.) If you need to make a more realistic case, it's just a matter of numerical processing, not with OpenGL.
First, let us assume that the three celestial bodies are spherical, and that their trajectories are in the same horizontal plane, establishing the following coordinate system: The center of the sun is the origin, the plane of the celestial trajectory represents the plane of the x-axis and the y-axis, and the first day of the Year, the Earth on the x-axis square upward, the moon in
The next step is to establish a visual space. Note: The sun's radius is much shorter than the distance from the sun to the earth. If we use astronomical observations directly, the size of the sun will be ignored when the entire window represents the size of the Earth's orbit. Therefore, we can only multiply the radius of several celestial bodies to fit the needs of our observation. (Baidu a bit, get the sun, the Earth, the moon's approximate radius is: 696000km, 6378km,1738km. The distance between the Earth and the sun is about 150 million km=150000000km, and the distance between the moon and the Earth is about 380000km. )
Let's imagine some data that would "modify" the radius of three celestial bodies to: 69600000 (100 times times magnification), 15945000 (2,500 times times magnification), 4345000 (2,500 times magnification). The distance from the Earth to the moon is "modified" to 38000000 (magnified 100 times times). The distance between the Earth and the sun remains the same.
In order for the Earth and the moon to be close to us, we still do not need to change the observation point and observe the direction to observe them, we put the observation point in this position: (0,-200000000, 0)-because the Earth orbit radius of 150000000, we will make a whole, Take-200000000 is available. The observation target is set to the origin (i.e. the center of the Sun), and the z axis is selected as the "Up" side. Of course, we can also move the observation point to the "upper" side of some, get (0,-200000000, 200000000), so you can get a 45-degree angle of the top effect.
To get a perspective, we use Gluperspective to set the visual space. It is assumed that the angle of view is 60 degrees (it can be modified if it is found to be inappropriate when debugging.) The number I chose at the end was 75. ), the aspect ratio is 1.0. The nearest visible distance is 1.0, and the furthest visible distance is 200000000*2=400000000. namely: Gluperspective (60, 1, 1, 400000000);
Now let's take a look at how to draw these three celestial bodies.
For the sake of simplicity, we think of the three celestial bodies as a regular sphere. In the glut utility we use, there is a ready-made function for drawing a sphere: Glutsolidsphere, which draws a sphere at the "origin". Since coordinates can be arbitrarily transformed by gltranslate* and glrotate* two functions, we can draw the sphere at any position. The function has three parameters: the first parameter represents the radius of the sphere, the latter two represent the number of "faces", the simple point is the precision of the sphere, the larger the value the more accurate, of course the price is slower. Here we simply set the after two parameters to 20.
The sun is at the origin of the coordinates, so you don't have to go through any transformations and draw directly.
The earth is a little more complicated and needs to transform coordinates. Since the number of days already passed this year is known as Day, the Earth turns around at an angle of day/a year * 360 degrees. It has been assumed that each year is 360 days, so the earth turns around at exactly the right angle. So the following code can be used to solve:
Glrotatef (day, 0, 0,-1);
/* Note that the Earth's revolution is "from west to East", so it rotates counterclockwise in the negative direction of the Z axis * *
Gltranslatef (Earth orbit radius, 0, 0);
Glutsolidsphere (Earth radius, 20, 20);
The moon is the most complex. Because it not only revolves around the Earth, but also moves around the sun as the earth goes. But if we choose the earth as a reference, then the movement of the Moon is a simple circular motion. If we were to draw the earth and then draw the moon, we would only need to make the same transformations as the Earth:
Glrotatef (angle of rotation of the moon, 0, 0,-1);
Gltranslatef (moon orbital radius, 0, 0);
Glutsolidsphere (moon radius, 20, 20);
But this "moon rotation angle", and can not be simply understood as day/one months of the days 30*360 degrees. Because we are drawing the earth, this coordinate is already rotated. The current rotation is rotated on a previous basis, so this "difference" is also required. We can write: Day/30*360-day, minus the original angle that has been turned. This is only a simple process, of course, you can save the matrix with Glpushmatrix before drawing the earth, after drawing the earth with Glpopmatrix recovery matrix. Design a moon position formula unrelated to the Earth's position to draw the moon. The latter method is usually better than the previous one, because the arithmetic of floating-point is imprecise, that is to say, we calculate the position of the Earth itself is imprecise. Taking this imprecise number to calculate the position of the moon can lead to the accumulation of "imprecise" ingredients, and excessive "imprecision" can cause errors. Our little program doesn't think about it, but it doesn't mean it doesn't matter.
Another detail to note: OpenGL draws objects in three-dimensional coordinates to a two-dimensional screen, and the order in which they are drawn is done in the order of the Code. As a result, the object that is drawn later obscures the first drawn object, even after the "back" of the object that was drawn earlier. This problem can be solved by using a depth test. The method used is: 1, call the Glenable function with Gl_depth_test as parameter, start the depth test. 2, when necessary (usually at the beginning of each drawing screen), empty depth buffer, namely: Glclear (Gl_depth_buffer_bit), wherein, glclear (gl_color_buffer_bit) and Glclear (gl_depth_ Buffer_bit) can be combined to write as:
Glclear (Gl_color_buffer_bit | Gl_depth_buffer_bit);
and the latter may run faster than the former.
So far, we can finally get the complete code for the whole "sun, Earth and Moon" system.
Code:
--------------------------------------------------------------------------------
The Sun, the Earth and the moon
Let's say every month is 30 days.
12 months a year, a total of 360 days
static int day = 200; Day change: from 0 to 359
void Mydisplay (void)
{
Glenable (gl_depth_test);
Glclear (Gl_color_buffer_bit | Gl_depth_buffer_bit);
Glmatrixmode (gl_projection);
Glloadidentity ();
Gluperspective (75, 1, 1, 400000000);
Glmatrixmode (Gl_modelview);
Glloadidentity ();
Glulookat (0,-200000000, 200000000, 0, 0, 0, 0, 0, 1);
Draw the Red "sun"
glcolor3f (1.0f, 0.0f, 0.0f);
Glutsolidsphere (69600000, 20, 20);
Draw the Blue "Earth"
glcolor3f (0.0f, 0.0f, 1.0f);
Glrotatef (day/360.0*360.0, 0.0f, 0.0f, -1.0f);
Gltranslatef (150000000, 0.0f, 0.0f);
Glutsolidsphere (15945000, 20, 20);
Draw a yellow "moon"
glcolor3f (1.0f, 1.0f, 0.0f);
Glrotatef (day/30.0*360.0-day/360.0*360.0, 0.0f, 0.0f, -1.0f);
Gltranslatef (38000000, 0.0f, 0.0f);
Glutsolidsphere (4345000, 20, 20);
Glflush ();
}
--------------------------------------------------------------------------------
Try changing the value of day to see how the picture changes.
Summary: At the beginning of this lesson, we formally entered the three-dimensional OpenGL world.
OpenGL transforms a three-dimensional object into a two-dimensional image through a matrix transformation, which is then displayed on the screen. In order to specify what kind of matrix the current operation is, we use the function Glmatrixmode.
We can move, rotate, or move or rotate an object, using the functions gltranslate* and glrotate*.
We can scale the object, and the function used is glscale*.
We can define the visual space, which can be "orthographic" (using Glortho or gluortho2d) or "Perspective projection" (using Glfrustum or gluperspective).
We can define the scope of the drawing to the window, and the function used is glviewport.
The matrix has its own "stack" for easy saving and recovery. This is useful when drawing complex graphics. The functions used are Glpushmatrix and Glpopmatrix.
Well, the hard lesson is finally over. I know that the content of this lesson is very dull, even the last example is. But I do not have a better way, I hope you can stick to the past. Do not worry, familiar with this lesson content, after a period of time, will be more relaxed and happy.
Introduction to OpenGL Learning (Fri)