美文网首页
Android OpenGL ES - 图形变换

Android OpenGL ES - 图形变换

作者: CHSmile | 来源:发表于2017-10-25 15:36 被阅读275次

    一、概念

    在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);
    即侧着头看,效果如下


    这里写图片描述

    相关文章

      网友评论

          本文标题:Android OpenGL ES - 图形变换

          本文链接:https://www.haomeiwen.com/subject/wlmqpxtx.html