Android使用OpenGL ES 3.0实现随手指旋转3D立方体
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立方体相关推荐
- NDK OpenGL ES 3.0 开发(一):绘制一个三角形
该原创文章首发于微信公众号:字节流动 什么是 OpenGLES OpenGLES 全称 OpenGL for Embedded Systems ,是三维图形应用程序接口 OpenGL 的子集,本质上是 ...
- 《OpenGL ES 2.0游戏开发(上卷):基础技术和典型案例》一第6章 让场景更逼真——光照效果...
本节书摘来异步社区<OpenGL ES 2.0游戏开发(上卷):基础技术和典型案例>一书中的第6章,第6.1节,作者: 吴亚峰 责编: 张涛,更多章节内容可以访问云栖社区"异步社 ...
- 【我的OpenGL学习进阶之旅】OpenGL ES 3.0新功能
目录 1.1 纹理 1.2 着色器 1.3 几何形状 1.4 缓冲区对象 1.5 帧缓冲区 OpenGL ES 2.0 开创了手持设备可编程着色器的时代,在驱动大量设备的游戏.应用程序和用户接口中获得 ...
- 利用JNI技术在Android中调用C++形式的OpenGL ES 2.0函数
1. 打开Eclipse,File-->New-->Project--->Android-->AndroidApplication Projec ...
- 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 ...
- 《Android 3D游戏开发技术宝典——OpenGL ES 2.0》——2.8节本章小结
本节书摘来自异步社区<Android 3D游戏开发技术宝典--OpenGL ES 2.0>一书中的第2章,第2.8节本章小结,作者 吴亚峰,更多章节内容可以访问云栖社区"异步社区 ...
- 《Android 3D游戏开发技术宝典——OpenGL ES 2.0》——2.4节文件I/O
本节书摘来自异步社区<Android 3D游戏开发技术宝典--OpenGL ES 2.0>一书中的第2章,第2.4节文件I/O,作者 吴亚峰,更多章节内容可以访问云栖社区"异步社 ...
- 使用Android OpenGL ES 2.0绘图之五:添加运动
传送门☞Android兵器谱☞转载请注明☞http://blog.csdn.net/leverage_1229 传送门☞系统架构设计☞转载请注明☞http://blog.csdn.net/levera ...
- 使用Android OpenGL ES 2.0绘图之一:搭建一个OpenGL ES环境
传送门☞Android兵器谱☞转载请注明☞http://blog.csdn.net/leverage_1229 传送门☞系统架构设计☞转载请注明☞http://blog.csdn.net/levera ...
最新文章
- DOS批处理高级教程精选(七)
- 再见,xShell,自己用Java撸一个Web版的,网友直呼:666
- VTK修炼之道70:体绘制讨论_光照阴影、VTKLODProp3D
- pythonsvc_sklearn-SVC实现与类参数详解
- java class获取type_java – 获取Class [Runtime-Type Token]的实例
- 看完数据分析师一天的工作,才明白为什么人家年薪50W
- 用DFS深度优先搜索求 1~n 的全排列
- 易语言linux支持多线程,详解易语言启动多线程
- 【HTML 教程系列第 10 篇】什么是 HTML 中的水平线标签 hr
- 自用gnome桌面美化插件
- Atmel 官方网站中文版
- 微信小程序wx.getLocation接口审核不通过
- video.js 自定义播放组件
- 量子通信,永不陷落的安全堡垒?
- 针对WIN10安卓模拟器蓝屏的解决办法
- js 编码解码 escape,encodeURI,encodeURIComponent
- NISP-信息安全事件与应急响应
- 【收藏向】电路(上) 思维导图 3小时不挂科(邱关源教材)
- 冲刺港交所上市,瞄准亚太地区未来增长空间,法拉帝或难以圆梦?
- 易网客商业Wifi的时代
热门文章
- 弘辽科技:淘宝新品上架,该如何有效快速提升流量?
- 火花塞报警能用计算机消除,更换火花塞后发动机故障报警怎么办
- 计算机主板功能是什么,电脑主板有什么作用?电脑主板作用详细解析
- python编辑ppt图片_Python实现对PPT文件进行截图操作的方法
- 学计算机什么电脑配置可以吗,学习室内设计,需要什么样的电脑配置?
- 学习之路(一)Android 的上下文菜单: Context Menu,registerForContextMenu(getListView());
- CNKI下载硕博论文PDF版及批量添加PDF书签
- 创建索引oracle 很慢,Oracle 建立索引及SQL优化
- 如何降低ue4 cpu消耗_如何有效降低CPU温度,六个步骤教你如何使用液金导热!...
- 等我干IT发财了,就和你离婚。。。。。