Android OpenGL ES 简明开发教程四:3D 坐标变换

来源:互联网 发布:淘宝店铺图片描述尺寸 编辑:程序博客网 时间:2024/05/16 12:11

本篇介绍3D 坐标系下的坐标变换transformations。

Coordinate System坐标系

OpenGL使用了右手坐标系统,右手坐标系判断方法:在空间直角坐标系中,让右手拇指指向x轴的正方向,食指指向y轴的正方向,如果中指能指向z轴的正方向,则称这个坐标系为右手直角坐标系。

Translate平移变换

方法public abstract void glTranslatef (float x, float y, float z) 用于坐标平移变换。

在上个例子中我们把需要显示的正方形后移了4个单位,就是使用的坐标的平移变换,可以进行多次平移变换,其结果为多个平移矩阵的累计结果,矩阵的顺序不重要,可以互换。

Rotate旋转

方法public abstract void glRotatef(float angle, float x, float y, float z)用来实现选择坐标变换,单位为角度。 (x,y,z)定义旋转的参照矢量方向。多次旋转的顺序非常重要。

比如你选择一个骰子,首先按下列顺序选择3次:

[java] view plaincopyprint?
  1. gl.glRotatef(90f, 1.0f, 0.0f, 0.0f);  
  2. gl.glRotatef(90f, 0.0f, 1.0f, 0.0f);  
  3. gl.glRotatef(90f, 0.0f, 0.0f, 1.0f);  

然后打算逆向旋转回原先的初始状态,需要有如下旋转: 


[java] view plaincopyprint?
  1. gl.glRotatef(90f, -1.0f, 0.0f, 0.0f);  
  2. gl.glRotatef(90f, 0.0f, -1.0f, 0.0f);  
  3. gl.glRotatef(90f, 0.0f, 0.0f, -1.0f);  


或者如下旋转: 

[java] view plaincopyprint?
  1. gl.glRotatef(90f, 0.0f, 0.0f, -1.0f);  
  2. gl.glRotatef(90f, 0.0f, -1.0f, 0.0f);  
  3. gl.glRotatef(90f, -1.0f, 0.0f, 0.0f);  

旋转变换glRotatef(angle, -x, -y, -z) 和glRotatef(-angle, x, y, z)是等价的,但选择变换的顺序直接影响最终坐标变换的结果。 角度为正时表示逆时针方向。

Translate & Rotate (平移和旋转组合变换)

在对Mesh(网格,构成三维形体的基本单位)同时进行平移和选择变换时,坐标变换的顺序也直接影响最终的结果。

比如:先平移后旋转, 旋转的中心为平移后的坐标。

先选择后平移: 平移在则相对于旋转后的坐标系:

一个基本原则是,坐标变换都是相对于变换的Mesh本身的坐标系而进行的。

Scale(缩放)

方法public abstract void glScalef (float x, float y, float z)用于缩放变换。

下图为使用gl.glScalef(2f, 2f, 2f) 变换后的基本,相当于把每个坐标值都乘以2.

Translate & Scale(平移和缩放组合变换)

同样当需要平移和缩放时,变换的顺序也会影响最终结果。

比如先平移后缩放:

[java] view plaincopyprint?
  1. gl.glTranslatef(200);  
  2. gl.glScalef(0.5f, 0.5f, 0.5f);  

如果调换一下顺序:


[java] view plaincopyprint?
  1. gl.glScalef(0.5f, 0.5f, 0.5f);  
  2. gl.glTranslatef(200);  


 

矩阵操作,单位矩阵

在进行平移,旋转,缩放变换时,所有的变换都是针对当前的矩阵(与当前矩阵相乘),如果需要将当前矩阵回复最初的无变换的矩阵,可以使用单位矩阵(无平移,缩放,旋转)。

public abstract void glLoadIdentity()。

在栈中保存当前矩阵和从栈中恢复所存矩阵,可以使用

public abstract void glPushMatrix()

public abstract void glPopMatrix()。

在进行坐标变换的一个好习惯是在变换前使用glPushMatrix保存当前矩阵,完成坐标变换操作后,再调用glPopMatrix恢复原先的矩阵设置。

最后利用上面介绍的坐标变换知识,来绘制3个正方形A,B,C。进行缩放变换,使的B比A小50%,C比B小50%。 然后以屏幕中心逆时针旋转A,B以A为中心顺时针旋转,C以B为中心顺时针旋转同时以自己中心高速逆时针旋转。

修改 onDrawFrame 代码如下:

 

[java] view plaincopyprint?
  1. public void onDrawFrame(GL10 gl) {  
  2.  // Clears the screen and depth buffer.  
  3.  gl.glClear(GL10.GL_COLOR_BUFFER_BIT  
  4.  | GL10.GL_DEPTH_BUFFER_BIT);  
  5.  // Replace the current matrix with the identity matrix  
  6.  gl.glLoadIdentity();  
  7.  // Translates 10 units into the screen.  
  8.  gl.glTranslatef(00, -10);  
  9.    
  10.  // SQUARE A  
  11.  // Save the current matrix.  
  12.  gl.glPushMatrix();  
  13.  // Rotate square A counter-clockwise.  
  14.  gl.glRotatef(angle, 001);  
  15.  // Draw square A.  
  16.  square.draw(gl);  
  17.  // Restore the last matrix.  
  18.  gl.glPopMatrix();  
  19.    
  20.  // SQUARE B  
  21.  // Save the current matrix  
  22.  gl.glPushMatrix();  
  23.  // Rotate square B before moving it,  
  24.  //making it rotate around A.  
  25.  gl.glRotatef(-angle, 001);  
  26.  // Move square B.  
  27.  gl.glTranslatef(200);  
  28.  // Scale it to 50% of square A  
  29.  gl.glScalef(.5f, .5f, .5f);  
  30.  // Draw square B.  
  31.  square.draw(gl);  
  32.    
  33.  // SQUARE C  
  34.  // Save the current matrix  
  35.  gl.glPushMatrix();  
  36.  // Make the rotation around B  
  37.  gl.glRotatef(-angle, 001);  
  38.  gl.glTranslatef(200);  
  39.  // Scale it to 50% of square B  
  40.  gl.glScalef(.5f, .5f, .5f);  
  41.  // Rotate around it's own center.  
  42.  gl.glRotatef(angle*10001);  
  43.  // Draw square C.  
  44.  square.draw(gl);  
  45.    
  46.  // Restore to the matrix as it was before C.  
  47.  gl.glPopMatrix();  
  48.  // Restore to the matrix as it was before B.  
  49.  gl.glPopMatrix();  
  50.    
  51.  // Increse the angle.  
  52.  angle++;  
  53.    
  54.  }  

原创粉丝点击