OpenGL ES 2.0:如何提高绘图精灵的帧速率?

我有一个动画背景图层,它构建在OpenGL ES 2.0之上,我使用GLKView作为图形容器,GLKViewController作为控制器。 对于绘图我使用GLKBaseEffect。

我介绍了一个精灵类,它可以将png文件作为纹理加载,操纵精灵(SRT)和一些其他属性,如alpha混合等。

我想知道如何优化我的程序,因为当我显示50个精灵(所有具有相同的纹理/ png文件!)时,我的iPhone 4S的帧速率下降到大约25 FPS,每个精灵的尺寸为128×128像素。

在以下部分中,我列出了该计划的重要部分。 目前,我为每个帧的50个精灵中的每一个调用glDrawArrays(GL_TRIANGLE_STRIP, 0, 4) (目标帧速率为60); 这同样是每秒3000次通话。

这可能是瓶颈吗? 我怎么能优化这个?

这是我初始化精灵数组(GLKViewController.m)的方法:

 - (void)initParticles { if(sprites==nil) { sprites = [NSMutableArray array]; for (int i=0; i<50; i++) { Sprite* sprite = [[Sprite alloc] initWithFile:@"bubble" extension:@"png" effect:effect]; // configure some sprite properties [abbreviated] [sprites addObject:sprite]; } } } 

这是渲染函数(GLKViewController.m):

 - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect { glClearColor(0.0, 0.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); // render the bubbles for (Sprite* sprite in sprites) { [sprite render]; } } 

以下是sprite类(Sprite.m)的一些重要部分:

 - (id)initWithFile:(NSString *)filename extension:(NSString*)extension effect:(GLKBaseEffect *)effect { if(self = [self init]) { self.effect = effect; NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], GLKTextureLoaderOriginBottomLeft, nil]; NSError* error = nil; NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:nil]; self.textureInfo = [GLKTextureLoader textureWithContentsOfFile:path options:options error:&error]; if (self.textureInfo == nil) { NSLog(@"Error loading file: %@", [error localizedDescription]); return nil; } TexturedQuad newQuad; newQuad.bl.geometryVertex = GLKVector2Make(0, 0); newQuad.br.geometryVertex = GLKVector2Make(self.textureInfo.width, 0); newQuad.tl.geometryVertex = GLKVector2Make(0, self.textureInfo.height); newQuad.tr.geometryVertex = GLKVector2Make(self.textureInfo.width, self.textureInfo.height); newQuad.bl.textureVertex = GLKVector2Make(0, 0); newQuad.br.textureVertex = GLKVector2Make(1, 0); newQuad.tl.textureVertex = GLKVector2Make(0, 1); newQuad.tr.textureVertex = GLKVector2Make(1, 1); self.quad = newQuad; } return self; } - (void)render { [self applyBaseEffect]; long offset = (long)&_quad; glEnableVertexAttribArray(GLKVertexAttribPosition); glEnableVertexAttribArray(GLKVertexAttribTexCoord0); glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void*) (offset + offsetof(TexturedVertex, geometryVertex))); glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void*) (offset + offsetof(TexturedVertex, textureVertex))); glBlendColor(1.0, 1.0, 1.0, self.alpha); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDisableVertexAttribArray(GLKVertexAttribPosition); glDisableVertexAttribArray(GLKVertexAttribTexCoord0); } - (void)applyBaseEffect { self.effect.texture2d0.name = self.textureInfo.name; self.effect.texture2d0.envMode = GLKTextureEnvModeModulate; self.effect.texture2d0.target = GLKTextureTarget2D; self.effect.texture2d0.enabled = GL_TRUE; self.effect.useConstantColor = GL_TRUE; self.effect.constantColor = GLKVector4Make(self.tint.r*self.alpha, self.tint.g*self.alpha, self.tint.b*self.alpha, self.alpha); self.effect.transform.modelviewMatrix = GLKMatrix4Multiply(GLKMatrix4Identity, [self modelMatrix]); [self.effect prepareToDraw]; } - (GLKMatrix4)modelMatrix { GLKMatrix4 modelMatrix = GLKMatrix4Identity; modelMatrix = GLKMatrix4Translate(modelMatrix, self.position.x, self.position.y, 0); modelMatrix = GLKMatrix4Rotate(modelMatrix, self.rotation, 0, 0, 1); modelMatrix = GLKMatrix4Scale(modelMatrix, self.scale, self.scale, 0); modelMatrix = GLKMatrix4Translate(modelMatrix, -self.normalSize.width/2, -self.normalSize.height/2, 0); return modelMatrix; } 

