OpenGL ES Tutorial for Android – Part III – Transformations

2024-02-19 09:40

本文主要是介绍OpenGL ES Tutorial for Android – Part III – Transformations,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

OpenGL ES Tutorial for Android – Part III – Transformations

January 1st, 2010 by Per-Erik Bergman — Android, 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编程时,常常将X,Y,Z写在手指上的。

 

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,然后后面使用glPushMatrix和glPopMatrix。

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.

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

Java代码   收藏代码
  1. public void onDrawFrame(GL10 gl) {  
  2.   
  3.         // Clears the screen and depth buffer.  
  4.   
  5.         gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);  
  6.   
  7.         // Replace the current matrix with the identity matrix  
  8.   
  9.         gl.glLoadIdentity();  
  10.   
  11.         // Translates 10 units into the screen.  
  12.   
  13.         gl.glTranslatef(00, -10);   
  14.   
  15.    
  16.   
  17.         // SQUARE A  
  18.   
  19.         // Save the current matrix.  
  20.   
  21.         gl.glPushMatrix();  
  22.   
  23.         // Rotate square A counter-clockwise.  
  24.   
  25.         gl.glRotatef(angle, 001);  
  26.   
  27.         // Draw square A.  
  28.   
  29.         square.draw(gl);  
  30.   
  31.         // Restore the last matrix.  
  32.   
  33.         gl.glPopMatrix();  
  34.   
  35.    
  36.   
  37.         // SQUARE B  
  38.   
  39.         // Save the current matrix  
  40.   
  41.         gl.glPushMatrix();  
  42.   
  43.         // Rotate square B before moving it, making it rotate around A.  
  44.   
  45.         gl.glRotatef(-angle, 001);  
  46.   
  47.         // Move square B.  
  48.   
  49.         gl.glTranslatef(200);  
  50.   
  51.         // Scale it to 50% of square A  
  52.   
  53.         gl.glScalef(.5f, .5f, .5f);  
  54.   
  55.         // Draw square B.  
  56.   
  57.         square.draw(gl);                        
  58.   
  59.    
  60.   
  61.         // SQUARE C  
  62.   
  63.         // Save the current matrix  
  64.   
  65.         gl.glPushMatrix();  
  66.   
  67.         // Make the rotation around B  
  68.   
  69.         gl.glRotatef(-angle, 001);  
  70.   
  71.         gl.glTranslatef(200);  
  72.   
  73.         // Scale it to 50% of square B  
  74.   
  75.         gl.glScalef(.5f, .5f, .5f);  
  76.   
  77.         // Rotate around it's own center.  
  78.   
  79.         gl.glRotatef(angle*10001);  
  80.   
  81.         // Draw square C.  
  82.   
  83.         square.draw(gl);  
  84.   
  85.    
  86.   
  87.         // Restore to the matrix as it was before C.  
  88.   
  89.         gl.glPopMatrix();  
  90.   
  91.         // Restore to the matrix as it was before B.  
  92.   
  93.         gl.glPopMatrix();  
  94.   
  95.    
  96.   
  97.         // Increse the angle.  
  98.   
  99.         angle++;  
  100.   
  101. }  

 

 

 

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

这篇关于OpenGL ES Tutorial for Android – Part III – Transformations的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/724286

相关文章

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

usaco 1.2 Transformations(模拟)

我的做法就是一个一个情况枚举出来 注意计算公式: ( 变换后的矩阵记为C) 顺时针旋转90°:C[i] [j]=A[n-j-1] [i] (旋转180°和270° 可以多转几个九十度来推) 对称:C[i] [n-j-1]=A[i] [j] 代码有点长 。。。 /*ID: who jayLANG: C++TASK: transform*/#include<

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使

Android Environment 获取的路径问题

1. 以获取 /System 路径为例 /*** Return root of the "system" partition holding the core Android OS.* Always present and mounted read-only.*/public static @NonNull File getRootDirectory() {return DIR_ANDR

Android逆向(反调,脱壳,过ssl证书脚本)

文章目录 总结 基础Android基础工具 定位关键代码页面activity定位数据包参数定位堆栈追踪 编写反调脱壳好用的脚本过ssl证书校验抓包反调的脚本打印堆栈bilibili反调的脚本 总结 暑假做了两个月的Android逆向,记录一下自己学到的东西。对于app渗透有了一些思路。 这两个月主要做的是代码分析,对于分析完后的持久化等没有学习。主要是如何反编译源码,如何找到