`
melord
  • 浏览: 144037 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

OpenGL ES教程III之移动变换(原文对照)

阅读更多

OpenGL ES Tutorial for Android – Part III – Transformations

January 1st, 2010 by Per-Erik BergmanAndroid, Embedded

Last tutorial was about building your polygons. This tutorial is all about transformations, how to move the polygons around. I will continue this tutorial from where the previous ended so you can use that source code or make a copy of it.

上一教程详述了多边形的创建,本教程将讲述移动与变换。本教程以前一教程为基础(本系列教程也都遵照此原则)

I am not going to bore you with a lot of mathematics but I believe it is important to know that when OpenGL render a mesh it multiplies all vertices with a matrix. All the transformations you do are about manipulating the vertices in different ways by modifying this matrix. You can think of the matrix as a paper and that you never move the pen before you start to draw. You always draw in the center. But by doing a translation on the matrix you are moving the paper and also the center. A rotation is like rotating the paper around the center. And a scale is a bit harder to visualize with the paper view but it is like changing the unit size regarding to how you translate your meshes. Usually you talk about transformations according to the mesh not the world, but it is still important to know about.

在这里,我不打算讲一些算法以使你感到厌倦,但我相信知道OpenGL在展现网格时矩阵相乘原理是很重要的。所有的移动变换都是通过不同方式的矩阵相乘得到。你可以这样认为,矩阵是一张纸,在开始绘画之前,你没有移动笔,笔的位置固定在纸中心。做矩阵变换相当于移动纸(和中心点)旋转可以看做是纸绕着中心点旋转。缩放的话,理解更难一点,可以看做是更改网格纸的网格大小。

Coordinate System

OpenGL uses a so called right-handed coordinate system. A system is called right-handed if you look from the positive end towards the origin of the axis the counter-clockwise rotation is considered to be a positive rotation.

OpenGL 使用一种称之为右手坐标系,坐标轴末端相对于原点为正方向,逆时针方向视为正向旋转。

When you have started up your view and haven't applied any transformations the axis are aligned like this: The x-axis goes from left to right, the y-axis comes from the bottom and goes up and the z-axis is moving from the back of the screen towards the front of the screen.

当启动OpenGL视图,并未应用任何移动变换的话,那么各轴方向为:X轴是从左到右,Y轴从下到上,Z轴从背面到前面。如右图所示

 

Translate

public abstract void glTranslatef (float x, float y, float z) //OpenGL docs.

A translations added to the matrix makes the mesh appear as it has been moved. Translations are made along the axis and with no rotation added the axis are in there default state. Translation affects all the vertices in a polygon the same amount over the same axis. Translations are simply additions and subtractions to a current value. The image to the right shows a translation in 2 dimensions

移动是矩阵的相加,看起来像是网格在移动一样,移动按当前状态分别在三个轴的方向相加。移动导致多边形上的所有顶点在相同轴上相加一个相等的偏移量。因移动方向有正有负,所以也可以认为移动是在当前值进行加或减操作。右图显示的是一个2D的移动。

The start point is {x:-2, y:1} we like to go to {x:1, y:3} so we add {x:3, y:2}.

A simple addition: {x:-2, y:1} + {x:3, y:2} = {x:-2 + 3, y:1 + 2} = {x:1, y:3}.

In 3 dimensions we do the same, if we are located at position: {x:1, y:1, z:0} and we like to move 3 units into the screen we add {x:0, y:0, z:-3} and end up at: {x:1, y:1, z:-3}.

In the last tutorial we moved the square 4 units into the screen just to be able to see the square. What we did was that we added {x:0, y:0, z:-4} to the current position. This is the code we used for the translation:

在上个教程中,将方块指向屏幕内部方向移动4单位,相当于对当前位置做了一个{x:0, y:0, z:-4}的移动。

// Translates 4 units into the screen.

gl.glTranslatef(0, 0, -4); OpenGL docs.

If you do several translations after each other the order of the movement is along the X, Y and Z axis, in that order. On translate the order isn't so important but when we do a rotation it's really important.

当进行多次移动时,无论移动的顺序如何,最终结果是一样的。移动与顺序无关。但旋转就有关了。

It can be quite tricky to remember how the axis are aligned. Fortunate there is a good trick to remember the direction of the axis. Hold your left hand like the photo below. The point on each finger represents the positive direction on one axis. Your thumb is y-axis, index finger is x-axis and your middle finger would represent the z-axis. When I first started with 3D programming I actually wrote the letters, x, y and z on my fingers

对于记住坐标轴的对齐位置非常棘手,(我不认为这是一件困难的事,包括关于矩阵的相加与相乘的原理在高中时期就已经全面的学过了。)这里作者提供了一种快速记忆的方式,按如下图,伸出你的左手,掌心向着身体,食指方向为X轴,拇指方向为Y轴,中指方向为Z轴,在作者刚开始学3D编程时,常常将XYZ写在手指上的。

 

Rotate

public abstract void glRotatef(float angle, float x, float y, float z)//OpenGL docs.

Rotating is what it sounds like. You add a rotation to the matrix making it appears like the mesh are rotated. With no translation before the rotation is around the origo. The x, y and z values defines the vector to rotate around. The angle value is the number of degrees to rotate.

旋转可以看作是对网格的转动,如何未做移动的话,那么认为按原点进行旋转。X,y,z值定义了旋转的中心点,旋转的单位是角度(不是弧度)。

 

If you remember these three things you will manage rotation quite easy.

1. The rotation value are in degrees.
Most frameworks and math functions on computers use radians but OpenGL use degrees.

许多计算机上的框架和数学函数旋转值使用的是弧度,但是OpenGL不一样,它使用的角度。

2. When doing several rotations the order are important.
If you like to restore a rotation you negate the angle or all the axis like this:

glRotatef(angle, x, y, z) is restored with glRotatef(angle, -x, -y, -z) or glRotatef(-angle, x, y, z).

如果你想要还原的话,可以再转相同的负角底,或是按各轴的相反值进行旋转。如做了glRotatef(angle, x, y, z),想要还原的话,可以使用glRotatef(-angle, x, y, z)glRotatef(angle, -x, -y, -z)

But if you do several rotations after each other like this:

参考下图,各旋转之后的色子如下(绿色的箭头是X轴方向,蓝色的是Y轴方向,红色的为Z轴方向)

gl.glRotatef(90f, 1.0f, 0.0f, 0.0f); // OpenGL docs.

gl.glRotatef(90f, 0.0f, 1.0f, 0.0f); // OpenGL docs.

gl.glRotatef(90f, 0.0f, 0.0f, 1.0f); // OpenGL docs.

 

And want to restore the mesh to it's original position you can't just negate the angle like this:

gl.glRotatef(90f, -1.0f, 0.0f, 0.0f); // OpenGL docs.

gl.glRotatef(90f, 0.0f, -1.0f, 0.0f); // OpenGL docs.

gl.glRotatef(90f, 0.0f, 0.0f, -1.0f); // OpenGL docs.

 

You have to revert the order of the rotations as well like this:

gl.glRotatef(90f, 0.0f, 0.0f, -1.0f); // OpenGL docs.

gl.glRotatef(90f, 0.0f, -1.0f, 0.0f); // OpenGL docs.

gl.glRotatef(90f, -1.0f, 0.0f, 0.0f); // OpenGL docs.

The order of several rotations is important.

旋转的顺序很重要!!

3. If you look from the positive end towards the origin of the axis the positive rotation is counter-clockwise.

如果你视末端点为正方向,相对于原点,正向旋转为逆时针方向
If you take a pencil in your hand, let the point be in the same direction as your thumb, as in the picture below, then aligns the pencil with the x-axis.
Let the pencil's point be aligned with the positive direction of the axis. Your other fingers will now point in the positive direction of the rotation over that axis.

 

Translate & Rotate

Since both rotation and translations are made within each mesh own coordinate system it is important to remember that the order you do the translation and rotation are very important.

当同时进行移动和旋转的时候,请记住移动与旋转的顺序,这很重要,关系到最终的结果。

If you do a translation on the mesh first and then rotate it, the translation is made on the current state of the mesh coordinate system and then rotated at the new location.

如下图,先平移再旋转

 


If you first rotate and the move the mesh it will be moved accordingly to its own rotated coordinate system.

下图为先旋转,后平移的结果

 

Scale

public abstract void glScalef (float x, float y, float z) // OpenGL docs.

Scaling is just as it sounds and it is possible to scale over each axis separately. Scaling is the same as multiplying all vertexes with the same scalar. In the image below we scale with: gl.glScalef(2f, 2f, 2f). That means that we multiply all vertixes with 2.

缩放可以认为在每个轴方向进行单独的缩放。下图展示的是进行缩放2的结果

 

Translate & Scale

The order of scaling and translating does matter. If you translate before scaling the transformation is intact. Like this example, first a translation of 2 units and then scale it by 0.5.

同时进行移动与缩放,他们的先后顺序也是很重要的。请看下面的图,是先执行平移,再缩放的结果

gl.glTranslatef(2, 0, 0); // OpenGL docs.

gl.glScalef(0.5f, 0.5f, 0.5f); // OpenGL docs.

 


But if you scale before the translation you get a different result. Since you scale the mesh coordinate system then do the translation you will not move the mesh the same amount as you would before the scaling. So if you first scale with 0.5 and then do a translation of 2 units the result will appear as a translation of 1 unit.

但是如果你先缩放,再平移的话,那么,你将得到一个不同的结果。因为缩放,相当于将网格的单位值变更了。再平移的话,平衡量就不一样了。如之前的代码,先做绽放0.5,再平移2,最终平移相当于1,如下图

gl.glScalef(0.5f, 0.5f, 0.5f); // OpenGL docs.

gl.glTranslatef(2, 0, 0); // OpenGL docs.

 

Load Identity, push and pop matrix

When you translate, rotate or scaling you are not applying the transformation from the same preconditions, you are applying them to the previous transition. You need to be able to reset the position.

在进行平移,旋转,缩放时,如果你不想应用一些预处理来恢复到变换前的状态,可以重新当前矩阵达到同样的效果。

glLoadIdentity

public abstract void glLoadIdentity() // OpenGL docs.

glLoadIdentity replaces the current matrix with the identity matrix. It is the same as calling glLoadMatrix with the identity matrix:

glLoadIdentity的作用是将单位矩阵替换当前矩阵,等同于使用以下矩阵:

1 0 0 0

0 1 0 0

0 0 1 0

0 0 0 1

There are situations where you don't want to reset the model matrix, you rather want to go back to how it was just before your latest transformation.

如果你不想重围模型矩阵的话,只是想简单的回到刚才变换前的矩阵,可以使用以下函数:

glPushMatrix

public abstract void glPushMatrix() // OpenGL docs.

glPushMatrix makes a copy of the current matrix and put it on the stack. This means that when you do any kind of translations after glPushMatrix you are doing them on a copy.

作用是生成当前矩阵的拷贝,并将其压入栈中,这意味着在此之后,你对矩阵的任何操作,实际上相当于对复本的操作,不影响到原来的矩阵。

glPopMatrix

public abstract void glPopMatrix() // OpenGL docs.

To get back to the previous matrix you use the glPushMatrix command.

A good practice can be to have one glLoadIdentity in the begining of each frame and after that use glPushMatrix and glPopMatrix.

恢复到使用glPushMatrix之前的矩阵。推荐的做法是在帧开始时使用glLoadIdentity,然后后面使用glPushMatrixglPopMatrix

Putting it all togetter

So to make something with this new knowlege let us do 3 squares call them A, B and C. Scale them so that B is 50% smaller then A and C is 50% smaller then B. Then let A rotate counter-clockwise in the center of the screen. B should rotate clockwise around A and finaly C rotating clockwise around B and counter-clockwise in a high speed around it's own center.

在这里,我们使用三个方块ABC来模拟太阳,地球和月亮。其中BA绽放50%的结果,CB缩放50%的结果。A逆时针自转。BA顺时针转。CB顺时针转,并且高速逆时针自转

public void onDrawFrame(GL10 gl) {

        // Clears the screen and depth buffer.

        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

        // Replace the current matrix with the identity matrix

        gl.glLoadIdentity();

        // Translates 10 units into the screen.

        gl.glTranslatef(0, 0, -10); 

 

        // SQUARE A

        // Save the current matrix.

        gl.glPushMatrix();

        // Rotate square A counter-clockwise.

        gl.glRotatef(angle, 0, 0, 1);

        // Draw square A.

        square.draw(gl);

        // Restore the last matrix.

        gl.glPopMatrix();

 

        // SQUARE B

        // Save the current matrix

        gl.glPushMatrix();

        // Rotate square B before moving it, making it rotate around A.

        gl.glRotatef(-angle, 0, 0, 1);

        // Move square B.

        gl.glTranslatef(2, 0, 0);

        // Scale it to 50% of square A

        gl.glScalef(.5f, .5f, .5f);

        // Draw square B.

        square.draw(gl);                      

 

        // SQUARE C

        // Save the current matrix

        gl.glPushMatrix();

        // Make the rotation around B

        gl.glRotatef(-angle, 0, 0, 1);

        gl.glTranslatef(2, 0, 0);

        // Scale it to 50% of square B

        gl.glScalef(.5f, .5f, .5f);

        // Rotate around it's own center.

        gl.glRotatef(angle*10, 0, 0, 1);

        // Draw square C.

        square.draw(gl);

 

        // Restore to the matrix as it was before C.

        gl.glPopMatrix();

        // Restore to the matrix as it was before B.

        gl.glPopMatrix();

 

        // Increse the angle.

        angle++;

}

 

 

 

And don't forget to add angel as a variable as well. Thanks Tim!

public class OpenGLRenderer implements Renderer {

        private Square square;

        private float angle; // Don't forget to add this.

        ...

References

The info used in this tutorial is collected from:
Android Developers
OpenGL ES 1.1 Reference Pages

You can download the source for this tutorial here: Tutorial_Part_III
You can also checkout the code from: code.google.com

Previous tutorial: OpenGL ES Tutorial for Android – Part II – Building a polygon
Next tutorial: OpenGL ES Tutorial for Android – Part IV – Adding colors

Per-Erik Bergman
Consultant at
Jayway

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics