OpenGL ES 2.0:如何提高图形精灵的帧速率? [英] OpenGL ES 2.0: How to improve frame rate of drawing sprites?
问题描述
我有一个动画背景层,它建立在OpenGL ES 2.0之上,并且我使用GLKView作为图形容器,并使用GLKViewController作为控制器.对于绘图,我使用GLKBaseEffect.
I have an animated background layer that is built on top of OpenGL ES 2.0 and I am using GLKView as graphics container and GLKViewController as controller. For drawing I use GLKBaseEffect.
我介绍了一个Sprite类,该类可以将png文件作为纹理加载,操纵Sprite(SRT)以及其他一些属性,例如Alpha混合等等.
I introduced a sprite class that can load png-files as textures, manipulate the sprite (SRT) and some additional properties like alpha blending and so on.
我想知道如何优化程序,因为当显示50个大小分别为128x128 px的sprite(均具有相同的texture/png文件!)时,iPhone 4S上的帧速率降至约25 FPS.
I am wondering how I could optimise my program, since the frame-rate drops on my iPhone 4S to about 25 FPS when displaying 50 sprites (all with the same texture/png-file!) with a size of 128x128 px each.
在以下各节中,我列出了程序的重要部分.目前,我为每个帧的50个精灵中的每个叫glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)
(目标帧速率为60).相当于每秒3000次通话.
In the following sections I have listed the important parts of the program. Currently I call glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)
for each of the 50 sprites for each of the frames (target frame rate is 60); which is equally to 3000 calls per second.
那是瓶颈吗?我该如何优化呢?
这就是我初始化子画面数组(GLKViewController.m)的方法:
This is how I initialise the sprite array (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):
This is the rendering function (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)的一些重要部分:
Here are some important parts of the sprite class (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;
}
EDIT-1:以下是一些性能指标(似乎与GPU绑定)
EDIT-1: Here are some performance indicators (seems to be GPU-bound)
EDIT-2:当我添加view.drawableMultisample
行时,无论我使用哪一行(无/4x),我的iPhone 4S的帧频都从25提高到45.奇怪-我的渲染代码似乎不受MSAA的影响,相反.
EDIT-2: The frame rate improved from 25 to 45 on my iPhone 4S when I added the view.drawableMultisample
line regardless of which line I used (none / 4x). Strange - my rendering code seems not to be affected by MSAA, rather on the contrary.
GLKView *view = (GLKView*)self.view;
view.context = context;
view.drawableMultisample = GLKViewDrawableMultisampleNone;
//view.drawableMultisample = GLKViewDrawableMultisample4x;
推荐答案
经过另外两个小时的深入研究,我终于找到了导致性能大幅下降的原因.如评论中所述,性能下降的重要性随着视图控制器中包含的按钮的增加而增加.因为我要用圆角和阴影装饰按钮,所以我要照顾好……这是UIView类的原始类别的一部分,目的是装饰UI元素:
After another two hours intensive research I finally found the cause for the massive performance hit. As described in a comment, the significance of the performance drop grew with increasing buttons that were contained within a view controller. Since I am decorating my buttons with rounded corners and a drop shadows, I looked after that... Here's a part of my original category on the UIView class for the purpose of decorating UI elements:
#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.
As soon as I switched off the drop shadow, the frame rate turned into constant 60 FPS.
快速搜索将我定向到此SO线程.
添加这两行可以解决问题:
Adding these two lines solved the problem:
self.layer.shouldRasterize = YES;
self.layer.rasterizationScale = UIScreen.mainScreen.scale;
现在,在具有60 FPS的iPhone 4S上,我可以轻松地将100个精灵与线性+径向背景渐变着色器结合使用.
I now render easily 100 sprites combined with the linear+radial background gradient shader on a iPhone 4S with 60 FPS :-D.
但是非常感谢你们的耐心和帮助!让我知道何时可以退货!
But thank you guys so much for your patience and help! Let me know when I can return the favour!
这篇关于OpenGL ES 2.0:如何提高图形精灵的帧速率?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!