系列回顾:
程序丨OpenGLES入门(一):如何将照明应用到游戏角色
程序丨OpenGLES入门(二):如何将Skybox应用到游戏
程序丨OpenGLES入门(三):如何将纹理应用到游戏角色
原文:Harold
翻译:刘鸿(lewis2012)
审校:王玥亭(玥亭)
介绍
在这篇文章中,将使用OpenGL ES在iOS设备上渲染你的第一个3D模型。 在屏幕上渲染3D模型的步骤如下:
1)初始化OpenGLES上下文。
2)设置渲染循环。
3)创建OpenGL对象并加载角色数据。
4)创建变换空间。
5)更新帧缓冲(framebuffer) 。
目标
我们的目标是在iOS设备屏幕上渲染机器人。
这是一个动手项目。你可以边学习边写代码,因此请下载空的XCode模板项目( template project)。该项目包含将要实现的C ++方法的框架。该项目还包含将在屏幕上呈现的角色的数据。文件名为Robot.h
知情
在我们开始之前,我建议你看看下面这些文章。虽然你并不需要,但是它会告诉你整个代码是怎么回事。
Loading data into OpenGL Buffers
Starting the rendering process in OpenGL
Rendering efficiently with OpenGL
初始化OpenGL上下文
渲染需要初始化图形上下文( graphics context)。 在iOS设备中,通过创建EAGLContext对象来分配和初始化图形上下文。
要在iOS设备上初始化OpenGL ES上下文,请打开文件名ViewController.mm。找到viewDidLoad方法,并键入代码1中显示的内容:
代码1:初始化OpenGL上下文
代码1中的第1行,为EAGLContext对象分配内存,然后通过调用initWithAPI方法初始化上下文。 方法initWithAPI初始化并返回一个新分配的渲染上下文(OpenGL ES 2.0版本)。
然后检查上下文是否已成功创建(第2行)。 如果是这样,新创建的上下文将使用setCurrentContext方法(第5行)设置为当前上下文。当前上下文也设置为iOS视图的上下文(第3行)。 然后要求视图每秒更新60帧(第4行)。
我们使用C++类实现机器人。项目中的主类称为Character。这个类包含几个方法,负责将数据加载到OpenGL缓冲区和更新帧缓冲(framebuffer) 。
我们的第一个任务是简单地创建一个Character类的实例(第6行)。 构造函数接收屏幕的宽度和高度。接下来,我们调用SetupOpenGL()方法(第7行)。此方法将创建OpenGL缓冲区并加载3D模型数据。
设置渲染循环
为了更新我们的帧缓冲(framebuffer),我们需要一个不断被我们的应用程序调用的函数。
在文件ViewController.mm中,找到glkView()方法并键入代码2中所示的内容。
iOS设备提供了一个称为glkView的方法。每当iOS视图的内容需要更新时调用glkView方法。在我们的例子中,我们将它设置为每秒更新60帧。我们将通过调用Character中的draw()方法(第3行)来实现glkView方法来更新帧缓冲(framebuffer)。
代码2:设置绘图例程
创建OpenGL对象并加载角色数据
有多种方法将数据加载到OpenGL缓冲区( load data into OpenGL Buffers)。在本教程中,我们将使用glBufferSubData函数加载数据。为了渲染效率,我们将使用顶点数组对象( Vertex Array Objects)。
让我们来看看渲染所需的11个步骤。他们是:
1)Generate a VAO(glGenVertexArrays):通知OpenGL创建VAO。
2)Bind the VAO(glBindVertexArray):通知OpenGL绑定VAO。
3)Generate a VBO(glGenBuffers()):通知OpenGL创建一个缓冲区。
4)Bind the VBO(glBindBuffer()):通知OpenGL将此缓冲区用于后续操作。
5)Buffer Data(glBufferData()或glBufferSubData()):通知OpenGL为当前绑定的缓冲区分配和初始化足够的内存。
6)Get Location of Attributes(glGetAttribLocation()):获取当前活动着色器中属性的位置。
7)Get Location of Uniform(glGetUniformLocation()):获取制服的位置在正确的活动着色器。
8)Enable (glEnableVertexAttribArray()):启用在着色器中找到的属性位置。
9)Set Pointers(glVertexAttribPointer()):通知OpenGL关于绑定缓冲区中的数据类型以及访问数据所需的任何内存偏移量。
10)Draw (glDrawArrays()或glDrawElements()):通知OpenGL使用当前绑定和启用的缓冲区中的数据渲染场景。
11)Delete (glDeleteBuffers()):告诉OpenGL删除以前生成的缓冲区和释放相关资源。
我们将在方法setupOpenGL()中实现这些步骤。此方法将负责创建VAO并将数据加载到OpenGL缓冲区中。
打开文件Character.mm。找到setupOpenGL()方法,并键入代码3中所示的内容。
机器人几何的顶点在Robot.h文件中的数组robot_vertices []中可以找到。
代码3:将数据加载到缓冲区中
我们首先从创建和绑定顶点数组对象开始,如第1行和第2行所示。然后创建一个OpenGL对象并绑定目标GL_ARRAY_BUFFER(第3和第4行)。然后使用glBufferSubData函数加载角色,如第5行所示。
然后获得attributes 和uniforms 位置,如第7和第8行所示。属性位置被启用,并且缓冲数据被链接到属性位置,如第10行所示。
由于我们将使用glDrawElements()开始渲染过程( start the rendering process),我们需要为我们的机器人几何的索引创建一个新的缓冲区。回想使用glDrawElements进行渲染比使用glDrawArrays进行渲染更加高效。
使用glDrawElements,提供了一组索引,它们将引导OpenGL通过图元汇编阶段。这些索引集减少了冗余顶点的连接,如果使用glDrawArrays可能发生冗余顶点的连接。
机器人几何的索引在Robot.h文件中的数组robot_index []中可以找到。
第11-12行显示了新索引缓冲区的创建和绑定。第13行显示了从robot_index数组加载到缓冲区中的数据。
最后,顶点数组对象解除绑定,如第14行所示。
设置转换空间
在Robot.h文件中找到的数据描述了我们的角色的几何。但是,此数据在其自己的坐标空间(也称为模型空间)中描述角色的几何。为了在屏幕上看到角色,需要通过多个坐标空间进行转换。它们如下:
1)世界空间变换(World SpaceTransformation)。
2)视图空间变换(View SpaceTransformation)。
3)透视投影空间变换(PerspectiveProjection Space Transformation)。
打开文件Character.mm。找到setTransformation()方法并键入代码4中所示的内容。
代码4:设置坐标变换
让我们从将角色的空间设置为单位矩阵(第1行)开始。这仅仅意味着模型被设置在其坐标系的原点。
通常,这足以表示角色的模型空间。该模型在Blender的建模软件中创建。不幸的是,Blender和OpenGL的坐标系是不同的。因此,我们需要通过Blender的变换矩阵(第2行)转换模型空间。
让我们也将World 空间设置为一个单位矩阵(第3行)。我们将通过简单地乘以它们的空间来将我们的模型的空间转换成世界的空间。新空间现在称为Model-World空间(第4行)。
View 空间表示摄像机没有任何旋转,但是分别沿着x,y和z轴(第5行)平移0.0,-1.0,-5.0单位。
Model-World空间会被View 空间转换。结果空间现在被称之为Model-World-View 空间(第6行)。
我们的最终转换包括将Model-World-View空间转换为Model-World-View-Projection空间。然而,我们必须首先构造一个具有45度视场的Projection-Perspective空间。近和远裁剪距离分别为0.1和100.0(第7行)。
现在我们能够将Model-World-View空间转换为Model-World-View-Projection空间,如第8行所示。
我们的最终任务是将Model-World-View-Projection空间中的数据提供给着色器中的uniform locations(第10行)。着色器将使用此数据将角色的模型空间正确转换为屏幕空间。
更新帧缓冲(framebuffer)
最后,我们准备实现draw()方法。这个方法将会以每秒60帧来更新framebuffer,并将被glkView()方法调用。
打开文件Character.mm。找到Draw()方法,并键入代码5中所示的内容。
第一个任务是设置要使用的着色器程序(第1行)。接下来,绑定包含我们的OpenGL渲染状态(第2行)的顶点数组对象(VAO)。 这在代码3中指定。然后通过调用glDrawElements(第3行)开始呈现效果。 最后,VAO解绑。
运行项目,你应该在iOS设备的屏幕上看到一个机器人。
代码5:渲染例程
最后结果
一旦你运行项目,你应该看到一个可爱的小机器人在你的iOS设备屏幕上呈现。机器人在屏幕上呈现
注意:
在较新的Xcode版本中,你可能会在运行项目演示时遇到此错误:
“No such file ordirectory: ... xxxx-Prefix.pch”
此错误表示项目没有PCH文件。修复是非常简单:
在Xcode中,转到new- file- PCH文件。
命名PCH文件:'NameOfProject-Prefix'其中“NameOfProject”是你尝试打开的demo的名称。在OpenGL演示项目中,我通常将项目命名为“openglesinc”。
所以PCH文件的名称应该是“openglesinc-Prefix”
确保文件保存在“NameOfProject”文件夹中。即,在“openglesinc”文件夹内。
单击创建并运行项目。
【版权声明】
原文作者未做权利声明,视为共享知识产权进入公共领域,自动获得授权。
系列预告:
下一篇将讲述如何在游戏中使用着色器,敬请期待。
今日推荐
福利丨送价值980元Unreal Open Day门票
1.加入GAD程序猿交流基地
获取行业干货资讯,观看大牛分享直播
2.直接领取60G独家程序资料库,地址在小编朋友圈
包括腾讯内部分享、文章教程、视频教程等全套资料