OpenGL 3D Transformations — Learn about Viewing, Modeling, ModelView, Projection and Viewport Transf

from:http://www.falloutsoftware.com/tutorials/gl/gl5.htm

OpenGL Transformations. OpenGL Transformations are also explained in the famous OpenGL "Blue Book", also known as the Superbible. But since we're on a roll here and I do hope that you've read all of my previous OpenGL tutorials, you can now draw colored 3D primitives. That alone requires a lot of prior knowledge, and things didn't even start to look very exciting yet. This is why I think this is a good place to cover transformation and object movement in 3D space because our next topic after this is lighting, and shading does not always look very impressive on a static objects. We will first learn how to move objects in 3D space and then add some light to make those objects' shadows move, depending on where our light source is. This will of course create something more realistic than a static colored triangle from previous tutorials. I first want to write about about some fundamentals and then will go into technical stuff like Transformations and Matrices. You don't really need to know the math behind them but you need to understand how they work and to understand the transformation pipeline (the order of performing transformations which is essential to understanding concepts behind moving the view, the world itself and the objects in the world).

Transformations in General

Lets see what can possibly be done to an object to change its position in 3D space first. An object can be moved (we will use the term translating from now on because this term is more common among 3D programmers) on all 3 axis (X Y and Z) in either negative or positive direction; I would assume you already took that for granted. An object can also be rotated AROUND the 3 axis. The axis an object can be rotated about are different from the axis it is translated on. An object is usually rotated around its LOCAL coordinates and translated along the WORLD coordinates. Does that ring a bell yet? It should because I mentioned it in my tutorial entitled #0 - Introduction to 3D; and it would be a good practice to read it over once again if you're a beginner.

One of other types of 3D transformations is called scaling. Scaling is simply achieved by multiplying all vertices of an object by the amount you want to reduce or increase the size of that object. Scaling can be used in horizontal only or vertical only dimension to achieve stretching or shrinking of the object.

Excuse me, I have to make another point straight, aside from the main topic of this tutorial which is Object Composition. To build more complex objects than just a polygon we would need to have some utility software because it's a huge pain to do it manually by hard-coding all vertices, highly undesirable. For this reason translation and rotation will be demonstrated on a single triangle. Just think of it as an object. Objects after all are made of triangles too, there are just more than one triangle enclosing them. Also I should mention Object (or Model) Composition is a different topic and will be covered in my next tutorial just before I cover the OpenGL light model and how light works in general; that way we will be able to see lit, rotating objects rather than just plain boring polygons.

Lets take a look at this triangle and I will demonstrate some more logic behind objects and object movement in 3D space.

What makes this triangle different is that it has a center. This is of course, an imaginary center but you need to know where it is in your head when you construct an object. You see, when you build3D objects you have to always make sure you build them around the logical center which is located at X=0, Y=0, Z=0 in the object's LOCAL coordinate system. If you don't follow this simple rule, your object will not rotate evenly, since all objects rotate around their local center.

Here's another example of how an object or a Half-Life model in this case is built around its center. Notice the 3 colored lines underneath the monster in the 3D model view. Those lines spread out from the center along the x y and z planes. As you can see the body of the monster is built around the center. And it's "standing" exactly in the center. This is the general rule behind building models and/or objects (which are basically the same things).

Moving and rotating objects is not the only thing involved in 3D graphics transformations (which is described in the following paragraph). As I mentioned before you're always viewing the 3D world from your eyes, an imaginary object called camera. The camera can also be rotated and translated so that it would be possible to change your viewpoint. Remember that initially, after OpenGL perspective is initialized, the camera is located at the origin of the coordinate system, looking down the negative Z space by default. When we drew primitives in previous tutorial, we drew them a little further into the screen (remember how the Z coordinate of our colored triangle was always -4.0f?) so that it would be possible to see them from the camera. But what if the camera wasn't placed at the origin? What if we moved it to a new location, and gave it a new viewing angle? That leads us to conclusion that our 3D objects will be drawn with respect to the camera position. When you move the camera (and this step should always be first, before you move your objects or do any other transformations) you are actually modifying the view by applying the Viewing Transformation to the coordinate system. It is crucial to understand that when you are moving the camera, what happens is not the actual movement of camera in space. And when you move objects you don't actually move them from one point to another. In both cases, you are in fact modifying the coordinate systems by applying transformations on them. What matters is the end result which makes us think the objects move and the view is moving the way we want them. So all movement in 3D is based on these theoretical transformations. There are rules to these transformations, specifically which transformation should be performed after which. In the following chapters I explain all types of transformations and when they should be applied. As complex as transformations can be, OpenGL makes your life a lot easier by giving you specific functions to perform movement in 3D space, which are based on these transformations. In general you don't even need to know anything about how everything works but to follow the tradition of my detailed tutorials I decided to add those explanations.

