opengles(三) 相机和投影概念

来源:互联网 发布:部落冲突更新软件 编辑:程序博客网 时间:2024/06/02 05:21

透视投影和相机就是允许像你用眼睛看物体的方式绘制图像对象

由于转变调整坐标绘制的对象是基于他们在GLSurfaceView上显示的宽和高。没有这样的计算,被OpenGL ES 绘制的对象在不同分辨率的显示器上会是歪的,就像我们之前画的三角型一样。所以我们必须要把opengles坐标映射在手机屏幕上;

透视投影需要设置近平面的左、右、下、上的最大值和近平面、远平面的距离
这里写图片描述

具体做法就是把相关的矩阵与原来的三角型坐标向量进行相乘得到最终的向量坐标;

先定义透视投影(mProjectionMatrix)和相机(mViewMatrix)的矩阵数组:

    private final float[] mMVPMatrix = new float[16];    private final float[] mProjectionMatrix = new float[16];    private final float[] mViewMatrix = new float[16];

再设置透视投影矩阵的值,这里要用到Matrix这个类的frustumM方法:

@Override    public void onSurfaceChanged(GL10 gl, int width, int height) {        GLES20.glViewport(0, 0, width, height);        // 计算长和宽的比例,由于在OpenGLes坐标系里最大是1,具体的算法是:        // x / width = 1 / height;        // 所以 x = width /height;        float ratio = (float) width / height;,        Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);    }

在onDrawFrame中设置相机矩阵,同样用的是Matrix,最后把相乘后的矩阵传入:

@Override    public void onDrawFrame(GL10 gl) {        // 设置相机矩阵        Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0, 0, 0, 0, 1.0f, 0);        // 透视投影矩阵与相机矩阵相乘,得到最后的矩阵mMVPMatrix        Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);        mTriangle.draw(mMVPMatrix);    }

在vertex shader的source里添加矩阵与位置向量相乘的代码:

private static final String VERTEX_SHADER_SOURCE = "attribute vec4 vPosition;" +            "uniform mat4 uMVPMatrix;" +            "void main() {" +            "   gl_Position = uMVPMatrix * vPosition;" +            "}";private static final String MATRIX_NAME = "uMVPMatrix";private int mPositionLocation, mFragColorLocation, mMatrixLocation;mMatrixLocation = GLES20.glGetUniformLocation(program, MATRIX_NAME);public void draw(float[] mvpMatrix) {        GLES20.glUniformMatrix4fv(mMatrixLocation, 1, false, mvpMatrix,     }

贴上全部的代码

public class MyRenderer implements GLSurfaceView.Renderer {    private final float[] mMVPMatrix = new float[16];    private final float[] mProjectionMatrix = new float[16];    private final float[] mViewMatrix = new float[16];    private Triangle mTriangle;    @Override    public void onSurfaceCreated(GL10 gl, EGLConfig config) {        GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);        mTriangle = new Triangle();    }    @Override    public void onSurfaceChanged(GL10 gl, int width, int height) {        GLES20.glViewport(0, 0, width, height);        float ratio = (float) width / height;        Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);    }    @Override    public void onDrawFrame(GL10 gl) {        Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0, 0, 0, 0, 1.0f, 0);        Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);        mTriangle.draw(mMVPMatrix);    }}
public class Triangle {    private static final String TAG = "Triangle";    // 三角形的三个顶点    private static final float[] TRIANGLE_VERTEX_COORD = {0, 0.5f,            -0.5f, -0.5f,            0.5f, -0.5f};    private static final int VERTEX_SIZE = 3;    private static final int COORDS_PER_VERTEX = TRIANGLE_VERTEX_COORD.length / VERTEX_SIZE;    private FloatBuffer mTriangleCoordBuffer;    private static final String VERTEX_SHADER_SOURCE = "attribute vec4 vPosition;" +            "uniform mat4 uMVPMatrix;" +            "void main() {" +            "   gl_Position = uMVPMatrix * vPosition;" +            "}";    private static final String FRAGMENT_SHADER_SOURCE = "uniform vec4 vColor;" +            "void main() {" +            "   gl_FragColor = vColor;" +            "}";    private int mVertexShader, mFragmentShader;    private static final String POSITION_NAME = "vPosition";    private static final String COLOR_NAME = "vColor";    private static final String MATRIX_NAME = "uMVPMatrix";    private int mPositionLocation, mFragColorLocation, mMatrixLocation;    public Triangle() {        // 数组转化为buffer,提高opengles性能        mTriangleCoordBuffer = ByteBuffer.allocateDirect(TRIANGLE_VERTEX_COORD.length * 4)                .order(ByteOrder.nativeOrder()).asFloatBuffer();        mTriangleCoordBuffer.put(TRIANGLE_VERTEX_COORD);        // 设置从第一位开始读        mTriangleCoordBuffer.position(0);        // 得到编译后的shader        mVertexShader = getShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER_SOURCE);        mFragmentShader = getShader(GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE);        // 创建并连接program        int program = GLES20.glCreateProgram();        GLES20.glAttachShader(program, mVertexShader);        GLES20.glAttachShader(program, mFragmentShader);        GLES20.glLinkProgram(program);        GLES20.glUseProgram(program);        // 找到对应变量的index        mPositionLocation = GLES20.glGetAttribLocation(program, POSITION_NAME);        mFragColorLocation = GLES20.glGetUniformLocation(program, COLOR_NAME);        mMatrixLocation = GLES20.glGetUniformLocation(program, MATRIX_NAME);    }    private int getShader(int type, String source) {        int shader = GLES20.glCreateShader(type);        GLES20.glShaderSource(shader, source);        GLES20.glCompileShader(shader);        // 获取编译的状态        final int[] compileStatus = new int[1];        GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS,                compileStatus, 0);        Log.v(TAG, "代码编译结果:" + "\n" + source                    + "\n:" + GLES20.glGetShaderInfoLog(shader));        if (compileStatus[0] == 0) {            Log.w(TAG, "编译失败!.");            return 0;        }        return shader;    }    public void draw(float[] mvpMatrix) {        // 由于性能方面的考虑,opengles默认读取不到缓冲区里的数据,需要先enable后再读        GLES20.glEnableVertexAttribArray(mPositionLocation);        GLES20.glVertexAttribPointer(mPositionLocation, COORDS_PER_VERTEX,                GLES20.GL_FLOAT, false, 0, mTriangleCoordBuffer);        GLES20.glUniformMatrix4fv(mMatrixLocation, 1, false, mvpMatrix, 0);        GLES20.glUniform4f(mFragColorLocation, 0, 0.5f, 0, 1.0f);        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, VERTEX_SIZE);        GLES20.glDisableVertexAttribArray(mPositionLocation);    }}

最后的运行结果是:
这里写图片描述

原创粉丝点击