转:http://blog.csdn.net/junzia/article/details/52842816

前面几篇博客,我们将了Android中利用OpenGL ES 2.0绘制各种形体,并在上一篇博客中专门讲了GLSL语言。但是我们看到的基于OpenGL开发的应用和游戏,可不仅仅是那些规则形体和一些简单的色彩构成,而是各种不规则的形体构成了现实世界或者卡通世界的人和事物,他们都是外面穿着漂亮“衣服”的。本篇博客就是来讲解这些“衣服”的基础的。这些衣服就是纹理贴图。

什么是纹理贴图

一般说来,纹理是表示物体表面的一幅或几幅二维图形,也称纹理贴图(texture)。当把纹理按照特定的方式映射到物体表面上的时候,能使物体看上去更加真实。当前流行的图形系统中,纹理绘制已经成为一种必不可少的渲染方法。在理解纹理映射时,可以将纹理看做应用在物体表面的像素颜色。在真实世界中,纹理表示一个对象的颜色、图案以及触觉特征。纹理只表示对象表面的彩色图案,它不能改变对象的几何形式。更进一步的说,它只是一种高强度的计算行为。——百度百科

比如我们在利用OpenGL做游戏的时候,加载了一个人物模型进来了,这个人物模型上是没有色彩的。我们需要给它绘上需要的色彩才行。但是这些色彩从哪里来呢?我们不可能像之前处理球体那样,根据顶点取生成需要的色彩,那样对于我们给这个人物模型绘色的工作量实在太大了。这个时候我们就需要用到纹理贴图的技术了——把一个纹理(对于2D贴图,可以简单的理解为图片),按照所期望的方式显示在诸多三角形组成的物体的表面。

纹理映射原理

启用纹理映射后,如果想把一幅纹理映射到相应的几何图元,就必须告诉GPU如何进行纹理映射,也就是为图元的顶点指定恰当的纹理坐标。纹理坐标用浮点数来表示,范围一般从0.0到1.0,左上角坐标为(0.0,0.0),右上角坐标为(1.0,0.0),左下角坐标为(0.0,1.0),右下角坐标为(1.0,1.0),如下图所示:

左图为纹理图和纹理坐标,右图为顶点图和顶点坐标。

将纹理映射到右边的两个三角形上(也就是一个矩形),需要将纹理坐标指定到正确的顶点上,才能使纹理正确的显示,否则显示出来的纹理会无法显示,或者出现旋转、翻转、错位等情况。

将右图顶点按照V2V1V4V3传入,以三角形条带方式绘制,则纹理坐标应按照V2V1V4V3传入。如果按照V3V4V1V2传入,会得到一个旋转了180度的纹理。如果按照V4V3V2V1传入,则会得到一个左右翻转的纹理。

显示图片

根据纹理映射原理,结合之前绘制正方形的经验,我们可以根据以下步骤利用OpenGL ES显示一张图片:

第一步,修改着色器

首先,我们需要修改我们的着色器,将顶点着色器修改为:

attribute vec4 vPosition;

attribute vec2 vCoordinate;

uniform mat4 vMatrix; varying vec2 aCoordinate; void main(){ gl_Position=vMatrix*vPosition; aCoordinate=vCoordinate; }

可以看到,顶点着色器中增加了一个vec2变量,并将这个变量传递给了片元着色器,这个变量就是纹理坐标。接着我们修改片元着色器为:

precision mediump float;

uniform sampler2D vTexture; varying vec2 aCoordinate; void main(){ gl_FragColor=texture2D(vTexture,aCoordinate); }

片元着色器中,增加了一个sampler2D的变量,sampler2D我们在前一篇博客GLSL语言基础中提到过,是GLSL的变量类型之一的取样器。texture2D也有提到,它是GLSL的内置函数,用于2D纹理取样,根据纹理取样器和纹理坐标,可以得到当前纹理取样得到的像素颜色。

第二步,设置顶点坐标和纹理坐标

根据纹理映射原理中的介绍,我们将顶点坐标设置为:

private final float[] sPos={

-1.0f,1.0f, //左上角 -1.0f,-1.0f, //左下角 1.0f,1.0f, //右上角 1.0f,-1.0f //右下角 };

相应的,对照顶点坐标,我们可以设置纹理坐标为:

private final float[] sCoord={

0.0f,0.0f, 0.0f,1.0f, 1.0f,0.0f, 1.0f,1.0f, };

第三步,计算变换矩阵

按照上步设置顶点坐标和纹理坐标,大多数情况下我们得到的一定是一张拉升或者压缩的图片。为了让图片完整的显示,且不被拉伸和压缩,我们需要向绘制等腰直角三角形一样,计算一个合适的变换矩阵,传入顶点着色器,代码如下:

@Override

public void onSurfaceChanged(GL10 gl, int width, int height) { GLES20.glViewport(0,0,width,height); int w=mBitmap.getWidth(); int h=mBitmap.getHeight(); float sWH=w/(float)h; float sWidthHeight=width/(float)height; if(width>height){ if(sWH>sWidthHeight){ Matrix.orthoM(mProjectMatrix, 0, -sWidthHeight*sWH,sWidthHeight*sWH, -1,1, 3, 7); }else{ Matrix.orthoM(mProjectMatrix, 0, -sWidthHeight/sWH,sWidthHeight/sWH, -1,1, 3, 7); } }else{ if(sWH>sWidthHeight){ Matrix.orthoM(mProjectMatrix, 0, -1, 1, -1/sWidthHeight*sWH, 1/sWidthHeight*sWH,3, 7); }else{ Matrix.orthoM(mProjectMatrix, 0, -1, 1, -sWH/sWidthHeight, sWH/sWidthHeight,3, 7); } } //设置相机位置 Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 7.0f, 0f, 0f, 0f, 0f, 1.0f, 0.0f); //计算变换矩阵 Matrix.multiplyMM(mMVPMatrix,0,mProjectMatrix,0,mViewMatrix,0); }

mMVPMatrix即为我们所需要的变换矩阵。

第四步,显示图片

然后我们需要做的,就和之前绘制正方形一样容易了。和之前不同的是,在绘制之前,我们还需要将纹理和纹理坐标传入着色器:

@Override

public void onDrawFrame(GL10 gl) {

GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT|GLES20.GL_DEPTH_BUFFER_BIT);

GLES20.glUseProgram(mProgram);

onDrawSet();

GLES20.glUniformMatrix4fv(glHMatrix,1,false,mMVPMatrix,0); GLES20.glEnableVertexAttribArray(glHPosition); GLES20.glEnableVertexAttribArray(glHCoordinate); GLES20.glUniform1i(glHTexture, 0); textureId=createTexture(); //传入顶点坐标 GLES20.glVertexAttribPointer(glHPosition,2,GLES20.GL_FLOAT,false,0,bPos); //传入纹理坐标 GLES20.glVertexAttribPointer(glHCoordinate,2,GLES20.GL_FLOAT,false,0,bCoord); GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP,0,4); } public abstract void onDrawSet(); public abstract void onDrawCreatedSet(int mProgram); private int createTexture(){ int[] texture=new int[1]; if(mBitmap!=null&&!mBitmap.isRecycled()){ //生成纹理 GLES20.glGenTextures(1,texture,0); //生成纹理 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,texture[0]); //设置缩小过滤为使用纹理中坐标最接近的一个像素的颜色作为需要绘制的像素颜色 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,GLES20.GL_NEAREST); //设置放大过滤为使用纹理中坐标最接近的若干个颜色,通过加权平均算法得到需要绘制的像素颜色 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR); //设置环绕方向S,截取纹理坐标到[1/2n,1-1/2n]。将导致永远不会与border融合 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE); //设置环绕方向T,截取纹理坐标到[1/2n,1-1/2n]。将导致永远不会与border融合 GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE); //根据以上指定的参数,生成一个2D纹理 GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, mBitmap, 0); return texture[0]; } return 0; }

这样我们就可以显示出我们需要显示的图片,并且保证它完整的居中显示而且不会变形了,如下图:

源码

opengl生成图片php,(转)使用OpenGL显示图像(七)Android OpenGLES2.0——纹理贴图之显示图片...相关推荐

  1. Android OpenGLES2.0(九)——利用OpenGL进行图片处理

    在之前的博客中我们就有提过OpenGLES的常见应用范围,其中有一个就是图片的处理.为了保证效率,Android手机中许多美颜相机.图片处理应用,都用到了OpenGLES来处理图片.上一篇博客中,我们 ...

  2. OpenGL蓝宝书源码学习(二十三)第七章——MultiTexture多重纹理

    在上一节CubeMap的基础上新增了一个纹理贴图实现多重纹理. // MultiTexture.cpp // OpenGL SuperBible // Demonstrates applying a ...

  3. 【OpenGL】十二、OpenGL 绘制线段 ( 绘制单条线段 | 绘制多条线段 | 依次连接的点组成的线 | 绘制圈 | 绘制彩色的线 )

    文章目录 一.设置线宽度 二.绘制单条线段 GL_LINES 三.绘制多条线段 GL_LINES 四.绘制依次连接的点组成的线 GL_LINE_STRIP 五.绘制圈 GL_LINE_LOOP ( 偶 ...

  4. 现代opengl 设计入门,纹理贴图

    上节 现代opengl 设计入门,着色器  介绍了着色器语言GLSL, 可以绘制多彩的三角形.这节介绍更高级的着色,纹理贴图. 先做纹理贴图的基本介绍,然后介绍其中几个重要设置:纹理环绕方式,纹理过滤 ...

  5. java opengl书_GitHub - cy-cyx/OpenGlDome: OpenGl的使用练习(安卓 Java opengl3.0)

    项目中现有的功能模块 1.fbo文件下 使用帧缓冲区,使用一个纹理作为帧缓冲的颜色缓冲区 注意:安卓的纹理的原点是在左上角,fbo的纹理的原点是在左下角 2.blend文件下 混合模式的使用 3.li ...

  6. C++ Opengl纹理贴图源码

    C++ Opengl纹理贴图源码 项目开发环境 项目功能 项目演示 项目源码传送门 项目开发环境 开发语言:C++和IDE:VS2017,操作系统Windows版本windows SDK8.1,三方库 ...

  7. C#中使用OpenGL(API)创建OpenGL渲染环境

    在C#中调用1.1版本的OpenGL函数,但是光有OpenGL函数还不能绘制图形,就像一个画家,他即使拥有绘画的技巧,还有画笔和颜料,如果没有画布,他也没有地方画画.有了画布,画家还需要画板把画布支起 ...

  8. 纹理窗口Qt+OpenGL之纹理贴图

    上班之余抽点时间出来写写博文,希望对新接触的朋友有帮助.今天在这里和大家一起学习一下纹理窗口 NeNe的代码中是加载到了一个正方体当中,代码很长.其实单纯的想要纹理贴图是很便利的.具体的纹理贴图技巧在 ...

  9. OpenGL学习(一)OpenGL基本介绍

    1. OpenGL基本介绍 1.1 OpenGL是什么?   当你第一次听到OpenGL时,你可能并不知道它到底是什么,但你应该知道它是与图形联系起来,这确实是OpenGL能够做的事情.OpenGL不 ...

最新文章

  1. 检测你处于程序员的哪个层级
  2. SAPScript和Smartform双面打印
  3. 【部署】Nginx长连接配置
  4. CCF CSP 201403-1 相反数(C++)
  5. linux emmc vfs错误,Hi3519a EMMC挂载EXT4文件系统失败
  6. OpenShift 4 之获取OpenShif的最新开发进度
  7. java 解析数据包_java - 如何在Java中正确解析TCP数据包? - 堆栈内存溢出
  8. 给92号油的汽车加95,为何老司机还说省钱?
  9. python做接口测试的优点_python做接口测试的必要性
  10. 周志华机器学习西瓜书速记第二章绪论模型评估与选择(一)
  11. 入侵无盘系统服务器,比有盘还快!梅捷带你体验锐起无盘系统
  12. 问卷调查试卷的数据设计
  13. vs2013配置CUDA .cu文件
  14. 取消Excel里面全部超级链接
  15. 计算机组成原理推荐书籍
  16. 如何给JButton添加图标,并使图标沾满整个按钮。
  17. 【今日CV 计算机视觉论文速览 第128期】Mon, 10 Jun 2019
  18. 先图科技的AGI模盒发布了!
  19. 《女侦探司马楠之箱尸谜案》横店开机 花潼冯荔军热血联手破奇案
  20. 微信登陆信息不回调WXEntryActivity-onResp()

热门文章

  1. 山东菏泽家乡网页代码 html静态网页设计制作 dw静态网页成品模板素材网页 web前端网页设计与制作 div静态网页设计
  2. Asan快速定位内存越界、内存泄漏
  3. 香帅的北大金融学课 01 金融世界观
  4. html在线聊天界面模板,一款带气泡对话框的HTML5聊天应用界面模板
  5. 点星PBX(DotAsterisk)外线呼入到离线坐席(sip分机未注册)时,如何播放语音提示外线客户坐席不在线
  6. Python--小游戏俄罗斯方块
  7. 什么是单点故障与应对措施
  8. 计算机中软键盘有哪些用途,电脑键盘的每个字母都有什么用途呢?
  9. linux设备模型:devtmpfs虚拟文件系统分析
  10. ply文件格式详细说明