OpenGL ES在做普通应用方面3D使用的不多,但有时候实现一些有趣的功能也是蛮不错的。画立方体的的demo网上已经很多了,这次我们就实现一个随手指旋转的立方体,这个demo基本可以了解各个坐标系转换矩阵的使用了。
先看一下最终效果:

话不多说,直接上代码了。

EGL的配置

EGL的配置也就是常规配置了,但是需要注意的一点是:为了使立方体看起来更加真实,需要开启深度测试,需要在egl的环境中加入深度测试的配置。不然就算启用了深度测试也会没用。

 //通过属性去筛选合适的配置const EGLint attibutes[] = {EGL_BUFFER_SIZE, 32,EGL_ALPHA_SIZE, 8,EGL_BLUE_SIZE, 8,EGL_GREEN_SIZE, 8,EGL_RED_SIZE, 8,EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, //指定渲染api版本 2EGL_SURFACE_TYPE, EGL_WINDOW_BIT,EGL_DEPTH_SIZE, 24, //添加这段来请求深度缓冲区EGL_NONE};

绘制一个立方体

首先使用OpenGL绘制一个立方体十分简单,一个面两个三角形,绘制十二个三角形就可以了。一个三角形3个点,也就是需要36个点。其实立方体很多点是重复的,我们完全可以用下标的形式去画点,但是这篇文章我没有用下标,使用了36个点来直接画。

  float vertices[] = {-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 1.0f,-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,-0.5f, 0.5f, -0.5f, 1.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, -0.5f, -0.5f, 0.0f, 1.0f,0.5f, -0.5f, -0.5f, 0.0f, 1.0f,0.5f, -0.5f, 0.5f, 0.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,0.5f, -0.5f, -0.5f, 1.0f, 1.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,0.5f, -0.5f, 0.5f, 1.0f, 0.0f,-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f, 0.0f,-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,-0.5f, 0.5f, -0.5f, 0.0f, 1.0f};glDrawArrays(GL_TRIANGLES, 0, 36);

这个立方体可以想象一下,就是边长为1.0的立方体了,中心在原点。

矩阵变换

我们也还是按照几种常用矩阵变换的套路来,我们还是使用模型,视图,投影矩阵来变换坐标。

#version 300 es
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;out vec2 TexCoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;void main(){gl_Position = projection*view*model*vec4(aPos, 1.0f);TexCoord=vec2(aTexCoord.x,1.0-aTexCoord.y);
}
1、不同向量的旋转

首先我们在只考虑在model中加入旋转。想象一下手指在屏幕上滑动是有一个方向向量的,加入我们在屏幕上这样滑动

那么立方体的旋转轴就是垂直于手指滑动方向的一个向量,而这个向量的求取方式,我们使用这个向量于Z轴的向量进行叉乘来取得。还要注意一点,因为我们取得屏幕坐标系和OpenGL的坐标系又差别,所以需要一定的变化来求得正确的旋转轴。

  if (x > 0 && y > 0) {y = -y;} else if (x <= 0 && y > 0) {x = -x;degree = -degree;} else if (x > 0 && y < 0) {y = -y;} else if (x <= 0 && y < 0) {y = -y;}LOGE("tedu %f %f %f" ,x,y,degree);if (degree != 0) {glm::vec3 cross = glm::cross(glm::vec3(0.0f, 0.0f, 1.0), glm::vec3(x, y, 0.0f));glm::mat4 tmpMat = glm::mat4(1.0f);tmpMat = glm::rotate(tmpMat, degree, cross);tmpMat *= model;model = tmpMat;}

简单分析一下,我们每次求得对应的向量后,生成一个新的选择矩阵,然后右乘原来的矩阵,注意不能交换顺序,然后求得最终的矩阵并赋值了model。通过状态的叠加,最终将会获得最终的效果。

2、双指的缩放

