欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android OpenGL ES 入门系列(五) --- 应用投影和相机视角

程序员文章站 2023-12-31 16:58:04
...

转载请注明出处

本文出自Hansion的博客



本章介绍如何创建投影和相机视图,并应用于GLSurfaceView中绘制的形状上。


在OpenGL ES环境中,利用投影和相机视角可以让绘制对象的显示更接近人眼看到的样子,这是一种视角模拟,它是通过对绘制对象坐标进行数学变换实现的。

投影(Projection):基于GLSurfaceView 的宽和高来调整绘制对象的坐标。如果没有该计算,绘制对象和GLSurfaceView的宽高比例不同,就会发生变形。投影转换通常只在OpenGL View的比例刚被建立或改变onSurfaceChanged()中计算

相机视角(Camera View):基于虚拟相机的位置调整绘制对象的坐标。而实际上OpenGL ES并没有定义相机对象,它是提供了一些方法通过转换绘制对象的显示来模拟相机视角。


定义一个投影

投影变换的数据是在 GLSurfaceView.Renderer 类的 onSurfaceChanged() 方法中计算出来的。
以下代码首先获取到GLSurfaceView的宽高,并使用Matrix.frustumM()方法填充一个投影变换矩阵


public class MyGLRenderer implements GLSurfaceView.Renderer {

    ...

    // mMVPMatrix is an abbreviation for "Model View Projection Matrix"
    private final float[] mMVPMatrix = new float[16];
    private final float[] mProjectionMatrix = new float[16];
    private final float[] mViewMatrix = new float[16];

    ...

    @Override
    public void onSurfaceChanged(GL10 gl10, int width, int height) {
        //glViewport用于告诉OpenGL应把渲染之后的图形绘制在窗体的哪个部位、大小
        GLES20.glViewport(0, 0, width, height);
        //计算宽高比
        float ratio = (float) width / height;
        //填充投影矩阵 mProjectionMatrix
        Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
    }
    ...
}


    对绘制对象仅使用投影变换,往往会导致看不到显示的东西,所以还需进行相机视角转换使绘制对象显示在屏幕上。



定义一个相机视角

下面的代码在 onDrawFrame()方法中使用 Matrix.setLookAtM() 方法计算相机视角变换,再与之前计算的投影矩阵结合起来,然后将组合后的变换矩阵传递给绘制对象:



    @Override
    public void onDrawFrame(GL10 gl10) {
        // glClear表示清除缓冲  传入GL_COLOR_BUFFER_BIT指要清除颜色缓冲
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        // 设置相机视角
        Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
        // 计算投影和视图变换
        Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
        // 绘制形状
        mTriangle.draw(mMVPMatrix);
    }


应用投影和相机视角转换


我们在Triangle中之前定义的顶点着色器vertexShaderCode中增加一个变量uMVPMatrix
然后修改draw方法,使其能接收组合后的变换矩阵,并应用于绘制对象上:


public class Triangle {

    //顶点着色器
    private final String vertexShaderCode =
            "uniform mat4 uMVPMatrix;" +
                    "attribute vec4 vPosition;" +
                    "void main() {" +
                    "  gl_Position = uMVPMatrix * vPosition;" +
                    "}";
    // 用于访问和设置视图转换

    private int mMVPMatrixHandle;
   
    ...

    public void draw(float[] mvpMatrix) {

        ...

        // 获取片元着色器的vColor成员
        mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
        // 得到绘制对象的变换矩阵句柄
        mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
        // 将投影和视图转换传递给着色器
        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
        // 设置绘制颜色
        GLES20.glUniform4fv(mColorHandle, 1, color, 0);
        // 绘制形状
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
        // 禁用顶点属性数组
        GLES20.glDisableVertexAttribArray(mPositionHandle);
    }
}



运行结果



Android OpenGL ES 入门系列(五) --- 应用投影和相机视角


此时就是按着正确的比例显示图形了。



参考:

OpenGL ES 2.0官方实例教程







上一篇:

下一篇: