通常一个纹理映射的步骤是:

  1. 创建纹理对象。就是获得一个新的纹理句柄 ID.
  2. 指定纹理。就是将数据赋值给 ID 的纹理对象,在这一步,图像数据正式加载到了 ID 的纹理对象中。
  3. 设定过滤器。定义了opengl现实图像的效果,如纹理放大时的马赛克消除。
  4. 绑定纹理对象。就是将 ID 的纹理作为下面操作的纹理。
  5. 纹理映射。将已绑定纹理的数据绘制到屏幕上去,在这一步,就能看到贴图的效果了。

一、opengl 中启用纹理映射功能

在默认设置中,纹理映射是关闭的,启用的参数是 GLTEXTURE2D, 还有其他的参数: GL_TEXTURE_1D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP。我们只用到2D纹理,其他不再赘述。

gl.glEnable(GL_TEXTURE_2D)二、创建纹理

创建纹理,用函数 glGenTextures() 完成,函数返回新创建的纹理的 ID。此函数可以创建 n 个纹理,并将纹理ID 放在 textures 中:

 
void glGenTextures (int n, IntBuffer textures)

范例:

?
1
2
3
IntBuffer intBuffer = IntBuffer.allocate(1);
gl.glGenTextures(1, intBuffer);
int textureId = intBuffer.get(); // 纹理 ID

指定纹理

OpenGL 提供了三个函数来指定纹理: glTexImage1D(), glTexImage2D(), glTexImage3D(). 这三个版本用于相应维数的纹理,我们用到的是 2D 版本: glTexImage2D().

void glTexImage2D (int target, int level, int internalformat, int width, int height, int border, int format, int type, Buffer pixels)

参数过多,可以使用 GLUtils 中的 texImage2D() 函数,好处是直接将 Bitmap 数据作为参数:

void texImage2D (int target, int level, Bitmap bitmap, int border)

参数:

target
操作的目标类型,设为 GL_TEXTURE_2D 即可
level
纹理的级别,本节不涉及,设为 0 即可
bitmap
图像
border
边框,一般设为0
?
1
GLUtils.texImage2D (GL10.GL_TEXTURE_2D, 0, mBitmap, 0);

删除纹理

删除纹理, 第三个参数指明了第二个参数 textures 数组中纹理ID 的步长,一般是紧凑顺序存放,设为0即可。

void glDeleteTextures (int n, int[] textures, int offset)

绑定纹理

绑定后,此纹理处于活动状态。在第一次绑定一个纹理对象时, 会将一系列初始值来适应你的应用。绑定比较简单,用函数 glBindTexture():

void glBindTexture (int target, int texture)

第一个参数是纹理类型,我们使用 2D 纹理,参数设为 GL_TEXTURE_2D, 第二个参数是纹理对象的 ID。

设置过滤器

有两个版本:float版和int版本。

void glTexParameterf (int target, int pname, float param)  
void glTexParameterx (int target, int pname, int param)

一般我们设置两个, 一个放大器的: GL_TEXTURE_MAG_FILTER, 一个缩小器的: GL_TEXTURE_MIN_FILTER.

下面的两行告诉OpenGL在显示图像时,当它比放大得原始的纹理大 ( GL_TEXTURE_MAG_FILTER )或缩小得比原始得纹理小( GL_TEXTURE_MIN_FILTER )时OpenGL采用的滤波方式。

通常这两种情况下我都采用 GL_LINEAR 。这使得纹理从很远处到离屏幕很近时都平滑显示。使用 GL_LINEAR 需要CPU和显卡做更多的运算。

如果您的机器很慢,您也许应该采用 GL_NEAREST 。过滤的纹理在放大的时候,看起来斑驳的很(马赛克)。您也可以结合这两种滤波方式。在近处时使用 GL_LINEAR ,远处时 GL_NEAREST 。

1
2
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // 线形滤波
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // 线形滤波

 三、纹理映射

用函数 glTexCoordPointer 指定纹理坐标数组,

void glTexCoordPointer (int size, int type, int stride, Buffer pointer)

默认这个功能是关闭的,所以需要打开:

?
1
2
3
4
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
// ... 
// 关闭
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

2 常见的几个问题

2.1 贴图呈现白色

可能的原因:

  • 未启用 GL_TEXTURE_2D 选项。请使用 glEnable()glDisable() 函数进行开启和关闭。
  • 纹理对象无数据。 使用 GLUtils.texImage2D() 来指定,指定前需 glBindTexture() 激活当前纹理。

