您的位置:首页 > 产品设计 > UI/UE

OpenGL ES Programming Guide for iOS 使用OpenGL ES和GLKit绘图

2014-07-23 18:51 459 查看
使用OpenGL ES和GLKit绘图

GLKit框架提供视图和视图控制器类,减少重复的设置和维护用来绘图和动画的OpenGLES上下文content。GLKView类管理OpenGLES的基础,来提供的绘图代码的地方,GLKViewcontroller类保证OpenGLES上下文绘制在GLView上的动画平滑的循环渲染。这些类扩展了UIKit里绘制视图上下文和管理视图呈现的标准设计模式。作为结果,努力集中在OpenGLES渲染代码,让应用程序快速启动和运行。

GLKit框架还提供其他功能,简化OpenGL ES 2和3的开发。

GLKit View按OpenGL ES Content要求绘图

GLKView类提供和OpenGLES相似的标准视图View绘图周期cycle。一个视图实例自动配置图形上下文,这样drawRect:只需要实现Quartz2D绘图命令command,GLKView实例自动配置自身,使绘图方法只需要执行OpenGLES command。GLKView提供一个帧缓冲对象保存OpenGLES绘图命令绘制结果。当绘图方法返回是通过CoreAnimation自动呈现出来。

和标准UIKit视图一样,GLKit视图按上下文要求渲染。当视图第一次显示,调用绘图方法,CoreAnimation缓存渲染输出,然后显示。当想改变视图的上下文时,调用setNeedsDisplay方法,视图会再次调用绘图方法,缓存绘制结果图像,在屏幕上显示。

这种方法多用于渲染图像很少变化或仅在响应用户的动作。当你需要的时候才绘制新的视图内容,这样节省电池电量,设备有更多的时间用于执行其他操作。

创建和设置GLKit视图

可以通过编程或使用InterfaceBuilder来创建和设置GLKView。在绘图之前,必须和EAGLContext关联起来(见“设置OpenGLES上下文”(第17页))。

● 以编程方式创建视图时,首先创建一个上下文,然后把它传递给视图的initWithFrame:context:方法。

● 在故事板加载视图后,创建上下文,设置上下文为视图的上下文。

GLKit视图自动创建和设置自己的OpengGLES帧缓冲对象和渲染缓冲区。通过视图的绘图属性来控制这些对象的属性,如清单3-1所示。通过GLKit来改变大小、缩放因子和绘图属性,在下次时,它会自动删除并重新创建适当的帧缓冲对象和渲染缓冲区来改变绘图上下文。

-(void)viewDidLoad
{
[superviewDidLoad];
//Create an OpenGL ES context and assign it to the view loaded from storyboard
GLKView*view = (GLKView *)self.view;
view.context= [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
//Configure renderbuffers created by the view
view.drawableColorFormat= GLKViewDrawableColorFormatRGBA8888;
view.drawableDepthFormat= GLKViewDrawableDepthFormat24;
view.drawableStencilFormat= GLKViewDrawableStencilFormat8;
//Enable multisampling
view.drawableMultisample= GLKViewDrawableMultisample4X;
}

通过drawableMultisample属性打开GLKView的多重采样(Multisampling)属性。多重采样是一种抗锯齿,锯齿状边缘平滑,提高图像质量,启用多重采样会花费更多的内存和帧处理时间。打开多重采样,经常测试app性能,确保可以接受。

GLKit视图中绘图

图3-1(22页)大纲展示了OpenGLES绘制上下文的三个步骤:准备OpenGLES组件,发送绘图命令,将呈现的内容交给CoreAnimation显示。GLKView实现了1和3步,第2步交由用户实现,例如清单3-2。

Listing 3-2 Example drawingmethod for a GLKit view
- (void)drawRect:(CGRect)rect
{
// Clear the framebuffer
glClearColor(0.0f, 0.0f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT |GL_DEPTH_BUFFER_BIT);

// Drawusing previously configured texture, shader, uniforms, and vertex array
glBindTexture(GL_TEXTURE_2D,_planetTexture);
glUseProgram(_diffuseShading);
glUniformMatrix4fv(_uniformModelViewProjectionMatrix,1, 0,
_modelViewProjectionMatrix.m);
glBindVertexArrayOES(_planetMesh);
glDrawElements(GL_TRIANGLE_STRIP,256, GL_UNSIGNED_SHORT);
}

注意:glClear函数将清掉任何现有的帧缓冲里的内容,避免将以前的内容加载到内存里的这种昂贵的内存操作。为了保证最佳性能,应该总是在绘图前调用此函数。

GLKView类能够提供简单的OpenGLES绘图,因为它管理OpenGLES渲染处理的标准部分:

● 调用绘图方法之前,视图:

n 使EAGLContext成为当前上下文

n 基于当前大小、缩放因子和绘图属性(如果需要),创建帧缓冲对象和渲染缓冲区。

n 将帧缓冲对象作为绘图命令的当前目标

n 设置OpenGL ES视口来匹配帧缓冲区大小

● 绘图方法返回之后,视图:

n 如果启用多重采样,提供多重采样缓冲区

n 丢弃不需要的渲染缓冲区

n 将显示的渲染缓冲区交给Core Animation来缓冲和显示

通过委托对象渲染

许多OpenGLES app使用定制类实现渲染代码。这样的好处是容易通过定义不同的渲染类来支持不同的渲染算法。渲染算法可用通用,或从父类直接继承。例如,使用不同的渲染类来支持OpenGLES 2和3(见配置OpenGLES上下文(17页))。或者在更强的硬件上定制更好的图像质量。

GLKit非常适合这种方式,将渲染对象委托给标准的GLKView实例,而不是子类化GLKView来实现drawRect:方法,渲染类采用GLKViewDelegate协议,实现glkView:drawInRect:方法。Listing3-3列出了在app启动时,根据硬件特性选择渲染类。

Listing 3-3 Choosing arenderer class based on hardware features
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Create a context so we can test for features
EAGLContext *context = [[EAGLContext alloc]
initWithAPI:kEAGLRenderingAPIOpenGLES2];
[EAGLContext setCurrentContext:context];
// Choose a rendering class based on device features
GLint maxTextureSize;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
if (maxTextureSize > 2048)
self.renderer = [[MyBigTextureRenderer alloc] initWithContext:context];
else
self.renderer = [[MyRenderer alloc] initWithContext:context];
// Make the renderer the delegate for the view loaded from the mainstoryboard
GLKView *view = (GLKView *)self.window.rootViewController.view;
view.delegate = self.renderer;
// Give the OpenGL ES context to the view so it can draw
view.context = context;
return YES;
}

