通过OpenGL ES在iOS平台实践增强现实
http://www.cnblogs.com/elvisyzhao/p/3398250.html
- 本文采用OpenGL ES 1固定渲染管线实现,目标为在设备拍摄到的现实世界中,绘制世界坐标轴,并根据设备所在位置和朝向,绘制周围一定范围内的指定目标(比如餐厅,咖啡馆等)。首先说明几个OpenGL的容易混淆的基础知识
OpenGL采用右手坐标系(伸出你的右手,拇指和食指垂直,中指分别和拇指,食指垂直,此时拇指代表x坐标轴,食指代表y坐标轴,中指代表z坐标轴,这就是右手坐标系)
OpenGL采用列向量,所以矩阵与向量运算为矩阵左乘
OpenGL的glMutMatrixf等操作为右乘
OpenGL采用列主序存储矩阵
- 下面为在iOS平台初始化绘制环境的代码

EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
self.context = context; [EAGLContext setCurrentContext:context]; glGenFramebuffersOES(1, &_framebuffer); // 创建帧缓冲区
glGenRenderbuffersOES(1, &_renderbuffer); // 创建绘制缓冲区
glBindFramebufferOES(GL_FRAMEBUFFER_OES, _framebuffer); // 绑定帧缓冲区到渲染管线
glBindRenderbufferOES(GL_RENDERBUFFER_OES, _renderbuffer); // 绑定绘制缓冲区到渲染管线
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, _renderbuffer); // 绑定绘制缓冲区到帧缓冲区 GLint width;
GLint height;
[context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:layer]; // 为绘制缓冲区分配存储区,此处将CAEAGLLayer的绘制存储区作为绘制缓冲区的存储区
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &width); // 获取绘制缓冲区的像素宽度
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &height); // 获取绘制缓冲区的像素高度 glGenRenderbuffersOES(1, &_depthbuffer); // 创建深度缓冲区
glBindRenderbufferOES(GL_RENDERBUFFER_OES, _depthbuffer); // 绑定深度缓冲区到渲染管线
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height); // 为深度缓冲区分配存储区
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, _depthbuffer); // 绑定深度缓冲区到帧缓冲区 glMatrixMode(GL_PROJECTION); // 改变矩阵变换模式到投影矩阵,以后的矩阵操作都会是对投影矩阵操作 GLfloat w = 0.5 * tanf(M_PI / 8);
glFrustumf(-w, w, -w*height/width, w*height/width, 0.5, 3000); // 视锥定义
glViewport(0, 0, width, height); // 视口定义
- 本文实现了一个摄像机类,根据摄像机的位置和朝向获得摄像机世界矩阵的逆矩阵

- (void)getViewMatrix:(GLfloat *)matrix
{
GLfloat x = _orientation.x;
GLfloat y = _orientation.y;
GLfloat z = _orientation.z;
GLfloat w = _orientation.w;
GLfloat *rot = malloc(sizeof(GLfloat) * 16);
rot[0] = 1-2*y*y-2*z*z;
rot[1] = 2*x*y-2*w*z;
rot[2] = 2*x*z+2*w*y;
rot[3] = 0.0;
rot[4] = 2*x*y+2*w*z;
rot[5] = 1-2*x*2-2*z*z;
rot[6] = 2*y*z-2*w*x;
rot[7] = 0.0;
rot[8] = 2*x*z-2*w*y;
rot[9] = 2*y*z+2*w*z;
rot[10] = 1-2*x*x-2*y*y;
rot[11] = 0.0;
rot[12] = 0;
rot[13] = 0;
rot[14] = 0;
rot[15] = 1.0; GLfloat transX = -rot[0]*_position.x - rot[4]*_position.y - rot[8]*_position.z;
GLfloat transY = -rot[1]*_position.x - rot[5]*_position.y - rot[9]*_position.z;
GLfloat transZ = -rot[2]*_position.x - rot[6]*_position.y - rot[10]*_position.z; rot[12] = transX;
rot[13] = transY;
rot[14] = transZ; memcpy(matrix, rot, sizeof(GLfloat)*16);
free(rot);
}
- 本文实现了一个纹理类,用来简化纹理操作

- (void)getViewMatrix:(GLfloat *)matrix
{
GLfloat x = _orientation.x;
GLfloat y = _orientation.y;
GLfloat z = _orientation.z;
GLfloat w = _orientation.w;
GLfloat *rot = malloc(sizeof(GLfloat) * 16);
rot[0] = 1-2*y*y-2*z*z;
rot[1] = 2*x*y-2*w*z;
rot[2] = 2*x*z+2*w*y;
rot[3] = 0.0;
rot[4] = 2*x*y+2*w*z;
rot[5] = 1-2*x*2-2*z*z;
rot[6] = 2*y*z-2*w*x;
rot[7] = 0.0;
rot[8] = 2*x*z-2*w*y;
rot[9] = 2*y*z+2*w*z;
rot[10] = 1-2*x*x-2*y*y;
rot[11] = 0.0;
rot[12] = 0;
rot[13] = 0;
rot[14] = 0;
rot[15] = 1.0; GLfloat transX = -rot[0]*_position.x - rot[4]*_position.y - rot[8]*_position.z;
GLfloat transY = -rot[1]*_position.x - rot[5]*_position.y - rot[9]*_position.z;
GLfloat transZ = -rot[2]*_position.x - rot[6]*_position.y - rot[10]*_position.z; rot[12] = transX;
rot[13] = transY;
rot[14] = transZ; memcpy(matrix, rot, sizeof(GLfloat)*16);
free(rot);
}
- 下面是绘制过程的代码

