OpenGL ES 3. 投影方式 详述

大家好,接下来为大家介绍OpenGL ES 3. 的投影方式。

1、摄像机的设置

        从日常生活的经验中可以很容易地了解到,随着摄像机位置、姿态的不同,就算是对同一 个场景进行拍摄,得到的画面也是迥然不同的。因此摄像机的位置、姿态在OpenGL ES 应用程序的开发中就显得非常重要,首先需要介绍一下摄像机的设置方法。

摄像机的设置需要给出 3 方面的信息,包括摄像机的位置、观察的方向以及 up 方向,具体情况如下图所示。

a:摄像机的位置很容易理解,用其在 3D 空间中的坐标来表示。

b:摄像机观察的方向可以理解为摄像机镜 头的指向,用一个观察目标点来表示(通过摄像机位置与观察目标点可以确定一个向量,此向量 即代表了摄像机观察的方向)。

c:摄像机的 up 方向可以理解为摄像机顶端的指向,用一个向量来表示。

设置摄像机的api如下:

Matrix.setLookAtM( 
        mVMatrix,        //存储生成矩阵元素的 float[]类型数组 
        0,               //填充起始偏移量
        cx, cy, cz,      //摄像机位置的 X、Y、Z 坐标 
        tx, ty, tz,      //观察目标点 X、Y、Z 坐标
        upx, upy, upz    //up 向量在 X、Y、Z 轴上的分量
)

 

2、正交投影

        OpenGL ES 中,根据应用程序中提供的投影矩阵,管线会确定一个可视空间区域,称为视景体。视景体是由 6 个平面确定的,这 6 个平面分别为:上平面(up)、下平面(down)、左平 面(left)、右平面(right)、远平面(far)、近平面(near)。
        场景中处于视景体内的物体会被投影到近平面上(视景体外面的物体将被裁剪掉),然后再将近平面上投影出的内容映射到屏幕上的视口中。

        正交投影示意图如下图所示:

        使用Matrix.orthoM()来设置正交投影。

    /**
     * @param m 生成的投影矩阵,float[4*4]
     * @param mOffset 填充时候起始的偏移量
     * @param left  近平面left边的x坐标
     * @param right 近平面right边的x坐标
     * @param bottom  近平面bottom边的y坐标
     * @param top   近平面top边的y坐标
     * @param near  近平面距离摄像机的距离
     * @param far   远平面距离摄像机的距离
     */
public static void orthoM(float[] m, int mOffset,
        float left, float right, float bottom, float top,
        float near, float far) {
}

正交投影的使用示例如下:

public class MatrixState {
    private static float[] mProjMatrix = new float[16];
    private static float[] mVMatrix = new float[16];
    private static float[] mMVPMatrix;
    public static void setCamera(
        float cx, float cy, float cz,
        float tx, float ty, float tz,
        float upx, float upy, float upz
    ){
        Matrix.setLookAtM(mVMatrix, 0, cx, cy, cz, tx, ty, tz, upx, upy, upz);
    }

    public static void setProjectOrtho(
        float left, float right,
        float bottom, float top,
        float near, float far
    ){
        Matrix.orthoM(mProjMatrix, 0, left, right, bottom, top, near, far);
    }
}
private class SceneRenderer implements GLSurfaceView.Renderer{ 

    public void onDrawFrame(GL10 gl) {
        GLES30.glClear( GLES30.GL_DEPTH_BUFFER_BIT | 
        GLES30.GL_COLOR_BUFFER_BIT); //清除深度缓冲与颜色缓冲
    }

    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES30.glViewport(0, 0, width, height); //设置视口的大小及位置
        float ratio= (float) width / height; //计算视口的宽高比   
        MatrixState.setProjectOrtho(-ratio, ratio, -1, 1, 1, 10);//设置正交投影 
        MatrixState.setCamera(0, 0, 3f, 0, 0, 0f, 0f, 1.0f, 0.0f);//设置摄像机
    }
}

 

3、透视投影

        现实世界中人眼观察物体时会有“近大远小”的效果,因此,要想开发出更加真实的场景, 仅使用正交投影是远远不够的,这时可以采用透视投影。透视投影的投影线是不平行的,他们相 交于视点。通过透视投影,可以产生现实世界中“近大远小”的效果,大部分 3D 游戏采用的都 是透视投影。

        透视投影示意图如下图所示:

        红点为摄像机位置(eyeX,eyeY,eyeZ) = (0, 0, 3)。 蓝色三角形为被观察的物体,绿色长方体为视景体,此时三角形全部在视景体内。 近平面各坐标: left=-1,right=1,top=2,bottom=-2, 近平面z坐标 = eyeZ - near=2, 远平面z坐标 = eyeZ - far = -2 。

        使用Matrix.frustumM()来设置正交投影。

  /**
     * @param m 生成的投影矩阵,float[4*4]
     * @param mOffset 填充时候起始的偏移量
     * @param left  近平面left边的x坐标
     * @param right 近平面right边的x坐标
     * @param bottom  近平面bottom边的y坐标
     * @param top   近平面top边的y坐标
     * @param near  近平面距离摄像机的距离
     * @param far   远平面距离摄像机的距离
     */
public static void frustumM(float[] m, int mOffset,
        float left, float right, float bottom, float top,
        float near, float far) {
}

透视投影的使用示例如下:

public class MatrixState {
    private static float[] mProjMatrix = new float[16];
    private static float[] mVMatrix = new float[16];
    private static float[] mMVPMatrix;
    public static void setCamera(
        float cx, float cy, float cz,
        float tx, float ty, float tz,
        float upx, float upy, float upz
    ){
        Matrix.setLookAtM(mVMatrix, 0, cx, cy, cz, tx, ty, tz, upx, upy, upz);
    }

    public static void setProjectOrtho(
        float left, float right,
        float bottom, float top,
        float near, float far
    ){
        Matrix.orthoM(mProjMatrix, 0, left, right, bottom, top, near, far);
    }

    public static void setProjectFrustum( 
        float left, float right,
        float bottom, float top,
        float near, float far 
    ){
        Matrix.frustumM(mProjMatrix, 0, left, right, bottom, top, near, far);
    }

}
private class SceneRenderer implements GLSurfaceView.Renderer{ 

    public void onDrawFrame(GL10 gl) {
        GLES30.glClear( GLES30.GL_DEPTH_BUFFER_BIT | 
        GLES30.GL_COLOR_BUFFER_BIT); //清除深度缓冲与颜色缓冲
    }

    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES30.glViewport(0, 0, width, height); //设置视口的大小及位置
        float ratio= (float) width / height; //计算视口的宽高比   
        MatrixState.setProjectFrustum(-ratio, ratio, -1, 1, 1, 10);//设置正交投影 
        MatrixState.setCamera(0, 0, 3f, 0, 0, 0f, 0f, 1.0f, 0.0f);//设置摄像机
    }
}

 

4、near、far的取值范围规定:

  • 正交投影时,摄像机可位于视景体中间,此时near < 0,far > 0,近平面位于视点后面(Z轴正方向),远平面位于视点前面(Z轴负方向)
  • 正交投影时,视景体也可位于视点后面(Z轴正方向),此时near < 0, far < 0
  • 正交投影时,far 和 near没有规定的大小关系,既可以far > near 也可以 far < near,只要物体在视景体内都可以被观察到。
  • 透视投影时,摄像机必须位于视景体前面:eyeZ>近平面Z坐标 && eyeZ > 远平面Z坐标,即:eyeZ > (eyeZ - near) && eyeZ > (eyeZ - far)。

 

最后,欢迎大家一起交流学习:微信:liaosy666 ; QQ:2209115372 。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值