3D Transformations

3D Transformations are achieved by modifying the given coordinate system. For example when you want to change the camera view, you apply the Viewing Transformation to the "main coordinate system" which is the world coordinate system. After that transformation is performed, any time you draw a new object, it is drawn according to the position of the new coordinate system, which is what makes the objects appear from a different point of view. You see how you're not directly moving the camera? This is the idea behind most transformations. It is however common to think of actual camera movement to understand it naturally, the way it would appear in real world. The whole purpose of transformations is imitation of movement in real world.

There are 4 types of main transformations we will be concerned with. You can even create your own by modifying some of matrices. But you shouldn't concern yourself with them or what they are at this point (or ever, because OpenGL, as always, does all the dirty job for us). The 4 transformations I will talk about are VIEWING, MODELING, PROJECTION and VIEWPORT transformations. There is a 5th transformation called MODELVIEW but it is really a combination of VIEWING and MODELING transformations which are actually the same as you will see. The VIEWPORT transformation is performed to scale the result into the window, it's not very important, so with all that said, we are basically down to two transformations Modelview and Projection.

A little aside from theory, I need to say a few things about how OpenGL handles certain things, and then I will continue with transformations. OpenGL has a function for specifying the current matrix which is the glMatrixMode function. It takes a single parameter mode which can be one of the following: GL_MODELVIEW, GL_PROJECTION or GL_TEXTURE. If you're not familiar with matrices, don't worry about them much. I am planning to explain matrices in the future in a separate tutorial because it's a whole new topic that needs to be addressed individually. Just think of glMatrixMode as a function that selects current transformation style. For example, calling glMatrixMode(GL_MODELVIEW) will tell OpenGL that any consequent transformation will be performed as a MODELVIEW transformation. In this tutorial we will only deal with GL_MODELVIEW transformations and this is enough to place your objects anywhere on your screen and rotate them in any way you want. In my OpenGL base code, I call glMatrixMode(GL_MODELVIEW) after all initialization is done inside the Resize function (Recall that the Resize function is called at least once during OpenGL initialization and then called whenever the window is resized, if it is). And while you're looking at it, the last line in the Resize function is a call to the glLoadIdentity function. That function loads the current matrix to identity. This should be a topic of a tutorial about matrices but I should briefly add that loading the current matrix to identity resets the current view. It's like starting from scratch. glLoadIdentity then should be called every frame before you draw anything. It resets whatever transformations were done in the previous frame back to a clean matrix again.

Back to transformations... And here is a list of all transformations with details.

The Viewing Transformation

The Viewing Transformation specifies location of the viewer or the camera. This transformation should be performed first before any other transformations. All consequent transformations will be based with respect to the effects of this transformation. Think of it as the main transformations that moves the view (camera) to a certain viewpoint. If you skip this step (which is what we did in previous tutorial) the camera will remain at the origin because it is transformed to the origin by default.

The Modeling Transformation

The Modeling Transformation is used to modify the position, rotation angle and size of your object (or parts of it) in a scene. Scaling is a type of modeling transformation if you apply it to your object. And if you do, that object will either appear smaller or bigger (depending on the scaling factor) in the view. Any movement applied to the objects, for instance if you move your monster model from one point to another, is achieved through the modeling transformation; and combined with say, walking animation (which has nothing to do with transformations) will result in a walking monster! See how both animation and modeling transformation put together makes a monster walk? Animation is not one of the topics of this tutorial, I was just making an example. Rotating the blades of your helicopter model is also a modeling transformation.

The Modelview Transformation

As a freak of nature the MODELVIEW transformation requires a little explanation. The Viewing and the Modeling transformations are really the same in terms of technicality. You see, there is really no difference between moving the view forward in the direction of the objects or moving all the objects backward in the direction of the camera. The resulting effect is identical. The termmodelview indicates that there is no distinction between the modeling and the viewing transformations and the principle behind which transformation it really is, is left to the programmer. So the Modelview Transformation can be used as both viewing or modeling transformation, depending on how it is used.

The Projection Transformation