GLKitViewController动画OpenGL ES Content

默认情况下,GLKView按要求渲染上下文。就是说,OpenGLES绘图的关键优势在于它使用的图形处理硬件能处理复杂场景的app,如游戏和模拟很少有静态图像的连续动画的能力。在这种情况下,GLKit框架提供视图控制器,保持对GLKView动画的循环。这个循环是游戏和模拟中常用的设计模式:更新和显示。图3-2显示一个简化的动画循环的例子。

理解循环动画

在更新阶段,视图控制器调用自己的更新方法(或其委托glkViewControllerUpdate:)。在该方法中,准备绘制下一帧。例如,游戏可以根据上次收到的帧的位置,使用此方法确定的玩家的位置和敌人的信息,以及科学可视化使用这种方法来运行一个模拟的步骤。如果需要定时信息来确定下一帧的应用程序的状态,使用视图控制器的时序特性,如timeSinceLastUpdate属性。图3-2,更新阶段增量角度并用它来计算变换矩阵。

在显示阶段,视图控制器调用视图的显示方法,这就需要你的绘图方法。在你的绘图方法,提交OpenGLES绘图命令来使用GPU渲染绘图内容。为获得最佳性能,程序应该在渲染一个新的帧的开始时修改OpenGLES对象,然后提交绘图命令。图3-2在显示阶段提供着色器程序变量,在更新阶段计算矩阵,然后提交绘图命令绘制新的内容。

视图控制器的framesPerSecond属性表示的动画循环交替的这两个阶段之间的速度。使用preferredFramesPerSecond属性来设置所需的帧速率,根据硬件性能优化当前显示,视图控制器自动选择一个最佳的帧速率接近期望值。

重要:为了最好的结果,始终使用一个帧速率。一个合适的,一致的帧速率比变化的帧速率,有更好的用户体验。

使用GLKit View Controller

清单3-4演示了典型使用GLKViewController子类和GLKView实例来渲染OpenGLES的动画内容的模式。

Listing 3-4 Using a GLKitview and view controller to draw and animate OpenGL ES content
@implementation PlanetViewController // subclass of GLKViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Create an OpenGL ES context and assign it to the view loaded fromstoryboard
GLKView *view = (GLKView *)self.view;
view.context = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
// Set animation frame rate
self.preferredFramesPerSecond = 60;
// Not shown: load shaders, textures and vertex arrays, set up projection
matrix
[self setupGL];
}
- (void)update
{
_rotation += self.timeSinceLastUpdate * M_PI_2; // one quarter rotationper
second

}
-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
// Clearthe framebuffer
glClearColor(0.0f,0.0f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
// Setshader uniforms to values calculated in -update
glUseProgram(_diffuseShading);
glUniformMatrix4fv(_uniformModelViewProjectionMatrix,1, 0,
_modelViewProjectionMatrix.m);
glUniformMatrix3fv(_uniformNormalMatrix,1, 0, _normalMatrix.m);
// Drawusing previously configured texture and vertex array
glBindTexture(GL_TEXTURE_2D,_planetTexture);
glBindVertexArrayOES(_planetMesh);
glDrawElements(GL_TRIANGLE_STRIP,256, GL_UNSIGNED_SHORT, 0);
}
@end

这个例子中,从storyboard中加载PlanetViewController实例(GLKViewController子类),使用默认的GLKView实例和绘图属性。viewDidLoad方法创建OpenGLES context提供给视图,设置动画循环的帧率。

视图控制器自动委托它的视图,所以它实现了动画循环的更新和显示阶段。在更新方法中,计算出需要显示旋转的行星的变换矩阵。在glkView:drawInRect:方法,它提供了矩阵的着色器程序,提交的绘图命令来绘制地球几何图形。

使用GLKit开发渲染器

除了视图和视图控制器的基础设施,GLKit框架提供了一些其他功能,更容易在iOS中使用OpenGLES开发。

向量和矩阵的数学处理

OpenGL ES 2.0和后续版本不提供内置的函数用于创建或指定的变换矩阵。相反,shader提供可编程顶点着色器,输入指定的变换,统一使用通用变量。GLKit框架包括一个综合库,提供向量和矩阵类型和函数,根据iOS硬件高度优化。(见GLKitFramework Reference)

从OpenGL ES 1.1
固定功能管线升级

OpenGL ES 2和后续版本移除与OpenGL ES 1.1的固定功能的图形管道相关的所有功能。GLKBaseEffect类提供了Objective-C实现OpenGLES 1.1管道的模拟转换,照明和阴影状态,GLKSkyboxEffect和GLKReflectionMapEffect类中添加常用的视觉效果的支持。详情见这些类的参考文件。

加载纹理数据

GLKTextureLoader类提供简单的方式,同步或异步地从任何图像格式的纹理数据加载到OpenGLES的上下文。(见“使用GLKit框架加载纹理数据”(80页)。)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: