Android OpenGL ES - 图形变换

一、概念

在OpenGl ES中,将一个3D模型显示到2D屏幕中有以下四个过程。

 1. 视角(Viewing)变换
 2. 模型(Modeling)变换
 3. 投影(Projection)变换
 4. 视窗(Viewport)变换
  • 视角(Viewing)变换

相当于你拿着一台照相机移动,从不同的位置来观察一个人,比如下图


这里写图片描述
  • 模型(Modeling)变换

此时相机不动,人做移动,比如下图


这里写图片描述

根据相对运动,可以看到视角(Viewing)变换和模型(Modeling)变换的效果是一样的。

  • 投影(Projection)变换

此时相机可以调整远近距离,人不动,这样观察到的也会不一样,比如下图


这里写图片描述
  • 视窗(Viewport)变换

按下快门之后,需要把像素按照比例转化后显示到屏幕上,这就是视窗(Viewport)变换,对应的就是

// Surface改变的的时候调用
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
    // 设置窗口大小
    gl.glViewport(0, 0, width  , height);
}

二、视角(Viewing)变换和 模型(Modeling)变换操作

前面说了,这两者产生的效果是一样的,具体的有以下三种变换

Translate    平移变换
Rotate       旋转变换
Scale        缩放变换
  • 平移变换

在平移变换之前,需调用以下代码才能进行变换

//设置为单位矩阵
gl.glLoadIdentity();

以上一篇绘制的三角形为例子,没移动前


这里写图片描述

调用glTranslatef(float x, float y, float z)方法进行平移

//向右移动0.6f个x坐标
gl.glTranslatef(0.6f, 0f, 0f);

效果


这里写图片描述
  • 旋转变换

调用glRotatef(float angle, float x, float y, float z)传入4个参数,角度和x、y、z坐标。此时一定要注意旋转的角度,角度为正表示逆时针。
PS:我发现可以用安培定则
来判断旋转方向,大拇指正对向量方向,卷曲手握着向量,手指弯曲的方向即为要旋转的方向。

//以(1f,0f,0f)空间向量旋转60度
gl.glRotatef(60, 1f, 0f, 0f);
这里写图片描述
//以(1f,0f,0f)空间向量旋转180度
gl.glRotatef(180, 1f, 0f, 0f);
这里写图片描述
  • 缩放变换

调用glScalef(float x, float y, float z)进行缩放,三个参数为缩放比例, 缩放之前的坐标乘以缩放比例即可
比如:

//缩小为原来0.1倍
gl.glScalef(0.1f,0.1f, 0.1f);

效果:


这里写图片描述
  • 组合变换

组合变换要注意顺序,比如平移和缩放变换组合起来,先平移后缩放和先缩放后平移的效果是不一样的。因为每次变换所依赖的是当前矩阵,先缩放再平移

//缩小为原来0.1倍 
gl.glScalef(0.1f,0.1f, 0.1f); 
//向右移动0.6f个x坐标 
gl.glTranslatef(0.6f, 0f, 0f);

效果:


这里写图片描述

先平移再缩放

//向右移动0.6f个x坐标 
gl.glTranslatef(0.6f, 0f, 0f); 
//缩小为原来0.1倍 
gl.glScalef(0.1f,0.1f, 0.1f);

效果:


这里写图片描述
  • 重置矩阵

如果想重置矩阵为没有任何变换之前,调用glLoadIdentity()
比如下面一段代码就将矩阵重置到之前的矩阵

//向右移动0.6f个x坐标
gl.glTranslatef(0.6f, 0f, 0f); 
//缩小为原来0.1倍 
gl.glScalef(0.1f,0.1f, 0.1f); 
//重置矩阵 
gl.glLoadIdentity();

效果图:


这里写图片描述
  • 保存、恢复矩阵

调用glPushMatrix保存当前矩阵,调用glPopMatrix恢复当前矩阵。
比如先保存矩阵,再重置矩阵,最后恢复矩阵,那么矩阵没改变。

//向右移动0.6f个x坐标 
gl.glTranslatef(0.6f, 0f, 0f); 
//缩小为原来0.1倍 
gl.glScalef(0.1f,0.1f, 0.1f); 
//保存当前矩阵 
gl.glPushMatrix(); 
//重置矩阵 
gl.glLoadIdentity(); 
//恢复矩阵 
gl.glPopMatrix();

效果图


这里写图片描述

三、投影(Projection)变换操作

前面说了,投影(Projection)变换相当于相机调整远近距离,人不动。
投影变换会定义一个视锥(viewing volume),视锥有两个作用

物体如何投影到屏幕(透视投影或者正侧投影)
裁剪场景的区域大小

OpenGL ES可以使用两种不同的投影变换:透视投影(Perspective Projection)和正侧投影(Orthographic Projection)

  • 透视投影(Perspective Projection)
    透视投影 ,就像我们眼睛看一个物体,近大远小。
    这里写图片描述

    从照相机(View Point)望去,由left、top、bottom、right四条线组成的面(也就是near面)和最远处的面(也就是far面)组成了一个椎体,这个椎体叫View volumn。
    裁剪
    就是把Viewing Volume之外的都裁剪掉,这样可以提高绘图性能。 定义透视投影的方法如下,传入6个参数

public void glFrustumf(float left,float right,float bottom,float top,float near,float far)

也可以用GLU.gluPerspective(fovy, aspect, zNear, zFar)方法,fovy是竖直方向也就是Y方向的夹角,aspect是near面的宽高比,即top的长度除以left长度。

  • 正侧投影(Orthographic Projection)
    透视投影 ,View Volumn椎体不变,一直是一个长方体,无论距离怎么改变,投影都不变。


    这里写图片描述

    定义正侧投影的方法如下,传入6个参数

public void glOrthof(float left, float right,float bottom,float top,float near,float far)

四、视窗(Viewport)变换操作

就是上面写的
按下快门之后,需要把像素按照比例转化后显示到屏幕上,这就是视窗(Viewport)变换,分两步

设置窗口的位置和大小 - glViewport(int x, int y, int width, int height)
设置观察的位置和角度 - GLU.gluLookAt(gl, eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ)

1.设置窗口的位置和大小

// Surface改变的的时候调用 
@Override public void onSurfaceChanged(GL10 gl, int width, int height) { 
    // 设置窗口大小 
    gl.glViewport(0, 0, width , height);
}

2.设置观察的位置和角度

GLU.gluLookAt(gl, eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ)
- eye理解为照相机或者你的眼睛,默认位置在原点(0,0,0) 
- center是观察物体的坐标,从eye到center的向量就是观察的方向 
- up默认为Y轴正方向,可以理解为眼睛到头顶的方向,比如改成(0,-1,0)那就是倒立着观察了

比如一个物体,默认gluLookAt坐标

@Override public void onDrawFrame(GL10 gl) { 
...... 
GLU.gluLookAt(gl, 0f, 0f, 0f, 0f, 0f, -1f, 0f, 1f, 0f);
......

效果如下:


这里写图片描述

我改为GLU.gluLookAt(gl, 0f, 0f, 0f, 0f, 0f, -1f, 1f, 0f, 0f);
即侧着头看,效果如下


这里写图片描述
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,783评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,360评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,942评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,507评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,324评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,299评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,685评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,358评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,652评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,704评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,465评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,318评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,711评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,991评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,265评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,661评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,864评论 2 335

推荐阅读更多精彩内容