http://ios.9tech.cn/news/2013/1108/38495.html

  • 1.本文采用OpenGL ES 1固定渲染管线实现,目标为在设备拍摄到的现实世界中,绘制世界坐标轴,并根据设备所在位置和朝向,绘制周围一定范围内的指定目标(比如餐厅,咖啡馆等)。首先说明几个OpenGL的容易混淆的基础知识

    • OpenGL采用右手坐标系(伸出你的右手,拇指和食指垂直,中指分别和拇指,食指垂直,此时拇指代表x坐标轴,食指代表y坐标轴,中指代表z坐标轴,这就是右手坐标系)
    • OpenGL采用列向量,所以矩阵与向量运算为矩阵左乘
    • OpenGL的glMutMatrixf等操作为右乘
    • OpenGL采用列主序存储矩阵
  • 2.下面为在iOS平台初始化绘制环境的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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);    // 视口定义

3.本文实现了一个摄像机类,根据摄像机的位置和朝向获得摄像机世界矩阵的逆矩阵

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
- (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);
}

4.本文实现了一个纹理类,用来简化纹理操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
- (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);
}

5.下面是绘制过程的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
- (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]; // 绘制到绘制缓冲区
}

下面是在测试数据在模拟器上的效果,后续会说明如何结合陀螺仪去将虚拟世界中的摄像头和设备绑定到一起

来自:cnblogs
分享到微信

0人喜欢 

通过OpenGL ES在iOS平台实践增强现实(一)的更多相关文章

  1. 通过OpenGL ES在iOS平台实践增强现实

    http://www.cnblogs.com/elvisyzhao/p/3398250.html 本文采用OpenGL ES 1固定渲染管线实现,目标为在设备拍摄到的现实世界中,绘制世界坐标轴,并根据 ...

  2. 通过OpenGL ES在iOS平台实践增强现实(二)

    上一篇讲到如何使用OpenGL ES绘制一个3D场景,这一篇我们会配合使用iOS提供的CoreMotion框架把虚拟世界中的摄像机的位置朝向和设备实际的位置朝向绑定起来.本文还对防抖做了处理. 首先说 ...

  3. WebGL 在 OpenGL ES 指令 iOS 在 C 分歧版指令分析

    WebGL 中 OpenGL ES 指令与 iOS 中 C 版指令的差异简析 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途 ...

  4. OpenGL ES on iOS --- 统一变量(Uniform)和统一变量块(UBO)

    简介 Uniform是一种从CPU中的应用向GPU中的着色器发送数据的方式,但uniform和顶点属性有些不同. 首先,uniform是全局的(Global).全局意味着uniform变量必须在每个着 ...

  5. OpenGL ES应用开发实践指南:iOS卷

    <OpenGL ES应用开发实践指南:iOS卷> 基本信息 原书名:Learning OpenGL ES for iOS:A Hands-On Guide to Modern 3D Gra ...

  6. iOS 中OpenGL ES 优化 笔记 1

    1,避免同步和Flushing操作 OpenGL ES的命令执行通常是在command buffer中积累一定量的命令后,再做批处理执行,这样效率会更高:但是一些OpenGL ES命令必须flush ...

  7. (转)规划从 OpenGL ES 2.0 到 Direct3D 的移植

    如果你移植 iOS 或 Android 平台中的游戏,那么你可能需要在 OpenGL ES 2.0 方面进行大量投资.如果你准备将你的图形管道代码库移动到 Direct3D 11 和 Windows ...

  8. OpenGL ES: (4) EGL API详解 (转)

    上一节我们初步学习了 OpenGL ES.EGL.GLSL 的相关概念,了解了它们的功能,以及它们之间的关联.我们知道了 EGL 是绘制 API(比如 OpenGL ES)与 底层平台窗口系统之间的接 ...

  9. [OpenGL ES 02]OpenGL ES渲染管线与着色器

    [OpenGL ES 02]OpenGL ES渲染管线与着色器 罗朝辉 (http://www.cnblogs.com/kesalin/) 本文遵循"署名-非商业用途-保持一致"创 ...

随机推荐

  1. __builtin_popcount() 函数

    详解 该函数的主要作用是计算一个数字的二进制中有多少个1,返回值就是其中1的个数. 它使用一张基于表的方法来进行位搜索,因此这个操作的执行效率很高 此处举一题 P1582 倒水 #include &l ...

  2. P1198 [JSOI2008]最大数【树状数组】

    题目描述 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值. 限制: L 不超过当前数列的长度. (L &g ...

  3. ABAP CDS - SELECT, WHERE

    格式 ... WHERE cond_expr ... 结果 定义CDS视图结果集的Where条件.访问CDS视图时,结果集仅包含来自数据源数据源的数据,该数据源数据源满足在where之后指定的条件co ...

  4. python基础之列表、元组和字典

    列表 列表定义:[]内以逗号分隔,按照索引,存放各种数据类型,每个位置代表一个元素 特性: 1.可存放多个值 2.可修改指定索引位置对应的值,可变 3.按照从左到右的顺序定义列表元素,下标从0开始顺序 ...

  5. 20145202 《信息安全系统设计基础》git安装

    git的安装 直接输入指令将其安装就可以了. 安装的时候要设置公钥,我不知道以前在windows上设置过的公钥是否还能用所以我就还是从新搞了一个. 验证可以连通 遇到的问题

  6. 微信小程序 | 49,小程序入门集锦系列文章20篇

    以下20篇文章,都是关于微信小程序的文章,以入门常见问题为主.如发现谬误,请与笔者联系. [小程序入门集锦]1,微信小程序在哪里打开 [小程序入门集锦]2,小程序商店 [小程序入门集锦]3,微信小程序 ...

  7. 安装完最小化 RHEL/CentOS 7 后需要做的 30 件事情(一)

    本文导航 -1. 注册并启用红帽订阅 -2. 使用静态 IP 地址配置网络 -3. 设置服务器的主机名称 -4. 更新或升级最小化安装的 CentOS -5. 安装命令行 Web 浏览器 -6. 安装 ...

  8. DataGridView重查后,返回原来所在行

    首先记录选中行 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 //查询前记录选中行 int _currentRow = 0; //int _cu ...

  9. 【转载】Unity插件研究院之自动保存场景

    原文: http://wiki.unity3d.com/index.php?title=AutoSave  最近发现Unity老有自动崩溃的BUG. 每次崩溃的时候由于项目没有保存所以Hierarch ...

  10. [OpenCV]Mat类详解

    http://blog.csdn.net/yang_xian521/article/details/7107786 Preface Mat:Matrix Mat类可以被看做是opencv中C++版本的 ...