本文参照:http://hukai.me/android-training-course-in-chinese/graphics/opengl/projection.html
投影(Projection):投影会基于显示出来的GLSurfaceView的长和宽,来调整绘图对象的坐标。如果没有投影计算,那么用OpenGL ES绘制的对象会由于其长宽比例和View窗口比例的不一致而发生形变。
发生时间:一般仅当OpenGL View的比例在渲染器的onSurfaceChanged()方法中建立或发生变化时才会被计算
相机视角(Camera View):基于一个虚拟相机位置改变绘图对象的坐标。事实上,OpenGL ES并没有定义一个实际的相机对象,而是提供一些方法,通过绘图对象的变换来模拟相机视角。
发生时间:一个相机视角可以仅在建立GLSurfaceView时计算一次,也可以进行动态调整。
关于openGL矩阵的一些函数讲解可参照:
http://blog.sina.com.cn/s/blog_a23d30f101018gl4.html
openGL坐标系如图
:
这份代码解决了上篇文章中画出来的三角形变形的问题,修改如下:
在MyGL20Renderer类中添加
// 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];
并修改onDrawFrame和onSurfaceChanged方法:
public void onDrawFrame(GL10 unused) {
// 重绘背景色
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
// 设置相机的位置。参数:要填充的矩阵;偏移;相机的x,y,z坐标;目标的x,y,z坐标;视觉向量x,y,z
//关于这个函数的更详细讲解可参照http://blog.csdn.net/a7178077/article/details/38014373
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// 参数说明:mMVPMatrix为mProjectionMatrix和mViewMatrix相乘得到,其他三个0均为偏移
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
//绘制三角形
triangle.draw(mMVPMatrix);
//绘制矩形
// square.draw();
}
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
// 这个投影矩阵是在onDrawFrame()方法中应用于目标对象坐标的
//Matrix.frustumM:凸透镜眼睛
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
}
然后修改Util类中原本的VertexShaderCode这个变量的值:
private final String vertexShaderCode =
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
"}";
修改第一个draw方法:
/**
* @param coords_per_vertex 每个顶点的坐标数
* @param vertexBuffer 浮点缓冲区
* @param color 颜色数组,数组的四个数分别为图形的RGB值和透明度
*/
public void draw(int coords_per_vertex, FloatBuffer vertexBuffer, float color[],float mvpMatrix[]) {
//获取程式
int program = getProgram();
//得到处理到顶点着色器的vPosition成员
int vPositionHandler = GLES20.glGetAttribLocation(program, "vPosition");
// 启用一个指向图形的顶点数组的handle
GLES20.glEnableVertexAttribArray(vPositionHandler);
// 准备坐标数据
GLES20.glVertexAttribPointer(vPositionHandler, coords_per_vertex,
GLES20.GL_FLOAT, false,
LENGTH * coords_per_vertex, vertexBuffer);
// 得到处理到片段着色器的vPosition成员
int mColorHandle = GLES20.glGetUniformLocation(program, "vColor");
// 设置颜色
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
// get handle to shape's transformation matrix
int MVPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
// Pass the projection and view transformation to the shader
GLES20.glUniformMatrix4fv(MVPMatrixHandle, 1, false, mvpMatrix, 0);
// 绘制三角形比较简单,这里采用glDrawArrays方法(默认是逆时针方向)
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
// 禁用指向图形的顶点数组
GLES20.glDisableVertexAttribArray(MVPMatrixHandle);
}
修改Triangle类中的draw方法:
public void draw(float matrix[]){
new Util().draw(COORDS_PER_VERTEX,vertexBuffer,color,matrix);
}
正方形的代码与此类似,只要稍微修改Util类中的第二个draw方法即可。
// Pass the projection and view transformation to the shader
GLES20.glUniformMatrix4fv(MVPMatrixHandle, 1, false, mvpMatrix, 0);
// 绘制图形
GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
并在方法参数末尾添加float mvpMatrix[]就行