本文参考了王刚的《疯狂Android讲义(第3版)》P554-P559

要求:利用OpenGL ES绘制一个三棱锥,并对每个面进行纹理贴图,每个面使用不同的图片进行渲染。

环境:Android Studio 3.6.1,gradle版本为5.6.4,OpenGL使用1x版本,新建工程后需在res/drawable目录下放4张图片img1、img2、img3、img4(建议图片长宽均是2的n次方,如果不符合则系统会自动调节,我使用的图片长宽是256×256)。

运行结果:

三棱锥多纹理贴图运行结果

 主要步骤:

1.在MainActivity.java文件自定义内部公共类MyRenderer实现接口Renderer(也可新建Java文件来实现)。

2.定义三棱锥的顶点坐标、纹理坐标、几个需要用到的Buffer及其他数据等。

// 定义三棱椎的4个顶点
private float[] taperVertices = new float[]{0.0f,  0.5f,  0.0f, //0-0.5f, -0.5f, -0.2f, //10.5f, -0.5f, -0.2f, //20.0f, -0.2f,  0.2f  //3
};
// 定义纹理贴图的坐标数据
private float[] taperTextures = {0.5000f, 0.0000f, 0.0000f, 1.0000f, 1.0000f, 1.0000f,0.0000f, 1.0000f, 1.0000f, 1.0000f, 0.5000f, 0.0000f,0.0000f, 1.0000f, 1.0000f, 1.0000f, 0.5000f, 0.0000f,1.0000f, 1.0000f, 0.0000f, 1.0000f, 0.5000f, 0.0000f,
};
private Context context;
private FloatBuffer taperVerticesBuffer;
private ByteBuffer[] taperFacts_indices;
private FloatBuffer taperTexturesBuffer;
// 定义本程序所使用的纹理
private int[] textures = new int[4];
// 旋转角度
float rotate = 0;

定义纹理坐标数据要注意:Android使用的OpenGL ES的纹理坐标系跟官方的OpenGL纹理坐标系统不一样。官方的OpenGL ES纹理坐标为左下角是(0, 0)右上角是(1, 1);而Android的纹理坐标左上角为(0, 0)右下角为(1, 1)。

3.实现MyRenderer(Context main)方法

public MyRenderer(Context main) {this.context = main;// 将三棱椎的顶点位置数据数组包装成FloatBuffertaperVerticesBuffer = floatBufferUtil(taperVertices);// 将三棱椎的4个面的数组indices[1:4]包装成ByteBuffer并加入一个数组中ByteBuffer indices1 = ByteBuffer.wrap(new byte[]{0, 1, 2,0, 0, 0,0, 0, 0,0, 0, 0});ByteBuffer indices2 = ByteBuffer.wrap(new byte[]{0, 0, 0,0, 1, 3,0, 0, 0,0, 0, 0});ByteBuffer indices3 = ByteBuffer.wrap(new byte[]{0, 0, 0,0, 0, 0,1, 2, 3,0, 0, 0});ByteBuffer indices4 = ByteBuffer.wrap(new byte[]{0, 0, 0,0, 0, 0,0, 0, 0,0, 2, 3});taperFacts_indices = new ByteBuffer[]{indices1, indices2, indices3, indices4};// 将立方体的纹理贴图的坐标数据包装成FloatBuffertaperTexturesBuffer = floatBufferUtil(taperTextures);
}

4.纹理映射功能默认是关闭的,所以需要在onSurfaceCreated内启用纹理映射功能。

// 启用2D纹理贴图
gl.glEnable(GL10.GL_TEXTURE_2D);
// 装载纹理
loadTexture(gl);

loadTexture()是自定义的一个装载纹理的方法,实现方法如下:

