[置顶] OpenGL ES总结(三)OpenGL通过计算纹理坐标来显示一张图片
2017-03-16 21:36
561 查看
转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/62444395
通过OpenGL来显示一张汽车图片,图片可以看做一个矩形,所以我们先来画一个矩形
OpenGL的基本形状是三角形,一个矩形可以看成由4个三角形构成,如果我们一个一个画,那需要12个顶点,36个坐标,效率不高,所以我们采用另外一种方式——顶点索引与glDrawElements配合使用。
什么是顶点索引呢?顶点索引就是给出顶点的下标而不给出具体的顶点坐标,如下声明:
我们的绘制区域是(-1,-1)到(1,1)的平面区域,mVertexData给出了5个顶点,mIndexData给出了4个三角形的【号位点,如打球时,有1号位,2号位】描述,如下图所示:
声明一个ShortBuffer ,用来存放顶点的索引数据
这个就是开始站好位置。
然后,使用GLES30.glDrawElements把三角形画出来
接着创建一个纹理
配置顶点shader(着色器)
vertex_shader.glsl
aTexCoord是一个二维向量,表示纹理的坐标,
varying这个变量是用来在vertex_shader和fragment_shader之间传递值用的,所以名称要相同,我们把aTexCoord赋值给vTexCoord,然后来看car_shader的配置
car_shader.glsl
在car_shader中,我们声明了一个uniform常量,类型是sampler2D,这个类型是指一个二维的纹理数据数组 ,使用texture2D来处理被插值的纹理坐标vTexCoord和纹理数据sTexture,得到的颜色值就是要显示的颜色,交给gl_FragColor
然后通过glAttachShader,link到program.
一般进程获取一个链接的着色器对象包括6个步骤
1、创建顶点着色器和片段着色器
2、将源码附加在每个着色器对象中
3、编译着色器对象
4、创建程序对象
5、将编译的着色器对象附加到程序对象中
6、链接程序对象
如果链接成功,我们就可以随时绘制。下面详细介绍执行这些进程的API
创建并编译着色器
GLuint glCreareShader(GLenum type) type :着色器类型【GL_VERTEX_SHADER,GL_FRAGMENT_SHADER】,返回对象为新着色器对象的句柄
void glDeleteShader(GLuint shader): shader 删除该着色器对象(如果一个着色器对象在删除前已经链接到程序对象中,那么当执行glDeleteShader函数时不会立即被删除,而是该着色器对象将被标记为删除,器内存被释放一次,它不再链接到其他任何程序对象)。
当我要显示一张1072*768的图示,由于它不是正方形,需要重新对其计算坐标
如图,红色就是对应的纹理坐标
于是我们有
最后在onDrawFrame中
实现效果如图:
第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。
如果你觉得好,随手点赞,也是对笔者的肯定,也可以分享此公众号给你更多的人,原创不易
通过OpenGL来显示一张汽车图片,图片可以看做一个矩形,所以我们先来画一个矩形
OpenGL的基本形状是三角形,一个矩形可以看成由4个三角形构成,如果我们一个一个画,那需要12个顶点,36个坐标,效率不高,所以我们采用另外一种方式——顶点索引与glDrawElements配合使用。
什么是顶点索引呢?顶点索引就是给出顶点的下标而不给出具体的顶点坐标,如下声明:
private final float[] mVertexData = { 0f,0f,0f, 1f,1f,0f, -1f,1f,0f, -1f,-1f,0f, 1f,-1f,0f }; private final short[] mIndexData = { 0,1,2, 0,2,3, 0,3,4, 0,4,1 };
我们的绘制区域是(-1,-1)到(1,1)的平面区域,mVertexData给出了5个顶点,mIndexData给出了4个三角形的【号位点,如打球时,有1号位,2号位】描述,如下图所示:
声明一个ShortBuffer ,用来存放顶点的索引数据
private ShortBuffer mIndexBuffer; mIndexBuffer= ByteBuffer.allocateDirect(mIndexData.length * 2) .order(ByteOrder.nativeOrder()) .asShortBuffer() .put(indexData); mIndexBuffer.position(0);
这个就是开始站好位置。
然后,使用GLES30.glDrawElements把三角形画出来
GLE30.glDrawElements(GLES30.GL_TRIANGLES,mIndexData.length,GLES30.GL_UNSIGNED_SHORT,mIndexBuffer);
接着创建一个纹理
public class CustomTexture { private static final String TAG = CustomTexture.class.getSimpleName(); public static int loadTexture(Context context, int resourceId) { final int[] textureObjectIds = new int[1]; GLES30.glGenTextures(1, textureObjectIds, 0); if (textureObjectIds[0] == 0) { Log.d(TAG, ">> create texture fail"); return 0; } BitmapFactory.Options options = new BitmapFactory.Options(); options.inScaled = false; Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options); if (bitmap == null) { Log.d(TAG, ">> load bitmap fail"); GLES30.glDeleteTextures(1, textureObjectIds, 0); return 0; } GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureObjectIds[0]); GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR_MIPMAP_LINEAR); GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR); GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, bitmap, 0); bitmap.recycle(); //与target相关联的纹理图像生成一组完整的mipmap GLES30.glGenerateMipmap(GLES30.GL_TEXTURE_2D); GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0); return textureObjectIds[0]; } }
一张图,看清纹理坐标及OpenGL坐标
配置顶点shader(着色器)
vertex_shader.glsl
attribute vec4 aPosition; attribute vec2 aTexCoord; varying vec2 vTexCoord; uniform mat4 uMatrix; void main() { vTexCoord=aTexCoord; gl_Position = uMatrix*aPosition; }
aTexCoord是一个二维向量,表示纹理的坐标,
varying这个变量是用来在vertex_shader和fragment_shader之间传递值用的,所以名称要相同,我们把aTexCoord赋值给vTexCoord,然后来看car_shader的配置
car_shader.glsl
precision mediump float; varying vec2 vTexCoord; uniform sampler2D sTexture; void main() { gl_FragColor = texture2D(sTexture,vTexCoord); }
在car_shader中,我们声明了一个uniform常量,类型是sampler2D,这个类型是指一个二维的纹理数据数组 ,使用texture2D来处理被插值的纹理坐标vTexCoord和纹理数据sTexture,得到的颜色值就是要显示的颜色,交给gl_FragColor
然后通过glAttachShader,link到program.
一般进程获取一个链接的着色器对象包括6个步骤
1、创建顶点着色器和片段着色器
2、将源码附加在每个着色器对象中
3、编译着色器对象
4、创建程序对象
5、将编译的着色器对象附加到程序对象中
6、链接程序对象
如果链接成功,我们就可以随时绘制。下面详细介绍执行这些进程的API
创建并编译着色器
GLuint glCreareShader(GLenum type) type :着色器类型【GL_VERTEX_SHADER,GL_FRAGMENT_SHADER】,返回对象为新着色器对象的句柄
void glDeleteShader(GLuint shader): shader 删除该着色器对象(如果一个着色器对象在删除前已经链接到程序对象中,那么当执行glDeleteShader函数时不会立即被删除,而是该着色器对象将被标记为删除,器内存被释放一次,它不再链接到其他任何程序对象)。
GLES30.glAttachShader(program, vertexShader); checkGlError("glAttachShader"); GLES30.glAttachShader(program, pixelShader); checkGlError("glAttachShader"); GLES30.glLinkProgram(program); int[] linkStatus = new int[1]; GLES30.glGetProgramiv(program, GLES30.GL_LINK_STATUS, linkStatus, 0); if (linkStatus[0] != GLES30.GL_TRUE) { Log.e(TAG, "Could not link program: "); Log.e(TAG, GLES30.glGetProgramInfoLog(program)); GLES30.glDeleteProgram(program); program = 0; }
当我要显示一张1072*768的图示,由于它不是正方形,需要重新对其计算坐标
如图,红色就是对应的纹理坐标
于是我们有
// 5个点,三角形显示区域 private final float[] mVertexData = { 0f, 0f, 0f, 1.0f, 0.75f, 0f, -1.0f, 0.75f, 0f, -1.0f, -0.75f, 0f, 1.0f, -0.75f, 0f }; private final short[] mIndexData = { 0, 1, 2, // 0号点,1号点,2号点组成一个三角形 0, 2, 3, // 0号点,2号点,3号点组成一个三角形 0, 3, 4, // 0号点,3号点,4号点组成一个三角形 0, 4, 1 // 0号点, 4号点,1号点组成一个三角形 }; //纹理坐标 private final float[] mTextureVertexData = { 0.5f,0.375f, 1f,0f, 0f,0f, 0f,0.75f, 1f,0.75f };
最后在onDrawFrame中
public void onDrawFrame(GL10 gl) { GLES30.glClear(GLES30.GL_DEPTH_BUFFER_BIT | GLES30.GL_COLOR_BUFFER_BIT); GLES30.glUseProgram(mProgramId); GLES30.glUniformMatrix4fv(mMatrix, 1, false, projectionMatrix, 0); GLES30.glEnableVertexAttribArray(mPosition); GLES30.glVertexAttribPointer(mPosition, 3, GLES30.GL_FLOAT, false, 12, mVertexBuffer); GLES30.glEnableVertexAttribArray(aTextureCoordHandle); GLES30.glVertexAttribPointer(aTextureCoordHandle, 2, GLES30.GL_FLOAT, false, 8, mTextureVertexBuffer); GLES30.glActiveTexture(GLES30.GL_TEXTURE0); GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureId); GLES30.glUniform1i(uTextureSamplerHandle, 0); GLES30.glDrawElements(GLES30.GL_TRIANGLES, mIndexData.length, GLES30.GL_UNSIGNED_SHORT, mIndexBuffer); }
实现效果如图:
第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。
如果你觉得好,随手点赞,也是对笔者的肯定,也可以分享此公众号给你更多的人,原创不易
相关文章推荐
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——1.4 用OpenGL ES 2.0显示一张图片(下)
- [置顶] OpenGL ES总结(二)OpenGL坐标变换之平移及旋转
- [OpenGL]从零开始写一个Android平台下的全景视频播放器——1.3 用OpenGL ES 2.0显示一张图片(上)
- OpenCV之旅(2):pencvqt opencv显示一张图片 测试 总结
- Qt中通过控件在Label标签中显示一张静态图片
- Python服务端,通过TCP发送一张图片给Android客户端,客户端把图片显示出来
- [置顶] OpenGL ES总结(四)OpenGL 渲染视频画面
- OpenGL自动计算纹理坐标( By 董士崇 jerrydong@tom.com)
- 【C#/OpenGL】CSGL中2D纹理加载PNG等透明图片显示的黑边问题
- 文件数据通过qt将二维数组中的像素点显示成一张图片
- [置顶] 【微信平台】艺萌管家APP技术总结(三)——上传和显示图片
- OpenGL自动计算纹理坐标( By 董士崇 jerrydong@tom.com)
- (转)使用OpenGL显示图像(七)Android OpenGLES2.0——纹理贴图之显示图片
- opengl离屏渲染(不需要和窗口绑定,仅当作一个可以渲染一张图片的API使用)+ opencv显示
- opengl离屏渲染(不需要和窗口绑定,仅当作一个可以渲染一张图片的API使用)+ opencv显示
- matlab 显示一张图片到三维坐标
- 通过qt将二维数组中的像素点显示成一张图片
- [置顶] OpenGL ES总结(一)OpenGL 初识
- 总结:SDL_第一课 在屏幕上显示一张图片
- 通过异步任务将一张由网络得来图片显示出来