通过OpenGL ES在iOS平台实践增强现实(一)

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人喜欢

时间: 2024-10-24 17:10:28

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

[转] iOS OpenGL ES Guide

OpenGL ES 小结 概述 OpenGL ES (Open Graphics Library for Embedded Systems)是访问类似 iPhone 和 iPad 的现代嵌入式系统的 2D 和 3D 图形加速硬件的标准. 把程序提供的几何数据转换为屏幕上的图像的过程叫做渲染. GPU 控制的缓存是高效渲染的关键.容纳几何数据的缓存定义了要渲染的点.线段和三角形. OpenGL ES 3D 的默认坐标系.顶点和矢量为几何数据的描述提供了数学基础. 渲染的结果通常保存在帧缓存中.有两

OpenGL ES总结(一)OpenGL 初识

转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/61615215 OpenGL是在图形图像中,非常优秀的渲染库,文中Demo下载地址:https://github.com/hejunlin2013/OpenGL31,看下今天的Agenda: OpenGL是什么? OpenGL主要功能是什么? OpenGL ES是什么? Android中如何描述OpenGL ES版本 映射坐标绘制对

OpenGL ES 系列之开篇

OpenGL ES 系列之开篇 很久前一直想研究 OpenGL 无奈自己的惰性,现在准备开始完整的学习下 OpenGL, 一来工作需要,二来也是自我学习的成长. 我是一名 iOSer,OpenGL 是与平台无关的一种开发技术,虽然苹果在 iOS 12 推荐使用自家的 Metal, 但这个做为学习还是有必要的. 关于 OpenGL OpenGL 全称:Open Graphics Library,用来处理2D.3D视觉数据的.是一个多用途的开放标准图形库,支持2D.3D数字内容的创建.机械和建筑设计

基于Cocos2d-x学习OpenGL ES 2.0系列——OpenGL ES渲染之LayerColor(8)

在前面文章中讲述了Cocos2d-x引擎OpenGL渲染准备Shader方面,本文主要讲解使用LayerColor来讲述OpenGL的渲染过程. 1.LayerColor对象创建 添加LayerColor元素到游戏中: autolayerColor = LayerColor::create(Color4B(255, 0, 0, 255), 100, 100); layerColor->setPosition(100,100); 下面是LayerColor::create方法: LayerColo

iOS 平台开发OpenGL ES程序注意事项

本人最近从Android平台的OpenGL ES开发转到iOS平台的OpenGL ES开发,由于平台不同,所以开发中会有一些区别,再次列出需要注意的几点. 1.首先需要了解iOS主要开发框架,再次仅介绍开发OpenGL ES应用常用的几个: CoreGraphics.framework  ——包含Quartz 2D接口(Core Graphics框架参考) Foundation.framework ——包含Cocoa Foundation层的类和方法(Foundation框架参考) OpenGL

iOS下OpenGL ES 3.0编程入门(一):构建Hello World环境

OpenGL ES简介: OpenGL ES (OpenGL for Embedded Systems) 是 OpenGL三维图形 API 的子集,针对手机.PDA和游戏主机等嵌入式设备而设计.该API由Khronos集团定义推广,Khronos是一个图形软硬件行业协会,该协会主要关注图形和多媒体方面的开放标准. OpenGL ES 3.0主要新功能有: 1.渲染管线多重增强,实现先进视觉效果的加速,包括遮挡查询(Occlusion Query).变缓反馈(Transform Feedback)

iOS开发- OpenGL ES屏幕截图

之前写过一个常规的屏幕截图:http://blog.csdn.net/hitwhylz/article/details/17189351 可是发现这个办法对于OpenGL 无用.  获取到的数据为空. 所以这里介绍下OpenGL ES屏幕截图. 1.初始化. CAEAGLLayer *eaglLayer = (CAEAGLLayer *) self.layer; eaglLayer.drawableProperties = @{ kEAGLDrawablePropertyRetainedBack

WebGL 中 OpenGL ES 指令与 iOS 中 C 版指令的差异简析

太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS.Android.Html5.Arduino.pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. WebGL 中 OpenGL ES 指令与 iOS 中 C 版指令的差异,从整体上看,应该是 gl 前缀在 WebGL 版指令中的省略,举例对比如

iOS实现图形编程可以使用三种API(UIKIT、Core Graphics、OpenGL ES及GLKit)

这些api包含的绘制操作都在一个图形环境中进行绘制.一个图形环境包含绘制参数和所有的绘制需要的设备特定信息,包括屏幕图形环境.offscreen 位图环境和PDF图形环境,用来在屏幕表面.一个位图或一个pdf文件中进行图形和图像绘制.在屏幕图形环境中进行的绘制限定于在一个UIView类或其子类的实例中绘制,并直接在屏幕显示,在offscreen位图或PDF图形环境中进行的绘制不直接在屏幕上显示. 一.UIKIT API UIKIT是一组Objective-C API,为线条图形.Quartz图像