private void loadTexture(GL10 gl) {Bitmap[] bitmap = new Bitmap[4];try {// 加载位图bitmap[0] = BitmapFactory.decodeResource(context.getResources(),R.drawable.img1);bitmap[1] = BitmapFactory.decodeResource(context.getResources(),R.drawable.img2);bitmap[2] = BitmapFactory.decodeResource(context.getResources(),R.drawable.img3);bitmap[3] = BitmapFactory.decodeResource(context.getResources(),R.drawable.img4);// 创建纹理对象,指定生成N个纹理(第一个参数指定生成几个纹理)// textures数组将负责存储所有纹理的代号gl.glGenTextures(4, textures, 0);for (int i = 0; i < textures.length; i++) {// 通知OpenGL将texture纹理绑定到GL10.GL_TEXTURE_2D目标中gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[i]);// 设置纹理被缩小(距离视点很远时被缩小)时的滤波方式gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);// 设置纹理被放大(距离视点很近时被方法)时的滤波方式gl.glTexParameterf(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);// 设置在横向、纵向上都是平铺纹理gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,GL10.GL_REPEAT);gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,GL10.GL_REPEAT);// 加载位图生成纹理GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap[i], 0);}} finally {// 生成纹理之后,回收位图for (int i = 0; i < bitmap.length; i++) bitmap[i].recycle();}
}

其中几个函数的含义如下:

void glGenTextures(int n,int[] textures,int offset)  //创建纹理对象

  • n:需要生成的纹理对象个数;
  • textures:保存生成所有纹理对象的数组;
  • offset:纹理对象数组的偏移(生成的纹理从数组什么位置开始赋值)。

void glBindTexture (int target, int texture)  //绑定纹理,绑定后的纹理才处于活动状态

  • target:纹理类型,使用 2D 纹理则参数设为GL_TEXTURE_2D;
  • texture:纹理对象的 ID。

void glTexParameterf(int target,int pname,float param)  //对绑定的纹理进行基本属性设置

  • target:纹理类型,表示我们激活的纹理单元对应了什么样的操作类型,比如GL_TEXTURE_1D、GL_TEXTURE_2D等;
  • pname:属性名称;
  • param:属性值。

void texImage2D (int target, int level, Bitmap bitmap, int border)  //指定纹理

  • target:操作的目标类型,本程序均设为 GL_TEXTURE_2D 即可
  • level:纹理的级别,表示多级分辨率的纹理图象的级数。若只有一种分辨率,level为0。
  • bitmap:使用的图像
  • border:边框,一般设为0

Bitmap decodeResource(Resources res, int id)  //加载位图

  • res:包含图像数据的Resources对象
  • id:图像数据的资源id

5.绘制图像及纹理

//绘制图形的方法
@Override
public void onDrawFrame(GL10 gl) {// 清除屏幕缓存和深度缓存gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);// 启用顶点坐标数据gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);// 启用贴图坐标数组数据gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);// 设置当前矩阵模式为模型视图。gl.glMatrixMode(GL10.GL_MODELVIEW);gl.glLoadIdentity();// 把绘图中心移入屏幕2个单位gl.glTranslatef(0f, 0.0f, -2.0f);// 旋转图形gl.glRotatef(rotate, -0.1f, -0.1f, 0.05f); // 旋转总坐标系// 设置顶点的位置数据gl.glVertexPointer(3, GL10.GL_FLOAT, 0, taperVerticesBuffer);// 设置贴图的坐标数据gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, taperTexturesBuffer);  // ②//使用for循环给三棱锥每个面都贴上相应的纹理图for(int i = 0; i < taperFacts_indices.length; i++) {// 绑定纹理,执行纹理贴图gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[i]);// 按taperFacts_indices[i]指定的面绘制三角形gl.glDrawElements(GL10.GL_TRIANGLES, 3*(i+1), GL10.GL_UNSIGNED_BYTE, taperFacts_indices[i]);}// 绘制结束gl.glFinish();// 禁用顶点、纹理坐标数组gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);//角度+1使绘制的图形旋转显示其他面rotate += 1;
}

void glTexCoordPointer(int size, int type, int stride, Buffer pointer)  //设置顶点数组为纹理坐标缓存

  • size:纹理顶点坐标的分量个数,本程序使用纹理坐标的2个分量(s, t)映射顶点坐标的3个分量(x, y, z);
  • type:纹理坐标的数据类型,short, int, float, double都可以;
  • stride:位图的宽度,可以理解为相邻的两个纹理之间跨多少个字节,一般为0,因为一般不会在纹理中再添加其他的信息;
  • pointer:存放纹理坐标的数组。

 总结:如果想多面体各个面的纹理不一样,则在画每个面之前要加上void glBindTexture (int target, int texture)函数绑定纹理。

Android Studio OpenGL ES绘制三棱锥/四面体的多纹理贴图 每个面使用一张图片渲染相关推荐

  1. Android 开发使用OpenGL ES绘制三棱锥并进行纹理贴图

    效果图: 直接上代码 MainActivity.java的代码 package com.zzu.shiyan3;import androidx.appcompat.app.AppCompatActiv ...

  2. 【Qt for Android】OpenGL ES 绘制彩色立方体

    Qt 内置对OpenGL ES的支持.选用Qt进行OpenGL ES的开发是很方便的,很多辅助类都已经具备.从Qt 5.0開始添加了一个QWindow类,该类既能够使用OpenGL绘制3D图形,也能够 ...

  3. OpenGL ES实现三棱锥纹理贴图

    这是老师布置的课后作业,闲来无事分享出来,也加深一遍自己的印象~ 自己定义一个MyRenderer.java类: package com.example.shiyan3_2;import androi ...

  4. android用openGl ES绘制任意方程的三维空间图形

    最近在写一个数值计算数学软件,用于矩阵分析.线性.非线性方程(组)求解.数值积分的求解,二维.三维绘图. 其中的三维绘图,用OpenGl渲染,本来打算用原生的方法实现,但是能力有限,且对OpenGl不 ...

  5. android三个骰子摇动动画,【Android】OpenGL ES实现3D抛骰子

    实现的效果: 抛骰子 加载模型 一.OpenGL简介 OpenGL(全写Open Graphics Library)是个定义了一个跨编程语言.跨平台的编程接口的规格,它用于三维图象(二维的亦可).Op ...

  6. 安卓学习笔记37:利用OpenGL ES绘制平面图形

    文章目录 零.学习目标 一.OpenGL概述 二.了解三维直角坐标系 三.案例演示 - 绘制三角形 (一)运行效果 (二)实现步骤 1.创建安卓应用[DrawTriangle] 2.建模:创建三角形类 ...

  7. OpenGL ES:绘制函数glDrawArrays 和 glDrawElements 的区别

    from:https://www.jianshu.com/p/4d02c2cd21ea 写文章注册登录 首页 下载App OpenGL ES:绘制函数glDrawArrays 和 glDrawElem ...

  8. 【AR实验室】OpenGL ES绘制相机(OpenGL ES 1.0版本)

    0x00 - 前言 之前做一些移动端的AR应用以及目前看到的一些AR应用,基本上都是这样一个套路:手机背景显示现实场景,然后在该背景上进行图形学绘制.至于图形学绘制时,相机外参的解算使用的是V-SLA ...

  9. Android Studio 插件开发详解三:翻译插件实战

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/78113868 本文出自[赵彦军的博客] 系列目录 Android Gradle使用 ...

最新文章

  1. R语言ggplot2可视化:使用ggplot2绘制按时间顺序排列的时间线图(chronological timeline plot)
  2. It Smells!不要让两个状态纠缠的类同时成为某个事件的观察者(一切都只是视图)...
  3. 四个C++函数模板实例
  4. 如何禁用 Azure 虚拟机的日期时间同步
  5. 用户体验五要素_UX系列课(三):用户体验影响力金字塔及五大要素
  6. 【 Grey Hack 】万金油脚本:常见端口漏洞检测
  7. CS144 计算机网络实验 lab3 笔记
  8. 关于批量插入数据之我见(100万级别的数据,mysql)
  9. slr1文法_SLR的完整形式是什么?
  10. java难度_你们觉得java难吗?
  11. 相比 Windows 为什么越来越多人选择Linux?
  12. SpringMVC中异常捕获
  13. 简单实例讲解为何深度学习有效
  14. liunx中查看安装软件和卸载软件和启动程序
  15. 【IRA/GSM/UCS2】the difference of IRA/GSM/UCS2 character set
  16. C语言if语句实现成绩划分
  17. html css屏蔽右键,css右键菜单.html
  18. 程序员都需要会的JVM调优总结 -Xms -Xmx -Xmn -Xss,附idea配置实战(程序员必学)
  19. Photoshop对图片加边框
  20. Day03_【数组、ArrayList】

热门文章

  1. teraterm乱码linux,[Unity3D][转] 关于Assets资源目录结构管理
  2. java B2B2C源码电子商务平台 ---搭建Eureka注册中心
  3. 一个北漂女程序员的心中梦想
  4. B - The Pilots Brothers' refrigerator
  5. Android 开发简单记事本程序(附源码)
  6. Spring Boot 注入接口 @Autowired interface
  7. [已解决] ‘strncpy‘ output truncated before terminating nul copying?bytes from a string of the same leng
  8. android layout_gravity center,android: layout_gravity与gravity区别及动态设置
  9. 舌尖上的创业者:吃货小分队CEO Amy Duan|伯斯人物志
  10. 计算机动画 vr技术应用,三维动画与VR交互和虚拟现实性技术的结合