[OpenGL]从零开始写一个Android平台下的全景视频播放器——1.3 用OpenGL ES 2.0显示一张图片(上)
来源:互联网 发布:我国茶叶出口数据2015 编辑:程序博客网 时间:2024/06/07 23:53
Github项目地址,欢迎star~!
为了方便没有准备好梯子的同学,我把项目在CSDN上打包下载,不过更新会慢一些
回到目录
本节示例代码下载地址
解决变形问题
要解决变形,我们需要引入Projection Matrix(投影矩阵)的概念,在OpenGL中,投影矩阵用来改变场景在屏幕上的显示方式(近大远小,平行投影等等)。
因为我们绘制的是二维平面,所以问题还是比较好解决的,假如我们的屏幕是16:9的(横屏情况),那么只要让OpenGL的绘制范围也是16:9的就好了,如下图所示:
可以看到,我们把OpenGL的绘制区域横向拉长了,拉长的比例就是(16/9 约1.777)
更多关于透视和投影变换可以参考这篇博文
那么代码要如何实现呢?答案是矩阵(线性代数没上90的哭晕在厕所。。),需要进行的操作是正交投影,好在我们并不需要去推导正交矩阵如何求出来(其实这个算简单的,有兴趣的可以自己查找相关资料),Android 提供的Matrix类中包含这个方法。
我们先声明一个长度16的float数组,这是Matrix的标准尺寸
private final float[] projectionMatrix=new float[16];
注意,在OpenGL中,数组是row-major的,如下所示:
/** * Matrix math utilities. These methods operate on OpenGL ES format * matrices and vectors stored in float arrays. * <p> * Matrices are 4 x 4 column-vector matrices stored in column-major * order: * <pre> * m[offset + 0] m[offset + 4] m[offset + 8] m[offset + 12] * m[offset + 1] m[offset + 5] m[offset + 9] m[offset + 13] * m[offset + 2] m[offset + 6] m[offset + 10] m[offset + 14] * m[offset + 3] m[offset + 7] m[offset + 11] m[offset + 15]</pre> */
创建了projectionMatrix以后,我们还需要更新glsl中顶点着色器的代码,以便把这个变换用的矩阵传递过去,如下所示:
attribute vec4 aPosition;uniform mat4 uMatrix;void main() { gl_Position = uMatrix*aPosition;}
uniform 是GLSL中的常量类型,之前的attribute类型是用来在Java代码和顶点着色器(Vertex Shader)传递变量用的,uniform则是给顶点着色器(Vertex Shader)和片元着色器(Fragment Shader)传递常量用的。我们把uMatrix和aPosition做矩阵乘法,就得到了一个新的顶点位置。
类似的,我们也需要一个入口,以便给这个矩阵传递数据
uMatrixHandle=GLES20.glGetUniformLocation(programId,"uMatrix");
目前类中的全局变量如下所示
private Context context; private int aPositionHandle; private int programId; private FloatBuffer vertexBuffer; private final float[] vertexData = { 0f,0f,0f, 1f,-1f,0f, 1f,1f,0f }; private final float[] projectionMatrix=new float[16]; private int uMatrixHandle;
完成正交投影
@Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) { float ratio=width>height? (float)width/height: (float)height/width; if (width>height){ Matrix.orthoM(projectionMatrix,0,-ratio,ratio,-1f,1f,-1f,1f); }else Matrix.orthoM(projectionMatrix,0,-1f,1f,-ratio,ratio,-1f,1f);}
在onSurfaceChanged中,我们获取了屏幕的宽和高,所以我们在这里计算缩放的比例,需要注意的是横屏和竖屏的时候是刚好相反的处理(一个改变x,一个改变y)
public static void orthoM(float[] m, int mOffset, float left, float right, float bottom, float top, float near, float far)
参数的含义:左右(x)下上(y)近远(z)
更新onDrawFrame
@Overridepublic void onDrawFrame(GL10 gl) { GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT); GLES20.glUseProgram(programId); GLES20.glUniformMatrix4fv(uMatrixHandle,1,false,projectionMatrix,0); GLES20.glEnableVertexAttribArray(aPositionHandle); GLES20.glVertexAttribPointer(aPositionHandle, 3, GLES20.GL_FLOAT, false, 12, vertexBuffer); GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);}
看一下效果吧:
如果是竖屏的情况,那么应该是这样子的:
下面我们来显示一张图片,图片可以看做一个矩形,所以我们先来画一个矩形(别急别急,后面会讲得越来越快( ⊙ o ⊙ ))
之前提到OpenGL的基本形状是三角形,一个矩形可以看成由4个三角形构成,如果我们一个一个画,那需要12个顶点,36个坐标,效率不高,所以我们采用另外一种方式——顶点索引与glDrawElements配合使用。
什么是顶点索引呢?顶点索引就是给出顶点的下标而不给出具体的顶点坐标,看代码:
private final float[] vertexData = { 0f,0f,0f, 1f,1f,0f, -1f,1f,0f, -1f,-1f,0f, 1f,-1f,0f};private final short[] indexData = { 0,1,2, 0,2,3, 0,3,4, 0,4,1};
我们的绘制区域是(-1,-1)到(1,1)的平面区域,vertexData给出了5个顶点,indexData给出了4个三角形的描述,如下图所示:
声明一个ShortBuffer ,用来存放顶点的索引数据
private ShortBuffer indexBuffer;
indexBuffer = ByteBuffer.allocateDirect(indexData.length * 2) .order(ByteOrder.nativeOrder()) .asShortBuffer() .put(indexData);indexBuffer.position(0);
这个和前面存放顶点数据的类似,就不解释了
然后,使用GLES20.glDrawElements把三角形画出来,注意如果我们之前的数组类型是byte,那么就应该使用GLES20.GL_UNSIGNED_BYTE,总之类型要对齐
GLES20.glDrawElements(GLES20.GL_TRIANGLES,indexData.length,GLES20.GL_UNSIGNED_SHORT,indexBuffer);
看一下运行效果:
下一节我们来学习如何把矩形变成一张图片
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——1.3 用OpenGL ES 2.0显示一张图片(上)
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——1.4 用OpenGL ES 2.0显示一张图片(下)
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——1.1 OpenGL ES 2.0基础知识
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——1.2 用OpenGL ES 2.0画一个三角形
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——3.2 使用OpenGL ES 2.0绘制一个球
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——目录
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——目录
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——5.7 使用OpenGL ES接口保存屏幕截图
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——2.1 使用GLSurfaceView和MediaPlayer播放一个平面视频(上)
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——2.1 使用GLSurfaceView和MediaPlayer播放一个平面视频(上)
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——5.6 播放器的UI制作
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——5.8 使用MediaPlayer播放在线视频
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——5.1 使用OpenGL把全景视频贴到球上
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——2.3 使用GLSurfaceView和MediaPlayer播放一个平面视频(下)
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——2.3 使用GLSurfaceView和MediaPlayer播放一个平面视频(下)
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——2.2 使用GLSurfaceView和MediaPlayer播放一个平面视频(中)
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——2.2 使用GLSurfaceView和MediaPlayer播放一个平面视频(中)
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——5.3 如何实现分屏效果
- linux AWK命令的一点使用见解
- 条件注释判断浏览器<!--[if !IE]><!--[if IE]><!--[if lt IE 6]><!--[if gte IE 6]>
- Could not resolve archetype org.apache.maven.archetypes:maven-archetype-quickstart
- Java中的“析构函数”——finalize() 对象消亡时调用
- ORACLE报错
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——1.3 用OpenGL ES 2.0显示一张图片(上)
- 解决.m3u8格式视频文件在chrome等浏览器中不能播放的问题
- 开始学习《利用python进行数据分析》
- 【poj 1006】Biorhythms 中国剩余定理
- JZOJ4884. 图的半径
- 广东工业大学第一次月赛的一道水题
- 代理
- hdu 1.3.3/hed 1084
- 文章标题 POJ 3253 : Fence Repair(哈夫曼)