这里就不得不提一下对于双指的判定了。我们的逻辑是:

  • 单指的时候不进行缩放,进行旋转
  • 双指的时候进行缩放,不进行旋转
  • 双指以上情况直接不处理,或者有双指变为单指的情况也不处理

    逻辑理顺之后,我们只需要加入判断的bool变量即可,注意在抬起手指,以及单指切换双指的时候需要清空旋转的值,看一下逻辑。

 cube.setOnTouchListener { v, event ->when (event.actionMasked) {MotionEvent.ACTION_DOWN -> {//单指触摸情况lastX = event.getX()lastY = event.getY()canRotate = truecanScale = false}MotionEvent.ACTION_POINTER_DOWN -> {//双指触摸canRotate = falsecanScale = trueif (event.pointerCount > 2) {canScale = falsereturn@setOnTouchListener false}val index0 = event.getPointerId(0)val index1 = event.getPointerId(1)lastX = event.getX(index0)lastY = event.getY(index0)last1X = event.getX(index1)last1Y = event.getY(index1)controler.rotate(0.0f, 0.0f, 0.0f)}MotionEvent.ACTION_POINTER_UP -> {//还原canScale=falsecanRotate=falsecontroler.rotate(0.0f, 0.0f, 0.0f)}MotionEvent.ACTION_MOVE -> {if (canRotate) {if(event.pointerCount>=2){controler.rotate(0.0f, 0.0f, 0.0f)return@setOnTouchListener true}val curY = event.yval curX = event.xval vecX = curX - lastXval vecY = curY - lastYlastY = curYlastX = curXval distance = Math.sqrt((vecX * vecX).toDouble() + (vecY * vecY).toDouble())controler.rotate(vecX, vecY, distance.toFloat())} else if (canScale) {//通过双指按下的距离比例来进行缩放,但是这里的比例并不实际缩放的比例,只是通过简单调整视野的范围来进行缩放val index0 = event.getPointerId(0)val index1 = event.getPointerId(1)val curX = event.getX(index0)val curY = event.getY(index0)val cur1X = event.getX(index1)val cur1Y = event.getY(index1)val lastDis=Math.sqrt(Math.pow((lastX-last1X).toDouble(), 2.0)+Math.pow((lastY-last1Y).toDouble(), 2.0))val curDis=Math.sqrt(Math.pow((curX-cur1X).toDouble(), 2.0)+Math.pow((curY-cur1Y).toDouble(), 2.0))controler.scale((curDis/lastDis).toFloat())}}}return@setOnTouchListener true;}

然后我们看native代码,首先是做简单的视野角度加减

void CubeTextureRender::setScale(jfloat scale) {LOGE("scale %f",scale);if (scale > 1) {fov -= scale;} else if(scale<1) {fov +=  (1.0f/scale);}if (fov <= 20.0) {fov = 20.0;} else if (fov > 140.0) {fov = 140.0;}
}

然后将视野传入投影即可

    glm::mat4 projection = glm::mat4(1.0f);float ratio = (float) _backingWidth / (float) _backingHeight;projection = glm::perspective(glm::radians(fov), ratio, 0.1f, 100.0f);

文章到这里就结束了,除了一些必要的数学知识,其实难度不大。我们通过添加互动让立方体更加有趣。如果喜欢这篇文章,麻烦点一下关注谢谢。有什么问题也可以在评论区留言。

源码地址

Android使用OpenGL ES 3.0实现随手指旋转3D立方体相关推荐

  1. NDK OpenGL ES 3.0 开发(一):绘制一个三角形

    该原创文章首发于微信公众号:字节流动 什么是 OpenGLES OpenGLES 全称 OpenGL for Embedded Systems ,是三维图形应用程序接口 OpenGL 的子集,本质上是 ...

  2. 《OpenGL ES 2.0游戏开发(上卷):基础技术和典型案例》一第6章 让场景更逼真——光照效果...

    本节书摘来异步社区<OpenGL ES 2.0游戏开发(上卷):基础技术和典型案例>一书中的第6章,第6.1节,作者: 吴亚峰 责编: 张涛,更多章节内容可以访问云栖社区"异步社 ...

  3. 【我的OpenGL学习进阶之旅】OpenGL ES 3.0新功能

    目录 1.1 纹理 1.2 着色器 1.3 几何形状 1.4 缓冲区对象 1.5 帧缓冲区 OpenGL ES 2.0 开创了手持设备可编程着色器的时代,在驱动大量设备的游戏.应用程序和用户接口中获得 ...

  4. 利用JNI技术在Android中调用C++形式的OpenGL ES 2.0函数

    1.                 打开Eclipse,File-->New-->Project--->Android-->AndroidApplication Projec ...

  5. cocos2d-x 2.X for Android中需要使用OpenGL ES 2.0

    cocos2d-x 2.X for Android中需要使用OpenGL ES 2.0 到了2.X版本中,cocos2d-x for Android已经不再支持(或者说放弃支持)opengl es 1 ...

  6. 《Android 3D游戏开发技术宝典——OpenGL ES 2.0》——2.8节本章小结

    本节书摘来自异步社区<Android 3D游戏开发技术宝典--OpenGL ES 2.0>一书中的第2章,第2.8节本章小结,作者 吴亚峰,更多章节内容可以访问云栖社区"异步社区 ...

  7. 《Android 3D游戏开发技术宝典——OpenGL ES 2.0》——2.4节文件I/O

    本节书摘来自异步社区<Android 3D游戏开发技术宝典--OpenGL ES 2.0>一书中的第2章,第2.4节文件I/O,作者 吴亚峰,更多章节内容可以访问云栖社区"异步社 ...

  8. 使用Android OpenGL ES 2.0绘图之五:添加运动

    传送门☞Android兵器谱☞转载请注明☞http://blog.csdn.net/leverage_1229 传送门☞系统架构设计☞转载请注明☞http://blog.csdn.net/levera ...

  9. 使用Android OpenGL ES 2.0绘图之一:搭建一个OpenGL ES环境

    传送门☞Android兵器谱☞转载请注明☞http://blog.csdn.net/leverage_1229 传送门☞系统架构设计☞转载请注明☞http://blog.csdn.net/levera ...

最新文章

  1. DOS批处理高级教程精选(七)
  2. 再见,xShell,自己用Java撸一个Web版的,网友直呼:666
  3. VTK修炼之道70:体绘制讨论_光照阴影、VTKLODProp3D
  4. pythonsvc_sklearn-SVC实现与类参数详解
  5. java class获取type_java – 获取Class [Runtime-Type Token]的实例
  6. 看完数据分析师一天的工作,才明白为什么人家年薪50W
  7. 用DFS深度优先搜索求 1~n 的全排列
  8. 易语言linux支持多线程,详解易语言启动多线程
  9. 【HTML 教程系列第 10 篇】什么是 HTML 中的水平线标签 hr
  10. 自用gnome桌面美化插件
  11. Atmel 官方网站中文版
  12. 微信小程序wx.getLocation接口审核不通过
  13. video.js 自定义播放组件
  14. 量子通信,永不陷落的安全堡垒?
  15. 针对WIN10安卓模拟器蓝屏的解决办法
  16. js 编码解码 escape,encodeURI,encodeURIComponent
  17. NISP-信息安全事件与应急响应
  18. 【收藏向】电路(上) 思维导图 3小时不挂科(邱关源教材)
  19. 冲刺港交所上市,瞄准亚太地区未来增长空间,法拉帝或难以圆梦?
  20. 易网客商业Wifi的时代

热门文章

  1. 弘辽科技:淘宝新品上架,该如何有效快速提升流量?
  2. 火花塞报警能用计算机消除,更换火花塞后发动机故障报警怎么办
  3. 计算机主板功能是什么,电脑主板有什么作用?电脑主板作用详细解析
  4. python编辑ppt图片_Python实现对PPT文件进行截图操作的方法
  5. 学计算机什么电脑配置可以吗,学习室内设计,需要什么样的电脑配置?
  6. 学习之路(一)Android 的上下文菜单: Context Menu,registerForContextMenu(getListView());
  7. CNKI下载硕博论文PDF版及批量添加PDF书签
  8. 创建索引oracle 很慢,Oracle 建立索引及SQL优化
  9. 如何降低ue4 cpu消耗_如何有效降低CPU温度,六个步骤教你如何使用液金导热!...
  10. 等我干IT发财了,就和你离婚。。。。。