- (void)render
{
glBindRenderbufferOES(GL_RENDERBUFFER_OES, _renderbuffer); // 绑定绘制缓冲区到渲染管线
//glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清空绘制缓冲区和深度缓冲区
glEnableClientState(GL_VERTEX_ARRAY); MZGLCamera *camera = self.camera;
GLfloat *matrix = malloc(sizeof(GLfloat) * 16);
[camera getViewMatrix:matrix]; glMatrixMode(GL_MODELVIEW_MATRIX); // 改变矩阵变换模式到模型矩阵
glLoadIdentity(); // 将模型矩阵更新为单位矩阵
glEnable(GL_DEPTH_TEST); // 开始深度测试
glDepthFunc(GL_LESS); // 切换深度测试模式为待绘制像素距离屏幕距离小于深度缓冲区当前值则绘制,否则不绘制 glLoadMatrixf(matrix); // 根据摄像机位置设置模型矩阵,此处的矩阵为摄像机世界矩阵的逆矩阵 glVertexPointer(3, GL_FLOAT, 0, _lineVertexBuffer);
glColor4f(1.0, 1.0, 0.0, 1.0);
glDrawElements(GL_LINES, _lineVertexCount, GL_UNSIGNED_BYTE, _lineIndexBuffer); // 绘制世界坐标系的坐标轴 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D); // 开启纹理绘制
glEnable(GL_ALPHA_TEST); // 开启Alpha测试
glAlphaFunc(GL_GREATER, 0.5f); // 切换Alpha测试模式为不透明度大于0.5则绘制,否则不绘制
glColor4f(1.0, 1.0, 1.0, 1.0); // 填充绘制缓冲区
NSArray *values = [self.entityDictionary allValues];
for (NSObject *entity in values) {
if ([entity conformsToProtocol:@protocol(MZGLRenderable)]) {
if ([entity isKindOfClass:[MZGLBillboard class]]) {
MZGLBillboard *billboard = (MZGLBillboard *)entity; glVertexPointer(3, GL_FLOAT, 0, billboard.vertexBuffer); // 设置顶点缓冲指针
glTexCoordPointer(2, GL_FLOAT, 0, billboard.coordinates); // 设置纹理坐标指针
[billboard preRender:self];
glLoadIdentity();
GLfloat *transform = [billboard worldTrasform]; // 设置模型世界矩阵
glLoadMatrixf(matrix); // 将模型矩阵设置为摄像机世界矩阵的逆矩阵
glMultMatrixf(transform); // 右乘模型的世界矩阵
[billboard.texure bind]; // 绑定纹理
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // 绘制顶点
}
}
} [_context presentRenderbuffer:GL_RENDERBUFFER]; // 绘制到绘制缓冲区
}
- 下面是在测试数据在模拟器上的效果,后续会说明如何结合陀螺仪去将虚拟世界中的摄像头和设备绑定到一起
通过OpenGL ES在iOS平台实践增强现实的更多相关文章
- 通过OpenGL ES在iOS平台实践增强现实(一)
http://ios.9tech.cn/news/2013/1108/38495.html 1.本文采用OpenGL ES 1固定渲染管线实现,目标为在设备拍摄到的现实世界中,绘制世界坐标轴,并根据设 ...
- 通过OpenGL ES在iOS平台实践增强现实(二)
上一篇讲到如何使用OpenGL ES绘制一个3D场景,这一篇我们会配合使用iOS提供的CoreMotion框架把虚拟世界中的摄像机的位置朝向和设备实际的位置朝向绑定起来.本文还对防抖做了处理. 首先说 ...
- WebGL 在 OpenGL ES 指令 iOS 在 C 分歧版指令分析
WebGL 中 OpenGL ES 指令与 iOS 中 C 版指令的差异简析 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途 ...
- OpenGL ES on iOS --- 统一变量(Uniform)和统一变量块(UBO)
简介 Uniform是一种从CPU中的应用向GPU中的着色器发送数据的方式,但uniform和顶点属性有些不同. 首先,uniform是全局的(Global).全局意味着uniform变量必须在每个着 ...
- OpenGL ES应用开发实践指南:iOS卷
<OpenGL ES应用开发实践指南:iOS卷> 基本信息 原书名:Learning OpenGL ES for iOS:A Hands-On Guide to Modern 3D Gra ...
- iOS 中OpenGL ES 优化 笔记 1
1,避免同步和Flushing操作 OpenGL ES的命令执行通常是在command buffer中积累一定量的命令后,再做批处理执行,这样效率会更高:但是一些OpenGL ES命令必须flush ...
- (转)规划从 OpenGL ES 2.0 到 Direct3D 的移植
如果你移植 iOS 或 Android 平台中的游戏,那么你可能需要在 OpenGL ES 2.0 方面进行大量投资.如果你准备将你的图形管道代码库移动到 Direct3D 11 和 Windows ...
- OpenGL ES: (4) EGL API详解 (转)
上一节我们初步学习了 OpenGL ES.EGL.GLSL 的相关概念,了解了它们的功能,以及它们之间的关联.我们知道了 EGL 是绘制 API(比如 OpenGL ES)与 底层平台窗口系统之间的接 ...
- [OpenGL ES 02]OpenGL ES渲染管线与着色器
[OpenGL ES 02]OpenGL ES渲染管线与着色器 罗朝辉 (http://www.cnblogs.com/kesalin/) 本文遵循"署名-非商业用途-保持一致"创 ...
随机推荐
- 将WebAPI发布到本地服务器与远程服务器
一.本地服务器 参考链接:https://blog.csdn.net/shuai_wy/article/details/69221858 1.要实现 IIS Express域名.IP的访问,关键在于需 ...
- 关于学习less后一些感悟
学习了一天的less发现,自己被自己弄的晕头转向,好在是学明白了! 一.写自己的第一个less css样式编程: 网址:http://www.1024i.com/demo/less/document. ...
- 一步一步学Linq to sql(一):预备知识
什么是Linq to sql Linq to sql(或者叫DLINQ)是LINQ(.NET语言集成查询)的一部分,全称基于关系数据的 .NET 语言集成查询,用于以对象形式管理关系数据,并提供了丰富 ...
- MAC中mongodb的连接遇到的问题及调试
今天在MAC环境下连接mongodb,遇到了一些报错,最终调试全部搞定.在此特做记录! 首先,mongod启动失败 上面有一句话是 exception in initAndListen: 20 Att ...
- (C)spring boot读取自定义配置文件时乱码解决办法
这是入门的第三天了,从简单的hello spring开始,已经慢慢接近web的样子.接下来当然是读取简单的对象属性了. 于是按照网上各位大神教的,简单写了个对象book,如上一篇(B),其他配置不需要 ...
- 【APUE】Chapter8 Process Control
这章的内容比较多.按照小节序号来组织笔记的结构:再结合函数的示例带代码标注出来需要注意的地方. 下面的内容只是个人看书时思考内容的总结,并不能代替看书(毕竟APUE是一本大多数人公认的UNIX圣经). ...
- katalon系列二:selenium IDE的替代者——Katalon Recorder
Katalon Recorder是和selenium IDE一样的一个浏览器插件,可以录制web上的操作并回放,但我个人感觉Katalon Recorder更好用.大家可以直接在chrome商店下载安 ...
- 抓包工具 - Fiddler - (一)
<转载于 miantest> Fiddler基础知识 Fiddler是强大的抓包工具,它的原理是以web代理服务器的形式进行工作的,使用的代理地址是:127.0.0.1,端口默认为8888 ...
- wxPython 界面编程的有关事件
在事件处理的过程中涉及四个要素: 1.事件. 它是用户对界面的操作,在wxPython中事件被封装成事件类wx.Event及其子类,例如按钮事件类wx.CommandEvent,鼠标事件类是wx.Mo ...
- Scrapy爬取到的中文数据乱码问题处理
Scrapy爬取到中文数据默认是 Unicode编码的,于是显示是这样的: "country": ["\u56fd\u4ea7\u6c7d\u8f66\u6807\u5f ...