编辑-1:这是一些性能指标(似乎是GPU绑定)

在此处输入图像描述

EDIT-2:当我添加了view.drawableMultisample行时,我的iPhone 4S的帧速率从25提高到45,无论我使用哪一行(无/ 4x)。 奇怪 – 我的渲染代码似乎不受MSAA的影响,而恰恰相反。

 GLKView *view = (GLKView*)self.view; view.context = context; view.drawableMultisample = GLKViewDrawableMultisampleNone; //view.drawableMultisample = GLKViewDrawableMultisample4x; 

要提高性能,必须避免冗余代码。 可能你为每个精灵设置了着色器程序。 但是总是使用相同的着色器绘制精灵,所以你可以避免每次都设置它。 您可以对顶点和纹理坐标使用这种优化。 对于每个精灵,只需计算矩阵MVP(模型 – 视图 – 投影)。

伪代码中的’drawFrame’方法:

 ... [set sprite program shader] [set vertex coordinates] [set texture coordinates] [set textures ] for each sprite [calculate matrix MVP] [draw sprite] end for ... 

另一个优化是使用顶点缓冲对象,但在你的情况下,我认为它的优先级低于精灵批量优化。

我在Android上工作,所以我无法帮助你使用示例代码。 不过,我建议你看看Libgdx来检查它们是如何实现sprite批处理的。

您的性能计数器似乎表明您是GPU填充率限制。 您可以检查bubble.png资产是否正在充分利用其纹理空间,不必要的过度绘制可能是您问题的一部分。

您可以在photoshop / gimp中打开它并自动切割图像,如果它从边缘移除任何纹素,那么您有一些浪费的空间。 如果你可以消除浪费的空间,你可以减少透支。

你提到气泡是128×128,但不清楚这是纹理大小还是屏幕尺寸。 减小屏幕尺寸将提高性能。

除此之外,您可能需要深入研究Sprite类并查看片段着色器实际执行的操作。 选择更有效的纹理格式并启用mipmapping也可能有所帮助。

经过两个小时的深入研究,我终于找到了大规模性能影响的原因。 正如评论中所描述的,性能下降的重要性随着视图控制器中包含的按钮的增加而增长。 由于我正在用圆角和阴影装饰我的按钮,所以我照看了…这是UIView类中我原始类别的一部分,用于装饰UI元素:

 #import "UIView+Extension.h" @implementation UIView (Extension) - (void)styleViewWithRoundedEdges:(BOOL)rounded shadowed:(BOOL)shadowed { if (rounded) { self.layer.cornerRadius = 3.0; } if (shadowed) { self.layer.shadowColor = [UIColor blackColor].CGColor; self.layer.shadowOffset = CGSizeMake(2.0, 2.0); self.layer.shadowOpacity = 0.25; self.layer.shadowRadius = 1.0; } } @end 

一旦我关闭了投影,帧速率就会变为恒定的60 FPS。

快速搜索引导我到这个SO线程 。

添加这两行解决了这个问题:

 self.layer.shouldRasterize = YES; self.layer.rasterizationScale = UIScreen.mainScreen.scale; 

我现在可以轻松地在iPhone 4S上使用60 FPS:-D轻松渲染100个精灵和线性+径向背景渐变着色器。

但是非常感谢你们的耐心和帮助! 让我知道什么时候能得到回报!