OpenGL Study Notes 3 (Introduction to 3D scenario transformation)

Source: Internet
Author: User

Note: The following content is from OpenGL getting started tutorial.

Select a part of content for learning ~~~

When we draw a geometric image above, do you think our plot scope is too narrow? Coordinates can only be from-1 to 1, and can only be the right X axis, Y axis up, Z axis vertical screen. These limitations cause a lot of inconvenience to our drawing.

We live in a 3D world-if we want to observe an object, we can:
1. Observe it from different locations. (View transformation)
2. Move or rotate it. Of course, if it is just an object in a computer, we can also zoom in or out it. (Model Transformation)
3. If you draw an object, you can choose whether to use a perspective effect of "near Big, far and small. 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. (View-view conversion)
These can be implemented in OpenGL.

OpenGL transformation is actually implemented through matrix multiplication. Whether it is moving, rotating, or scaling, the current matrix is multiplied by a new matrix.

OpenGL can operate the Matrix directly at the bottom layer. However, as a beginner, this does not make much sense. I will not introduce it here.

1. model transformation and view Transformation

From the perspective of "relative movement", changing the position and direction of the observation point and changing the position and direction of the object are equivalent. In OpenGL, the same functions are even used to implement these two functions.
Since both model and view transformations are implemented through matrix operations, you should first set the current operation matrix to "Model View matrix" Before transformation ". The gl_modelview parameter is used to call the glmatrixmode function, as shown in the following code:

Glmatrixmode (gl_modelview );

In general, we need to set the current matrix as a unit matrix before transformation. This also requires only one line of code:

Glloadidentity ();

Then, you can perform model transformation and view transformation.

Model and view transformation involves three functions:

Gltranslate * to multiply the current matrix with a matrix that represents a moving object. The three parameters represent the displacement values on the three coordinates respectively.
Glrotate *, which is used to multiply the current matrix and a matrix representing the rotated object. An object rotates in a straight line from (0, 0) to (x, y, z) counterclockwise. The angle parameter indicates the rotation angle.
Glscale * is used to multiply the current matrix and a matrix representing a scaled object. X, Y, and Z respectively indicate the scaling ratio in this direction.

Note that I always say "multiply with xx", instead of simply saying "this function is rotating" or "this function is moving". There is a reason for this. I will talk about it right away.

Assume that the current matrix is a matrix of units, multiply it by a matrix R that represents rotation, multiply it by a matrix T that represents movement, and then multiply the final matrix by the coordinate matrix V of each vertex. Therefore, the transformed vertex coordinates are (RT) V ). Because of the combination rate of matrix multiplication, (RT) V) = (R (TV), in other words, it is actually moving first and then rotating. That is, the actual conversion order is the opposite of the write order in the code. Because the results obtained by "first move, then rotate" and "first rotate and then move" are very different, you need to pay special attention to this point when you are a beginner.

OpenGL is designed to achieve higher efficiency. However, it is also very painful to consider how to reverse a complex 3D image every time. Another idea is introduced here to make the Code look more natural (the code written is actually exactly the same, but the method used when considering the problem is different ).
As we can imagine, the coordinates are not fixed. During rotation, the coordinate system rotates with the object. When moving, the coordinate system moves with the object. In this way, you do not need to consider the code reverse order.

The above are all about changing the position and direction of an object. To change the position of the observation point, you can also use the glrotate * And gltranslate * functions: glulookat. It has many parameters. The first three parameters represent the position of the observation point, the middle three parameters represent the position of the observation target, and the last three parameters represent the position from (0, 0, 0) to a straight line (x, y, z), which represents the "top" direction that the observer Deems.

2. Projection Transformation

A projection transformation defines a visible space. objects other than the visible space are not drawn to the screen. (Note: from now on, the coordinates can no longer be-1.0 to 1.0 !)

OpenGL supports two types of projection transformations: Perspective Projection and normal projection. Projection is also implemented using matrices. To operate the projection matrix, use the gl_projection parameter to call the glmatrixmode function.

Glmatrixmode (gl_projection );

In general, we need to set the current matrix as a unit matrix before transformation.

Glloadidentity ();

The result of perspective projection is similar to a photo, which has the effect of being close to big and small. For example, taking a picture of a railway track forward in the front of the locomotive, the two rails seem to have crossed in the distance.

You can use the glfrustum function to set the current visible space to the Perspective Projection space.

The parameter meanings include:

Statement: this image is from www.opengl.org. It is a picture of the book OpenGL programming guide. Since the old version of this book (the first version, 1994) has been circulating on the internet, I hope I have not touched on copyright issues.
You can also use more commonly used gluperspective functions. The parameter meanings include:

Normal projection is equivalent to the result observed in an infinite distance. It is just an ideal state. However, for computers, using positive projection may lead to better running speed.
You can use the glortho function to set the current visible space to a positive projection space. The parameter meanings include:

If the drawing space itself is two-dimensional, you can use gluortho2d. Its usage is similar to glorgho.

3. Modify the view
When everything is ready, you just need to draw pixels to the screen. At this time, the last question remains: Which area of the window should the pixel be drawn? Normally, the entire window is completely filled by default, but we can only fill in half. (That is, fill the entire image in half of the window)

Use glviewport to define the view. The first two parameters define the lower left foot (0, 0 indicates the bottom left) of the view, and the last two parameters are width and height.

4. Operation matrix Stack

When performing a matrix operation, we may need to save a matrix and restore it later. When we need to save it, call the glpushmatrix function, which is equivalent to putting the 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 requires that the stack capacity can contain at least 32 matrices. In some OpenGL implementations, the stack capacity actually exceeds 32. Therefore, you do not have to worry too much about the Matrix capacity.

Generally, it is more convenient and faster to save and restore data before performing the first transformation and then performing the inverse transformation.
Note: Both the Model View matrix and the projection matrix have corresponding stacks. Use glmatrixmode to specify whether the current operation is a model view matrix or a projection matrix.

5. Comprehensive examples

We want to create a three-dimensional scenario, including the sun, Earth, and moon. Assume that there are 12 months in a year and 30 days each month. Every year, the Earth rotates around the sun. Every month, the moon circle the earth. That is, there are 360 days in a year. The number of the given date (0 ~ 359), the relative positions of the sun, Earth, and moon must be drawn. (This is designed for programming convenience. If you need to make a more realistic situation, it is only some numerical processing, and has little to do with OpenGL)

First, let us determine that these three celestial bodies are spherical and their motion tracks are in the same horizontal plane,

Create the following coordinate system: the center of the Sun is the origin, and the plane of the celestial trajectory represents the plane determined by the X and Y axes. On the first day of each year, the Earth is in the positive direction of the X axis, the moon is in the positive X axis of the Earth.


The next step is to establish a visual space. Note: The radius of the sun is much shorter than the distance from the sun to the Earth. If we directly use the length ratio obtained from astronomical observations, the size of the sun will be ignored when the entire window represents an hour of the Earth's orbit. Therefore, we can only multiply the radius of several celestial bodies to meet our observation needs. (For Baidu, the approximate radius of the sun, Earth, and moon is 696000 km, 6378 km, and 1738 km respectively. The distance from the Earth to the sun is about 0.15 billion km = 150000000 km, and the distance from the moon to the Earth is about 380000 km .)
Let's assume some data and modify the radius of the three celestial bodies to 69600000 (100 times), 15945000 (2500 times), and 4345000 (2500 times ). Change the distance from the Earth to the Moon to 38000000 (up 100 times ). The distance from the Earth to the Sun remains unchanged.

To make the earth and the moon very close to us, we still don't need to change the observation points and the observation direction to observe them. We put the observation points in this position: (0,-200000000, 0) -- because the Earth's orbital radius is 150000000, we can get an integer and get-200000000. Set the observation target to the origin (that is, the sun center), and select the positive direction of the Z axis as the "upper" side. Of course, we can also move the observation point to the "TOP" side to get (0,-200000000,200 usd00), so that we can get a look-down effect of 45 degrees.
To get the perspective effect, we use gluperspective to set the visual space. It is assumed that the angle of view is 60 degrees (if this angle is found inappropriate during debugging, it can be modified. The value I selected at the end is 75 .), The aspect ratio is 1.0. The nearest visible distance is 1.0, and the farthest visible distance is 200000000*2 = 400000000. That is: 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 all three celestial bodies as the regular sphere. In the glut utility we use, there is a ready-made function to draw the sphere: glusolidsphere, which is used to draw a sphere at the "origin.

Since coordinates can be freely transformed using the gltranslate * And glrotate * functions, we can draw a sphere at any position.

The function has three parameters: the first parameter represents the radius of the sphere, and the last two parameters represent the number of "planes". Simply put, the accuracy of the sphere increases, of course, the lower the speed.

Here we just set the last two parameters to 20.

The sun is at the coordinate origin, so it does not need to undergo any transformation and can be directly drawn.

The Earth must be a little more complex and need to change coordinates. Since the number of days passed this year is known to be day, the earth turns to the angle of day/The number of days in a year * 360 degrees. It has been assumed that every year is 360 days, so the earth turns to day. So we can solve the problem through the following code:

Glrotatef (day, 0, 0,-1)

/* Note that the earth's public rotation is "from West to East", so it is a clockwise rotation in the negative direction of the Z axis */

Gltranslatef (Earth Orbit Radius, 0, 0 );
Glusolidsphere (Earth radius, 20, 20 );

The moon is the most complex. Because it not only has to go around the Earth, but also has to go around the sun. However, if we choose the Earth as a reference, the movement of the moon is a simple circular motion. If we plot the Earth first and then the moon, we only need to perform a transformation similar to the earth:

Glrotatef (moon rotation angle, 0, 0,-1 );
Gltranslatef (Moon orbital radius, 0, 0 );
Glusolidsphere (Moon radius, 20, 20 );

However, this "Rotation Angle of the Moon" cannot be simply understood as day/day of a month at 30*360 degrees. Because when we plot the earth, the coordinates have already been rotated. The current rotation is based on the previous rotation, so you still need to process this "difference ". We can write it as: Day/30*360-day, that is, minus the original angle that has been switched.

This is just a simple process.

Of course, you can also use glpushmatrix to save the matrix before drawing the Earth, and then use glpopmatrix to restore the matrix. Design a formula for the Moon location unrelated to the Earth location to draw the moon.

Generally, the latter method is better than the former method, because the floating point operation is not accurate, that is, we calculate the location of the Earth itself is not accurate. Using this inaccurate number to calculate the position of the moon will lead to the accumulation of "inaccurate" components, and excessive "inaccurate" May cause errors. We didn't think about this in this small program, but it doesn't mean this issue is not important.

Note: OpenGL draws objects in 3D coordinates to a two-dimensional screen, and the order of drawing is in the order of code. Therefore, the objects drawn later will cover the objects first drawn, even if the objects drawn later are the "back" of the objects first drawn. Deep testing can solve this problem.

The method is as follows: 1. Call the glable function with the gl_depth_test parameter to start the deep test.

2. When necessary (usually at the beginning of each screen), clear the depth buffer, that is, glclear (gl_depth_buffer_bit );

Here, glclear (gl_color_buffer_bit) and glclear (gl_depth_buffer_bit) can be combined:
Glclear (gl_color_buffer_bit | gl_depth_buffer_bit );
The latter may run faster than the former.

So far, we can finally get the complete code of the entire "Sun, earth and moon" system.

Code:

# Include <Gl/glut. h> // The Sun, Earth, and moon. // assume that each month is 30 days. // 12 months a year. The total number is 360 days. Static int day = 200. // the change of day: from 0 to 359 void mydisplay (void) {glenable (gl_depth_test); // start the deep test (if the drawn image is in front of the existing image, it will be overwritten, instead of hiding others' glclear (gl_color_buffer_bit | gl_depth_buffer_bit); // clear the color and depth buffer 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, 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); fig (15945000, 20, 20); // draw the 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); Glu Tsolidsphere (4345000, 20, 20); glflush ();} int main (INT argc, char * argv []) {gluinit (& argc, argv ); // initialize the glut. This function must be called once before other gluts are used (glu_rgb | glu_single); // you can set the display mode to gluinitwindowposition (100,100 ); // set the window location. The parameter is used as the title of the window. Gludisplayfunc (& mydisplay); // call the mydisplay function () when drawing a picture; // return 0 in a message loop ;}

Result:

Function usage:

Glloadidentity ()


Move the origin of the current user coordinate system to the center of the screen: similar to a reset operation
1. X axis from left to right, Y axis from bottom to top, and Z axis from inside to outside.
2. The coordinates of the OpenGL screen center are 0.0f points on the X and Y axes.
3. The coordinate value on the left of the center is a negative value, and the right is a positive value.
Moving to the top of the screen is positive, and moving to the bottom of the screen is negative.
Moving to the depth of the screen is a negative value, and moving out of the screen is a positive value.

Gltranslatef (x, y, z)

Move along the X, Y, and Z axes.

Note that in gltranslatef (x, y, z), when you move, you do not move relative to the center of the screen, but relative to the current screen position. The function is to translate the origin of the Point coordinate to A (x, y, z) vector based on the current origin.

Glrotatef (angle,
X, Y, Z)

Similar to gltranslatef (x, y, z), glrotatef (angle, x, y, z) also operates the coordinate system.
The rotation axis goes through the origin. The orientation is (x, y, z), the rotation angle is angle, and the orientation meets the right-hand rule.

//////////////////////////////////////// //////////////////////////////////////// /////////////////////////////

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.