要实现3D引擎的跨平台功能. 必须研究OpenGLES的接口规范. 而OpenGLES 在IOS平台上的使用也有自身的特点.本文将详细比较两者在使用上的异同.
一. OpenGL ES对象及接口函数
OpenGL ES中的对象分别用于处理两大类问题: 平台相关的问题和OpenGL渲染相关的问题.
EGLDisplay与EGLSurface用于处理与平台相关的问题.
EGLContext处理与OpenGL渲染相关的问题.
1. EGLDisplay可以简单理解为一个显示渲染结果的渲染窗口. EGLSurface可以理解为此窗口中的显示表面.只有画在此surface上的内容,才是渲染窗口中最后显示出来的画面.
1) 一般的应用平台在使用OpenGLES对象时, 只要使用以下API即可:eglGetDisplay, eglInitialize, eglChooseConfig, eglCreateWindowSurface 等.
2) 但在Apple平台中, 对OpenGLES的使用略有不同.
在IOS编程中必须要有一个UIWindow类实例对象,UIWindow就相当于上面的EGLDisplay.同时还必须要有一个从UIView类派生的类(可以称之为CustomView),UIView就相当于上面的EGLSurface. 并且必须将CustomView的成员变量layer, 由CALayer类型变为CAEAGLLayer类型. CAEAGLLayer成员的作用, 类似于eglChooseConfig函数. 用来设置目标surface的宽,高,像素格式及透明性等属性.设置完CAEAGLLayer后, 再以此对象的设置为参数, 调用renderbufferStorage来分配相应的内存空间(其作用类似于eglCreateWindowSurface?).
需要明确的是, 一个UIView的最终显示结果, 是由它所包含的所有layer的画面叠加后形成的.
2. EGLContext
与OpenGL渲染相关的内容由EGLContext对象来管理. 首先要调用eglCreateContext函数创建一个EGLContext对象,EGLContext内部采用双缓冲机制来实现渲染结果的显示.EGLContext有两个Framebuffer对象.一个做为back一个为front.当渲染完一帧后.通过调用eglSwapBuffers函数, EGLContext会自动交换两个Framebuffer的位置, 并且将front Framebuffer中的内容提交给相应的EGLSurface.Framebuffer象一个Renderbuffer集(它可以包含多个Renderbuffer对象).
Renderbuffer有三种: color Renderbuffer, depth Renderbuffer, stencil Renderbuffer.
渲染结果是先输出到Framebuffer中,然后通过调用context的presentRenderbuffer,将Framebuffer上的内容提交给之前的CustumView.
二. IOS中渲染一个3D场景的做法如下:
1. 生成一个OffScreen Framebuffer对象. 3D场景的渲染结果最终会由此Framebuffer给出.
生成renderbuffer(或称color buffer), 并将其与Framebuffer挂接到一起.
用glGenFramebuffers创建帧缓冲.
用glGenRenderbuffers创建渲染缓冲.
然后用glFramebufferRenderbuffer将Renderbuffer挂接到相应的Framebuffer上.
2. 生成一个CAEAGLLayer对象,
作为图像最终输出窗口的UIView, 有一个成员变量CALayer, 要显示的图像都画在此对像上. 并且一个UIView可以有多个CALaye , 并且这些CALayer之间可以形成一个树形数据结构, 所有layer中的结果数据叠加后形成最终的画面. 而不管这些 Core Animation Layer 是由 OpenGL ES 、Quartz 、还是其他什么图形库来描画的.
如果要使输出画面只依赖OpenGLES渲染输出的图像,则要创建一个CAEAGLLayer对象. 并将不透明性设为YES .
3. 生成一个EAGLContext对象
EAGLContext对象管理着渲染状态信息,命令和将被渲染的资源(An EAGLContext
object manages the state information, commands, and resources needed to draw using OpenGL ES. ). 并且在将画面显示到context对象之前必须将一个framebuffer 绑定到此Context之上( To draw to an EAGL context, a complete framebuffer object must first be bound to the context. ) . 但找了许多资料也没看到如何将framebuffer与一个context绑定, 只看到将renderbuffer与context绑定的接口.
4.Framebuffer与CAEAGLLayer的关联
在创建完以上三个对象后,
a. 先调用EAGLContext的类方法前之前生成的EAGLContext对象设定为当前context.
b. 然后调用EAGLContext对象的renderbufferStorage接口函数, 为之前生成的CAEAGLLayer对象分配空间.
( 按IOS的文档的说法是: Allocate its storage by calling the context’s renderbufferStorage:fromDrawable:
method, passing the layer object as the parameter.
The width, height and pixel format are taken from the layer and used to allocate storage for the renderbuffer. )
c. 在渲染之前先用glBindFramebuffer, 将之前用glGenFramebuffers创建的帧缓冲绑定为当前的Framebuffer(绑定到context上?).
这样一来之后的所有的渲染命令就是针对当前绑定的Framebuffer(也就是针对新创建的Framebuffer)了.
可以参见:http://miaoshuanghe.blog.163.com/blog/static/140130476201052453756439/ 中对Framebuffer的描述.
d. 在渲染完成之后,先调用
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
其作用是将Renderbuffer绑定到context上.(IOS的文档:binds the renderbuffer to the context)
此时当前Framebuffer完全由renderbuffer控制(The color renderbuffer holds the completed frame, so all you need to do is present it to the user).
所谓hold的含义估计是这样来理解的:
由于Framebuffer可以包括renderbuffer(或者称colorbuffer), depthbuffer, stencilbuffer.
Framebuffer与renderbuffer/depthbuffer/stencilbuffer间的关系, 可以参见: http://xiaozu.renren.com/xiaozu/100134/335830019
最终的输出结果(final output)由整个Framebuffer给出.
所以,当renderbuffer "hold" Framebuffer时,Framebuffer的内容就是renderbuffer的内容.
e. 最后,调用EAGLContext的presentRenderbuffer.
context presentRenderbuffer:GL_RENDERBUFFER将最终渲染结果提交.
5. 需要说明的是OpenGLES中的
glGenBuffers
glBindBuffer
glBufferData
所针对的是资源数据缓冲.这类缓冲中存放的是作为渲染内容的外部资源数据, 比如顶点,法线等.
参考文章:
http://db-in.com/blog/2011/01/all-about-opengl-es-2-x-part-13/#Buffers
http://db-in.com/blog/2011/02/all-about-opengl-es-2-x-part-23/
http://db-in.com/blog/2011/05/all-about-opengl-es-2-x-part-33/
http://db-in.com/blog/2011/02/khronos-egl-and-apple-eagl/
https://developer.apple.com/library/ios/#documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/WorkingwithEAGLContexts/WorkingwithEAGLContexts.html#//apple_ref/doc/uid/TP40008793-CH103-SW1
http://developer.apple.com/library/ios/#documentation/OpenGLES/Reference/EAGLContext_ClassRef/Reference/EAGLContext.html
http://developer.apple.com/library/ios/#documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/WorkingwithEAGLContexts/WorkingwithEAGLContexts.html#//apple_ref/doc/uid/TP40008793-CH103-SW5
http://xiaozu.renren.com/xiaozu/100134/335830019
http://www.helmsmansoft.com/index.php/archives/1436
http://miaoshuanghe.blog.163.com/blog/static/140130476201052453756439/