2.2 图像扭曲

可能的原因:

  • 纹理坐标和顶点坐标对应关系是否正确,调整之
  • 图像的大小不是 2 的次幂, 解决: 内部重新生成一张 2 的次幂的image,调整uv坐标

3 代码实现

先定义一个纹理对象,其基本接口有:

  • 创建+指定。 构造函数完成
  • 绑定。
  • 绘制。

@note: 为了处理 2 的次幂,内部对原始图像不是2的次幂的重新建立了一个图像。详见代码吧。

public class Texture2D { private int mWidth; private int mHeight; private int mPow2Width; private int mPow2Height; private float maxU = 1.0f; private float maxV = 1.0f; private Bitmap mBitmap = null; private int textureId = 0; // 删除纹理数据 public void delete(GL10 gl) { if (textureId != 0){ gl.glDeleteTextures(1, new int[]{textureId}, 0); textureId = 0; } // bitmap if (mBitmap != null) { if (mBitmap.isRecycled()) mBitmap.recycle(); mBitmap = null; } } public static int pow2(int size) { int small = (int)(Math.log((double)size)/Math.log(2.0f)) ; if ( (1 << small) >= size) return 1 << small; else return 1 << (small + 1); } // 构建,推迟到第一次绑定时 public Texture2D(Bitmap bmp) { // mBitmap = bmp; mWidth = bmp.getWidth(); mHeight = bmp.getHeight(); mPow2Height = pow2(mHeight); mPow2Width =pow2(mWidth); maxU = mWidth/(float)mPow2Width; maxV = mHeight/(float)mPow2Height; Bitmap bitmap = Bitmap.createBitmap(mPow2Width, mPow2Height, bmp.hasAlpha() ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565); Canvas canvas = new Canvas(bitmap); canvas.drawBitmap(bmp, 0, 0, null); mBitmap = bitmap; } // 第一次会加载纹理数据 public void bind(GL10 gl) { if (textureId ==0) { int[] textures = new int[1]; gl.glGenTextures(1, textures, 0); textureId = textures[0]; gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId); gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, mBitmap, 0); mBitmap.recycle(); mBitmap = null; } gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId); } // 绘制到屏幕上 public void draw(GL10 gl, float x, float y) { gl.glEnable(GL10.GL_TEXTURE_2D); gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); //  绑定 this.bind(gl); // 映射 FloatBuffer verticleBuffer = FloatBuffer.wrap(new float[]{ x,y, x+mWidth, 0, x, y+mHeight, x+mWidth, y+mHeight, }); FloatBuffer coordBuffer = FloatBuffer.wrap(new float[]{ 0,0, maxU,0, 0,maxV, maxU,maxV, }); gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, coordBuffer); gl.glVertexPointer(2, GL10.GL_FLOAT, 0, verticleBuffer); gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,0,4); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); gl.glDisable(GL10.GL_TEXTURE_2D); } public void draw(GL10 gl, float x, float y, float width, float height) { gl.glEnable(GL10.GL_TEXTURE_2D); gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); //  绑定
        bind(gl); // 映射 // 映射 FloatBuffer verticleBuffer = FloatBuffer.wrap(new float[]{ x,y, x+width, 0, x, y+height, x+width, y+height, }); FloatBuffer coordBuffer = FloatBuffer.wrap(new float[]{ 0,0, maxU,0, 0,maxV, maxU,maxV, }); gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, coordBuffer); gl.glVertexPointer(2, GL10.GL_FLOAT, 0, verticleBuffer); gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP,0,4); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); gl.glDisable(GL10.GL_TEXTURE_2D); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); gl.glDisable(GL10.GL_TEXTURE_2D); } } 

4 贴图一个机器人

代码很简单了,在场景 scene 的 draw() 中绘制一个 texture2D, 具体下载代码看看吧:

public class AndroidScene extends GlObject{ Texture2D texture; public AndroidScene() { super(); // 使用 assets 文件夹下的 androida.jpg  Bitmap androidBitmap = GameSystem.getInstance().getBitmapFromAssets("androida.jpg"); texture = new Texture2D(androidBitmap); } public void draw(GL10 gl) { texture.draw(gl, 0, 0); }
} 

这一节有点枯燥,学习愉快。

OpenGL ES 详解纹理生成和纹理映射步骤以及函数相关推荐

  1. OPENGL ES 2.0 知识串讲 (10) ——OPENGL ES 详解IV(纹理优化)

    上节回顾 上一节学习了如何从一张原始图片中,获取生成纹理所需要的信息,然后根据这些信息,通过OpenGL ES API在GPU内存中生成了一张纹理,并且还介绍了纹理属性,知道了如何通过纹理坐标将纹理映 ...

  2. OPENGL ES 2.0 知识串讲 (8) ——OPENGL ES 详解II(传入绘制信息)

    上节回顾 上一节讲述了如何通过 OpenGL ES 给 GPU 关联一套可以使用的 shader,这 一套 shader 是被放在一个 program 中当作一个整体供 GPU 使用的.那么 GPU ...

  3. Android openGl开发详解(二)

    https://zhuanlan.zhihu.com/p/35192609 Android openGl开发详解(二)--通过SurfaceView,TextureView,GlSurfaceView ...

  4. Android openGl开发详解(二)——通过SurfaceView,TextureView,GlSurfaceView显示相机预览(附Demo)

    最近公司在做自定义相机这一块,之前使用的是第三方,后来需求变更,第三方不支持添加动态贴纸,所以只能自己扩展.当然网上有很多例子,但是关于添加动态贴纸的例子几乎找不到,反正我是没找到(欲哭无泪).当然, ...

  5. OpenGL ES之十——纹理贴图(展示一张图片)

    概述 这是一个系列的Android平台下OpenGl ES介绍,从最基本的使用最终到VR图的展示的实现,属于基础篇.(后面针对VR视频会再有几篇文章,属于进阶篇) OpenGL ES之一--概念扫盲 ...

  6. OpenGL粒子系统详解及编程实现

    OpenGL粒子系统详解及编程实现 标签: opengl编程 2016-08-23 14:23  1114人阅读  评论(0)  收藏  举报   分类: OSG(6)  版权声明:本文为博主原创文章 ...

  7. opengl 深度详解_一步步学OpenGL(1) -《打开一个窗口》

    注意本教程中需要使用的是freeGLUT(GLUT太老会有潜在危险)窗口库和GLEW扩展库. vs2013配置freeGLUT3.0:vs2013 配置 freeglut3.0(opengl的窗口系统 ...

  8. 关于OpenGL ES中的纹理压缩

    基于OpenGL ES的压缩纹理有常见的如下几种实现: 1. ETC1(Ericcson texture compression) 2. PVRTC(PowerVR texture compressi ...

  9. Apollo6.0代码Lattice算法详解——Part5: 生成横纵向轨迹

    Apollo6.0代码Lattice算法详解--Part5: 生成横纵向轨迹 0.前置知识 1.涉及主要函数 2.函数关系 3.部分函数代码详解 3.1 lattice_planner.cc中代码部分 ...

最新文章

  1. 通过 39 个 问答方式快速了解学习 Git
  2. asterisk for mipsel
  3. Sting中方法举例
  4. 让C68平台“冷又静”
  5. java 显示服务器的图片,【JavaWeb】实现读取本地服务器路径下的图片
  6. 【论文写作】SSH在线订餐系统如何写软件测试章节
  7. python做积分计算器_PyQt5练习:积分计算器
  8. python分词词典_Python分词模块推荐:结巴中文分词
  9. 场地预约小程序开发及前后端源码
  10. pm2 重启策略(restart strategies)
  11. 专访智齿科技吴立楠:智能客服行业发展的三个趋势
  12. freeswitch mrcp 源码分析--数据包的发送
  13. 机器学习从抬脚到趴倒在门槛No.34
  14. 微秒级别的网络延迟检测
  15. JMeter基础 — JMeter聚合报告详解
  16. linux usleep占用cpu,c-Cent OS 6.3上的usleep的CPU高使用率
  17. linux创建后门账户,Linux后门
  18. 一个程序员的连续套现
  19. select二级联动价格策略+js的eval()
  20. 足不出户逛商场,酷雷曼带你体验vr全景云超市

热门文章

  1. 《应试捷径-典型考题解析与考点贯通_系统分析师考试》复习重点提示
  2. 使用ABAP编程实现对微软Office Word文档的操作
  3. js 字符串操作函数
  4. SVN的Windows和Linux客户端操作详解
  5. JSP page指令
  6. Enigma Virtual Box:生成可执行文件。
  7. 【转】老程序猿给新程序猿的13点建议
  8. js数组去重(多种方法)
  9. Java基础-Eclipse第三方安装包管理工具之Maven
  10. 笔记2 自定义文件上传