As a final step the Projection Transformation is performed. This transformation finalizes what you will see on the screen by establishing the 2D view (based on 3D coordinates of desirably all visible objects' vertices and the camera position) as seen from the current camera view. This process is explained in tutorial #0 visually and I even have a formula there of how it can be achieved in software. Remember when we talked about projections? So yes this is also a part of transformation pipeline.

The Viewport Transformation

This is by far the easiest concept to understand. Once we have the 2D view of our 3D scene. The Viewport Transformation stretches that view into the OpenGL window.

Once you modified the coordinate system you can place objects on it and they will appear as if they were transformed by whatever you did to the coordinate system. You can even save the current state of the coordinate system and then retrieve it later on after more transformations are applied, and then to use it as a starting point for consequent transformations. By using this technique you will see that you will be able to place objects at any position and angle you want and you will even be able to draw objects that rotate around other objects that also rotate (simulating orbiting planets for example).

All transformations are consequent. It is up to the programmer to come up with the right order of transformations to achieve a wanted effect. For example, consider a Modeling Transformation of an object. Lets say you have a sphere object built around the center of its local coordinates. The order you perform your Modeling Transformation on the sphere is very important. Imagine that you first move the sphere left and then rotate it around the Y axis. The outcome is that the sphere will be rotating around an imaginary origin (located at [0, 0, 0]) as if it's a planet rotating around the sun and not around its center because you first displaced the sphere from its center and only THEN rotated it. Keep in mind that rotation is performed around the center of the given coordinate system. Now, imagine the same set of actions performed in a different order - first rotation and then movement to the left hand side. The sphere will appear to be rotating around its center at a distance from the center on the coordinate system (because you rotated it first, and only thenmoved it to a new position in the coordinate system.

this image is not available at the moment

I won't go into any of the math that operates behind those transformations. OpenGL hides all that from your eyes and only provides you with a few functions. Now we are actually ready to apply all of this to practice and use those functions. The functionality of transformations in OpenGL is really not that hard to understand even if you're a beginner. Anyone could just learn a function and remember that "that function" rotates an object and "this function" moves an object. That is also acceptable but you don't really learn anything about 3D graphics with that. That's the reason I included those explanations here. Everyone should know it! And now that you know how transformations work, you're ready to put them in action. Consider the following code.



void RenderFrame (void)
{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    glLoadIdentity();
    glTranslatef(0.0f, 0.0f, -4.0f);

    glBegin(GL_TRIANGLES);

    glColor3f(1.0f, 0.0f, 0.0f);
    glVertex3f(-1.0f, -0.5f, 0.0f);    // A

    glColor3f(0.0f, 1.0f, 0.0f);
    glVertex3f( 1.0f, -0.5f, 0.0f);    // B

    glColor3f(0.0f, 0.0f, 1.0f);
    glVertex3f( 0.0f,  0.5f, 0.0f);    // C

    glEnd();
}

To begin using the Modelview transformation (which is used to move or rotate models/objects) you have to first select it. As mentioned before this is done by calling glMatrixMode(GL_MODELVIEW). This call is required only once during initialization. And it is first called from the Resize function. Then the RenderFrame starts to repeat itself until you close the window.

The code above is the exact copy of the previous tutorial where I displayed a smoothly shaded triangle but with a few additions and changes. The first difference is that I added a call to glLoadIdentity, which should always be there before drawing anything or the view will not be reset and you will end up transforming your objects based on previous transformations and not a "clean" coordinate system. The second difference is that I'm not drawing the triangle with Z = -4.0 anymore.

I draw it exactly at the center of the coordinate system. But before I do, you will notice a call to glTranslatef. This is the function call that changes position of our triangle. We are translating it farther into the screen from its original position, that's why it appears at exactly the same position as in previous tutorial. The parameters of glTranslatef are 3 floating-point values that describe the X, Y and Z coordinates of where to translate (or move) the objects. Again, as I explained before, as you can see the coordinate system is first translated with glTranslatef and then the object is drawn which results in the object being farther away from the camera. These concepts are better understood if you keep practicing. By modifying all of the 3 parameters of glTranslate you can move the coordinate system to anywhere you want and then, when you draw your object it will appear on the screen according to the transformations you've made. See how you're not actually moving the object itself? The object still resides at [0, 0, 0] on its local coordinate system. Well, I explained how moving works, our next step is rotation.

Rotation is identical to translating. The function OpenGL provides you with to achieve rotation is glRotate. The variation of this function I will use is glRotatef, which as glTranslatef, deals with floating numbers. In theory this function multiplies the current matrix by a rotation matrix which in turn gives us rotation. How exactly this is done will be covered in my matrix tutorial and is purely mathematical. glRotatef takes 4 parameters: the angle of rotation, and the direction of rotation specified by x, y and z coordinates, in the following form glRotatef(float angle, float x, float y, float z). The angle of rotation is simply by what amount the object will turn. If the angle is a positive value, the objects will rotate in counter-clockwise direction, if the value is negative the object will rotate in clockwise direction. The amount by which to turn on each of the 3 axis is specified by the x, y and z parameters.

For example, lets make the x y z values to be [x=0, y=0, z=1.0] and make the angle=1.0. Which will look something like this:


glRotatef(1.0f,     0.0f, 0.0f, 1.0f);

In this case the triangle will make one turn equal to one angle in counter-clockwise direction on the z axis. Note that it will only make a turn equal to one angle. It will not constantly rotate the object because we refresh the view every time a new frame starts with glLoadIdentity. That means that we need to constantly change the angle of rotation to achieve real-time rotation. We know that on each axis you can rotate an object by 360 degrees to make a full turn. With this knowledge, lets write the following code


float angle = 0.0f;

void RenderFrame (void)
{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    glLoadIdentity();
    glTranslatef(0.0f, 0.0f, -4.0f);
    glRotatef(angle, 0.0f, 0.0f, 1.0f);

    glBegin(GL_TRIANGLES);

    glColor3f(1.0f, 0.0f, 0.0f);
    glVertex3f(-1.0f, -0.5f, 0.0f);

    glColor3f(0.0f, 1.0f, 0.0f);
    glVertex3f( 1.0f, -0.5f, 0.0f);

    glColor3f(0.0f, 0.0f, 1.0f);
    glVertex3f( 0.0f,  0.5f, 0.0f);

    glEnd();

    angle += 0.5f;

    if (angle >= 360.f)
        angle = 0.0f;
}

I added a new global variable angle which is constantly added half an angle to until it reaches a 360 degree angle. Then the value is clamped to 0 and the process repeats. The main part of the code remains in the beginning. As in the previous example I first translate the object farther into the screen so we can see it, and then apply rotation, passing glRotate the current angle specified by the variable angle. Each frame angle increases and the angle of the rotation changes accordingly. The view is reset every time the triangle is drawn with a new angle of rotation. This code results in a smoothly "rotating" triangle on the z axis. Try to experiment with passing different X Y and Z values to glRotate and see how it changes the rotation of triangle. Try to modify the position of the triangle as it spins in "real-time". Also try adding more triangles to the scene. Remember that when you want to add a new object, to the scene and draw it in relation to the previous object, you need to reset the view with glLoadIdentity again and specify new coordinates with glTranslatef (and glRotatef if you want your new object to be roating). For instance, here is the code that draws two "objects" identified by as of now well-known triangles. The first triangle will be located at z = -4.0, and rotating in counter-clockwise direction. The second triangle will be located a little closer to the camera, at z = -3.0 and will be rotating in clockwise direction.


float angle = 0.0f;

void DrawTriangle (void)
{
    glBegin(GL_TRIANGLES);

    glColor3f(1.0f, 0.0f, 0.0f);
    glVertex3f(-1.0f, -0.5f, 0.0f);

    glColor3f(0.0f, 1.0f, 0.0f);
    glVertex3f( 1.0f, -0.5f, 0.0f);

    glColor3f(0.0f, 0.0f, 1.0f);
    glVertex3f( 0.0f,  0.5f, 0.0f);

    glEnd();
}

void RenderFrame (void)
{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    glLoadIdentity();
    glTranslatef(0.0f, 0.0f, -4.0f);
    glRotatef(angle, 0.0f, 0.0f, 1.0f);

    DrawTriangle();

    glLoadIdentity();
    glTranslatef(0.0f, 0.0f, -3.0f);
    glRotatef(-angle, 0.0f, 0.0f, 1.0f);

    DrawTriangle();

    angle += 0.5f;

    if (angle >= 360.f)
        angle = 0.0f;
}

Note that I enclosed drawing triangle in a function DrawTriangle so it is easier to see the logic behind transformations applied to both triangles. First triangle is translated back a little, away from the camera and is rotated. Then the view is cleared back to original position with glLoadIdentity. The second triangle is then drawn according to the new translation and rotation coordinates specified by consequent calls to glTranslatef and glRotatef. And finally the angle of rotation is changed. Note that when the second triangle is rotated, the negative value of angle is used. This makes the second triangle spin in an opposite direction to the first triangle.

This was definitely a long tutorial but a lot of ground has to be covered. I hope you enjoyed it as much as I enjoyed writing it. The source code is a copy of the last example with two spinning triangles. Well, there is still not much you can do with colored, spinning triangles. The next tutorial covers object composition. I will make a fast object loader and then we will be able to use some of the objects I've created for our experiments with OpenGL light model, instead of boring triangles.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值