Android OpenGL ES学习笔记之图形变换

一、概念

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

 1. 视角(Viewing)变换

 2. 模型(Modeling)变换

 3. 投影(Projection)变换

 4. 视窗(Viewport)变换

视角(Viewing)变换

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

Android OpenGL ES学习笔记之图形变换_第1张图片


模型(Modeling)变换

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

Android OpenGL ES学习笔记之图形变换_第2张图片


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

投影(Projection)变换

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

Android OpenGL ES学习笔记之图形变换_第3张图片


视窗(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();

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

Android OpenGL ES学习笔记之图形变换_第4张图片

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

向右移动0.6f个x坐标

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

效果

Android OpenGL ES学习笔记之图形变换_第5张图片


旋转变换

调用glRotatef(float angle, float x, float y, float z)传入4个参数,角度和x、y、z坐标。此时一定要注意旋转的角度,角度为正表示逆时针。

PS:我发现可以用安培定则 来判断旋转方向,大拇指正对向量方向,卷曲手握着向量,手指弯曲的方向即为要旋转的方向。

    //以(1f,0f,0f)空间向量旋转60度
    gl.glRotatef(60, 1f, 0f, 0f);

Android OpenGL ES学习笔记之图形变换_第6张图片

    //以(1f,0f,0f)空间向量旋转180度
    gl.glRotatef(180, 1f, 0f, 0f);

Android OpenGL ES学习笔记之图形变换_第7张图片


缩放变换

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

比如:

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

效果:

Android OpenGL ES学习笔记之图形变换_第8张图片


组合变换

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

先缩放再平移

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

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

效果:

Android OpenGL ES学习笔记之图形变换_第9张图片


先平移再缩放

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

效果:

Android OpenGL ES学习笔记之图形变换_第10张图片


重置矩阵

如果想重置矩阵为没有任何变换之前,调用glLoadIdentity()

比如下面一段代码就将矩阵重置到之前的矩阵

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

效果图:

Android OpenGL ES学习笔记之图形变换_第11张图片


保存、恢复矩阵

调用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();

效果图

Android OpenGL ES学习笔记之图形变换_第12张图片


三、投影(Projection)变换操作

前面说了,投影(Projection)变换相当于相机调整远近距离,人不动。

投影变换会定义一个视锥(viewing volume),视锥有两个作用

 - 物体如何投影到屏幕(透视投影或者正侧投影)

 - 裁剪场景的区域大小

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


透视投影(Perspective Projection)

透视投影 ,就像我们眼睛看一个物体,近大远小。 如下图

Android OpenGL ES学习笔记之图形变换_第13张图片

从照相机(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椎体不变,一直是一个长方体,无论距离怎么改变,投影都不变。

Android OpenGL ES学习笔记之图形变换_第14张图片

定义正侧投影的方法如下,传入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)

设置窗口的位置和大小

这个之前讲过,没什么好说的

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

设置观察的位置和角度

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);
        ......

效果如下:

Android OpenGL ES学习笔记之图形变换_第15张图片

我改为GLU.gluLookAt(gl, 0f, 0f, 0f, 0f, 0f, -1f, 1f, 0f, 0f);

即侧着头看,效果如下

Android OpenGL ES学习笔记之图形变换_第16张图片


五、结束

图形的变换就介绍到这,下一篇讲解如何给图形添加颜色。

你可能感兴趣的:(Android,OpenGL,ES,Android,OpenGL,ES学习笔记)